Files
voltsrage 1d28880920
CI / backend (push) Successful in 8m43s
CI / frontend (push) Successful in 2m0s
feature: Simulation Control Center (Dashboard)
2026-08-06 02:22:55 +08:00

168 lines
7.2 KiB
C#

using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;
[Collection("Integration")]
public class EncountersListTests : IAsyncLifetime
{
private readonly ApiFixture _fixture;
private readonly HttpClient _client;
private Guid _activeIcuEncounterId;
private Guid _activeSurgeryEncounterId;
private Guid _dischargedEncounterId;
public EncountersListTests(ApiFixture fixture)
{
_fixture = fixture;
_client = fixture.CreateClient();
}
public async Task InitializeAsync()
{
using var scope = _fixture.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await DbResetHelper.ResetAsync(db);
var patientIcu = new Patient
{
Id = Guid.NewGuid(), Mrn = "MRN-WARD-001", FirstName = "Alice", LastName = "Icu",
DateOfBirth = new DateOnly(1970, 3, 1), Gender = "F", CreatedAt = DateTimeOffset.UtcNow
};
var patientSurgery = new Patient
{
Id = Guid.NewGuid(), Mrn = "MRN-WARD-002", FirstName = "Bob", LastName = "Surgery",
DateOfBirth = new DateOnly(1965, 7, 12), Gender = "M", CreatedAt = DateTimeOffset.UtcNow
};
_activeIcuEncounterId = Guid.NewGuid();
_activeSurgeryEncounterId = Guid.NewGuid();
_dischargedEncounterId = Guid.NewGuid();
db.Patients.AddRange(patientIcu, patientSurgery);
db.Encounters.AddRange(
new Encounter
{
Id = _activeIcuEncounterId, PatientId = patientIcu.Id,
EncounterType = EncounterType.Inpatient, Status = EncounterStatus.Active,
Department = Department.Icu, AttendingPhysician = "Dr. Ward",
RoomBed = "ICU-3", AdmittedAt = DateTimeOffset.UtcNow.AddHours(-2),
CreatedAt = DateTimeOffset.UtcNow
},
new Encounter
{
Id = _activeSurgeryEncounterId, PatientId = patientSurgery.Id,
EncounterType = EncounterType.Inpatient, Status = EncounterStatus.Active,
Department = Department.Surgery, AttendingPhysician = "Dr. Ward",
RoomBed = "S-12", AdmittedAt = DateTimeOffset.UtcNow.AddHours(-1),
CreatedAt = DateTimeOffset.UtcNow
},
new Encounter
{
Id = _dischargedEncounterId, PatientId = patientSurgery.Id,
EncounterType = EncounterType.Outpatient, Status = EncounterStatus.Discharged,
Department = Department.Surgery, AttendingPhysician = "Dr. Ward",
AdmittedAt = DateTimeOffset.UtcNow.AddDays(-3),
DischargedAt = DateTimeOffset.UtcNow.AddDays(-2),
CreatedAt = DateTimeOffset.UtcNow.AddDays(-3)
});
db.News2Scores.Add(new News2Score
{
Id = Guid.NewGuid(), EncounterId = _activeIcuEncounterId, PatientId = patientIcu.Id,
TotalScore = 7, RiskLevel = "HIGH", CalculatedAt = DateTimeOffset.UtcNow,
RespRateScore = 1, Spo2Score = 0, SystolicBpScore = 1, HeartRateScore = 1,
ConsciousnessScore = 0, TemperatureScore = 0, SupplementalO2Score = 0
});
db.ClinicalAlerts.Add(new ClinicalAlert
{
Id = Guid.NewGuid(), EncounterId = _activeIcuEncounterId, PatientId = patientIcu.Id,
AlertType = AlertType.News2Emergency, Severity = AlertSeverity.Critical,
Details = "NEWS2 score 7", Status = AlertStatus.Open,
TriggeredAt = DateTimeOffset.UtcNow
});
db.SofaScores.Add(new SofaScore
{
Id = Guid.NewGuid(), EncounterId = _activeIcuEncounterId, PatientId = patientIcu.Id,
TotalScore = 8, RespiratoryScore = 2, CoagulationScore = 1, LiverScore = 1,
CardiovascularScore = 2, CnsScore = 1, RenalScore = 1,
DeltaFromBaseline = 2, CalculatedAt = DateTimeOffset.UtcNow,
CreatedAt = DateTimeOffset.UtcNow
});
db.GcsScores.Add(new GcsScore
{
Id = Guid.NewGuid(), EncounterId = _activeIcuEncounterId, PatientId = patientIcu.Id,
EyeScore = 3, VerbalScore = 4, MotorScore = 5, TotalScore = 12,
Classification = "MODERATE", CalculatedAt = DateTimeOffset.UtcNow,
CreatedAt = DateTimeOffset.UtcNow
});
db.Observations.Add(new Observation
{
Id = Guid.NewGuid(), EncounterId = _activeIcuEncounterId,
ObservationCode = "HEART_RATE", Value = 110m, Unit = "bpm",
Source = ObservationSource.Manual,
RecordedAt = DateTimeOffset.UtcNow.AddHours(-3),
CreatedAt = DateTimeOffset.UtcNow
});
await db.SaveChangesAsync();
}
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
public async Task ListActiveEncounters_ReturnsSummariesWithPatientNames()
{
var resp = await _client.GetAsync("/api/v1/encounters?status=ACTIVE&page=1&pageSize=20");
resp.StatusCode.Should().Be(HttpStatusCode.OK);
var body = await resp.Content.ReadFromJsonAsync<JsonDocument>();
var items = body!.RootElement.GetProperty("data").GetProperty("items");
items.GetArrayLength().Should().Be(2);
var icu = items.EnumerateArray()
.First(i => i.GetProperty("encounterId").GetGuid() == _activeIcuEncounterId);
icu.GetProperty("firstName").GetString().Should().Be("Alice");
icu.GetProperty("lastName").GetString().Should().Be("Icu");
icu.GetProperty("mrn").GetString().Should().Be("MRN-WARD-001");
icu.GetProperty("roomBed").GetString().Should().Be("ICU-3");
icu.GetProperty("news2Score").GetInt32().Should().Be(7);
icu.GetProperty("openAlertCount").GetInt32().Should().Be(1);
icu.GetProperty("qsofaScore").GetInt32().Should().Be(0);
icu.GetProperty("sofaScore").GetInt32().Should().Be(8);
icu.GetProperty("sofaDelta").GetInt32().Should().Be(2);
icu.GetProperty("gcsScore").GetInt32().Should().Be(12);
icu.GetProperty("gcsClassification").GetString().Should().Be("MODERATE");
icu.GetProperty("attendingPhysician").GetString().Should().Be("Dr. Ward");
icu.GetProperty("lastObservationAt").GetDateTimeOffset().Should().NotBe(default);
icu.GetProperty("isSimulated").GetBoolean().Should().BeFalse();
}
[Fact]
public async Task ListByDepartment_FiltersCorrectly()
{
var resp = await _client.GetAsync("/api/v1/encounters?status=ACTIVE&department=SURGERY");
resp.StatusCode.Should().Be(HttpStatusCode.OK);
var body = await resp.Content.ReadFromJsonAsync<JsonDocument>();
var items = body!.RootElement.GetProperty("data").GetProperty("items");
items.GetArrayLength().Should().Be(1);
items[0].GetProperty("encounterId").GetGuid().Should().Be(_activeSurgeryEncounterId);
items[0].GetProperty("firstName").GetString().Should().Be("Bob");
}
[Fact]
public async Task ListInvalidStatus_Returns400()
{
var resp = await _client.GetAsync("/api/v1/encounters?status=Active");
resp.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
}