안전 이벤트 대시보드 보강
This commit is contained in:
parent
fe2796f05a
commit
51053af536
15 changed files with 1081 additions and 423 deletions
|
|
@ -11,6 +11,17 @@ interface HealthResponse {
|
|||
engine?: boolean;
|
||||
}
|
||||
|
||||
interface TeacherSafetyAlert {
|
||||
session_id: string;
|
||||
resource_title: string;
|
||||
resource_number: string;
|
||||
}
|
||||
|
||||
interface TeacherDashboardResponse {
|
||||
source: string;
|
||||
safety_alerts: TeacherSafetyAlert[];
|
||||
}
|
||||
|
||||
interface ReviewTurn {
|
||||
speaker: string;
|
||||
text: string;
|
||||
|
|
@ -492,6 +503,72 @@ test.describe("session persistence", () => {
|
|||
).toBe(true);
|
||||
});
|
||||
|
||||
test("persists crisis safety event into DB-backed teacher dashboard @single-run", async ({
|
||||
page,
|
||||
}) => {
|
||||
test.setTimeout(120_000);
|
||||
|
||||
const healthResponse = await page.request.get("/api/health");
|
||||
await expectResponseOk(healthResponse);
|
||||
const health = (await healthResponse.json()) as HealthResponse;
|
||||
test.skip(!health.db, "crisis safety queue persistence requires DB");
|
||||
|
||||
await signInAsLearner(page);
|
||||
const persona = await fetchAvailablePersona(page, 1);
|
||||
const crisisText = "저 지금 자살하고 싶어요. 도와주세요.";
|
||||
|
||||
await page.goto(`/learn/session/${persona.code}`);
|
||||
await page.getByRole("button", { name: "회기 시작" }).click();
|
||||
await expect(page.locator(".sx-page.sx-page--active")).toBeVisible({ timeout: 15_000 });
|
||||
await expect(page).toHaveURL(/\/learn\/session\/[0-9a-f-]+$/i);
|
||||
const sessionId = new URL(page.url()).pathname.split("/").at(-1);
|
||||
expect(sessionId).toMatch(/^[0-9a-f-]+$/i);
|
||||
|
||||
const streamResponsePromise = page.waitForResponse((response) => {
|
||||
const url = new URL(response.url());
|
||||
return (
|
||||
response.request().method() === "POST" &&
|
||||
url.pathname.endsWith(`/api/sessions/${sessionId}/stream`)
|
||||
);
|
||||
});
|
||||
|
||||
const input = page.getByLabel("학습자 발화 입력");
|
||||
await input.fill(crisisText);
|
||||
await page.getByRole("button", { name: "보내기" }).click();
|
||||
|
||||
const streamResponse = await streamResponsePromise;
|
||||
await expectResponseOk(streamResponse);
|
||||
await expect(page.locator(".sx-crisis-resource")).toContainText("자살예방상담전화 109", {
|
||||
timeout: 15_000,
|
||||
});
|
||||
await expect(page.getByRole("link", { name: "109" })).toBeVisible();
|
||||
await expect(input).toBeDisabled();
|
||||
|
||||
await signInAsTeacher(page);
|
||||
await expect
|
||||
.poll(
|
||||
async () => {
|
||||
const dashboardResponse = await page.request.get("/api/teacher/dashboard");
|
||||
await expectResponseOk(dashboardResponse);
|
||||
const dashboard = (await dashboardResponse.json()) as TeacherDashboardResponse;
|
||||
expect(dashboard.source).toBe("database");
|
||||
return dashboard.safety_alerts.some(
|
||||
(alert) => alert.session_id === sessionId && alert.resource_number === "109",
|
||||
);
|
||||
},
|
||||
{
|
||||
timeout: 30_000,
|
||||
intervals: [500, 1_000, 2_000],
|
||||
message: "crisis safety event should reach the DB-backed teacher dashboard",
|
||||
},
|
||||
)
|
||||
.toBe(true);
|
||||
|
||||
await page.goto("/teach");
|
||||
await expect(page.getByText("109 안전 확인 큐")).toBeVisible({ timeout: 15_000 });
|
||||
await expect(page.locator(".pf-alert").filter({ hasText: sessionId ?? "" })).toContainText("109");
|
||||
});
|
||||
|
||||
test("persists AI tutor coaching history through reload @single-run", async ({ page }) => {
|
||||
test.setTimeout(150_000);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue