168 lines
7.2 KiB
C#
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);
|
|
}
|
|
}
|