feature: Self-Service Clinical Testing Sessions
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
[Collection("Integration")]
|
||||
public class AlertQualityScenarioAttributionTests : IAsyncLifetime
|
||||
{
|
||||
private readonly ApiFixture _fixture;
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public AlertQualityScenarioAttributionTests(ApiFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_client = fixture.CreateClient();
|
||||
_client.AsNurse();
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await DbResetHelper.ResetAsync(db);
|
||||
}
|
||||
|
||||
public Task DisposeAsync() => Task.CompletedTask;
|
||||
|
||||
[Fact]
|
||||
public async Task AlertQuality_FiltersByScenarioId()
|
||||
{
|
||||
Guid matchFeedbackId;
|
||||
Guid otherFeedbackId;
|
||||
|
||||
using (var scope = _fixture.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
var patientA = NewPatient("MRN-SCEN-A");
|
||||
var patientB = NewPatient("MRN-SCEN-B");
|
||||
var encounterA = NewEncounter(patientA.Id);
|
||||
var encounterB = NewEncounter(patientB.Id);
|
||||
var alertA = NewAlert(encounterA.Id, patientA.Id, AlertType.News2Warning);
|
||||
var alertB = NewAlert(encounterB.Id, patientB.Id, AlertType.News2Emergency);
|
||||
|
||||
db.Patients.AddRange(patientA, patientB);
|
||||
db.Encounters.AddRange(encounterA, encounterB);
|
||||
db.ClinicalAlerts.AddRange(alertA, alertB);
|
||||
db.SimulationRuns.Add(new SimulationRun
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
ScenarioId = "uti-sepsis-elderly-01",
|
||||
ScenarioName = "UTI Sepsis",
|
||||
Speed = 60,
|
||||
Status = SimulationRunStatus.Completed,
|
||||
PatientId = patientA.Id,
|
||||
EncounterId = encounterA.Id,
|
||||
SessionId = "session-b-alert-quality",
|
||||
StartedByUserId = "tester",
|
||||
StartedAt = DateTimeOffset.UtcNow.AddHours(-1),
|
||||
CompletedAt = DateTimeOffset.UtcNow,
|
||||
});
|
||||
db.SimulationRuns.Add(new SimulationRun
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
ScenarioId = "medication-false-alarm-01",
|
||||
ScenarioName = "Med False Alarm",
|
||||
Speed = 60,
|
||||
Status = SimulationRunStatus.Completed,
|
||||
PatientId = patientB.Id,
|
||||
EncounterId = encounterB.Id,
|
||||
SessionId = "session-b-alert-quality",
|
||||
StartedByUserId = "tester",
|
||||
StartedAt = DateTimeOffset.UtcNow.AddHours(-1),
|
||||
CompletedAt = DateTimeOffset.UtcNow,
|
||||
});
|
||||
|
||||
var fbA = new AlertFeedback
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AlertId = alertA.Id,
|
||||
UserId = Guid.NewGuid(),
|
||||
FeedbackType = AlertFeedbackType.WouldAct,
|
||||
CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-10),
|
||||
};
|
||||
var fbB = new AlertFeedback
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AlertId = alertB.Id,
|
||||
UserId = Guid.NewGuid(),
|
||||
FeedbackType = AlertFeedbackType.FalsePositive,
|
||||
CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-5),
|
||||
};
|
||||
db.AlertFeedbacks.AddRange(fbA, fbB);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
matchFeedbackId = fbA.Id;
|
||||
otherFeedbackId = fbB.Id;
|
||||
}
|
||||
|
||||
var all = await _client.GetAsync("/api/v1/alerts/quality-metrics/feedback");
|
||||
all.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var allBody = await all.Content.ReadFromJsonAsync<JsonDocument>();
|
||||
var allItems = allBody!.RootElement.GetProperty("data").GetProperty("items");
|
||||
allItems.GetArrayLength().Should().Be(2);
|
||||
|
||||
var match = allItems.EnumerateArray()
|
||||
.Single(e => e.GetProperty("id").GetGuid() == matchFeedbackId);
|
||||
match.GetProperty("scenarioId").GetString().Should().Be("uti-sepsis-elderly-01");
|
||||
match.GetProperty("sessionId").GetString().Should().Be("session-b-alert-quality");
|
||||
|
||||
var filtered = await _client.GetAsync(
|
||||
"/api/v1/alerts/quality-metrics/feedback?scenarioId=uti-sepsis-elderly-01");
|
||||
filtered.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var filteredBody = await filtered.Content.ReadFromJsonAsync<JsonDocument>();
|
||||
var filteredItems = filteredBody!.RootElement.GetProperty("data").GetProperty("items");
|
||||
filteredItems.GetArrayLength().Should().Be(1);
|
||||
filteredItems[0].GetProperty("id").GetGuid().Should().Be(matchFeedbackId);
|
||||
filteredItems[0].GetProperty("scenarioId").GetString().Should().Be("uti-sepsis-elderly-01");
|
||||
|
||||
// Other scenario's feedback must not leak into the filter.
|
||||
filteredItems.EnumerateArray()
|
||||
.Any(e => e.GetProperty("id").GetGuid() == otherFeedbackId)
|
||||
.Should().BeFalse();
|
||||
}
|
||||
|
||||
private static Patient NewPatient(string mrn) => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Mrn = mrn,
|
||||
FirstName = "Sim",
|
||||
LastName = "Patient",
|
||||
DateOfBirth = new DateOnly(1980, 1, 1),
|
||||
Gender = "F",
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
IsSimulated = true,
|
||||
};
|
||||
|
||||
private static Encounter NewEncounter(Guid patientId) => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
PatientId = patientId,
|
||||
EncounterType = EncounterType.Inpatient,
|
||||
Status = EncounterStatus.Active,
|
||||
Department = Department.Icu,
|
||||
AttendingPhysician = "Dr. Test",
|
||||
AdmittedAt = DateTimeOffset.UtcNow,
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
};
|
||||
|
||||
private static ClinicalAlert NewAlert(Guid encounterId, Guid patientId, AlertType type) => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
EncounterId = encounterId,
|
||||
PatientId = patientId,
|
||||
AlertType = type,
|
||||
Severity = AlertSeverity.Warning,
|
||||
Details = "Test alert",
|
||||
Status = AlertStatus.Acknowledged,
|
||||
TriggeredAt = DateTimeOffset.UtcNow.AddMinutes(-30),
|
||||
AcknowledgedAt = DateTimeOffset.UtcNow.AddMinutes(-20),
|
||||
AcknowledgedBy = "nurse",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user