전 저장소 리팩터링과 SSOT 정비

This commit is contained in:
Yun Chan 2026-07-15 21:31:30 +09:00
parent 14ecbd4e7d
commit 3dfddcac6f
173 changed files with 19679 additions and 6952 deletions

View file

@ -529,6 +529,13 @@ async function evaluationState(page: Page, sessionId: string) {
return `pending:${body.status ?? "none"}:${body.durable ? "durable" : "cache"}:${loop}`;
}
/** 리뷰는 모든 폭에서 가로 탭으로 영역을 전환한다. */
async function openReviewTab(page: Page, label: "축어록" | "피드백" | "워크시트") {
const tabs = page.locator(".sr-tabs");
await tabs.waitFor({ state: "attached", timeout: 20_000 });
await tabs.locator("button", { hasText: label }).click();
}
test.describe("session persistence", () => {
test("persists selected CBT theory mode from session UI into DB-backed detail @single-run", async ({
page,
@ -781,7 +788,7 @@ test.describe("session persistence", () => {
});
test("persists AI tutor coaching history through reload @single-run", async ({ page }) => {
test.setTimeout(150_000);
test.setTimeout(240_000);
const healthResponse = await page.request.get("/api/health");
await expectResponseOk(healthResponse);
@ -890,7 +897,7 @@ test.describe("session persistence", () => {
});
test("persists voice nonverbal metadata into DB-backed review @single-run", async ({ page }) => {
test.setTimeout(120_000);
test.setTimeout(240_000);
const healthResponse = await page.request.get("/api/health");
await expectResponseOk(healthResponse);
@ -937,7 +944,9 @@ test.describe("session persistence", () => {
const timeout = window.setTimeout(() => {
ws.close();
finish(-1);
}, 60_000);
// dev 엔진(Claude CLI 게이트웨이) 음성 턴이 90초를 넘기도 한다 — 게이트웨이
// GENERATE_TURN_TIMEOUT_SECONDS(300초)와 정합하게 150초까지 기다린다.
}, 150_000);
ws.onopen = () => {
ws.send(JSON.stringify({ type: "audio_start", format: "webm" }));
@ -1085,7 +1094,7 @@ test.describe("session persistence", () => {
reply: events.some((event) => event.type === "reply"),
errors: events.filter((event) => event.type === "error" || event.type === "degraded").length,
};
}, { timeout: 60_000 })
}, { timeout: 90_000 })
.toEqual({ transcript: true, reply: true, errors: 0 });
const reviewResponse = await page.request.get(`/api/sessions/${sessionId}/review`);
@ -1166,6 +1175,7 @@ test.describe("session persistence", () => {
).toBeGreaterThanOrEqual(2);
await page.goto(`/learn/session/${sessionId}/review`);
await openReviewTab(page, "워크시트");
const worksheetCard = page.locator(".sr-card--worksheet");
await expect(worksheetCard).toBeVisible({ timeout: 20_000 });
await expect(worksheetCard).toContainText("축어록 기반 자동 초안");
@ -1188,10 +1198,13 @@ test.describe("session persistence", () => {
await signInAsTeacher(page);
await page.goto(`/teach/session/${sessionId}/review`);
await openReviewTab(page, "워크시트");
await expect(worksheetCard).toBeVisible({ timeout: 20_000 });
await expect(worksheetCard).toContainText("학습자 저장본 읽기 전용");
await expect(worksheetCard.locator(".sr-ws-input").first()).toHaveValue(savedWorksheetValue);
// 워크시트 검수 메모·수정요청은 교수자 검토 카드(피드백 탭)에 있다.
await openReviewTab(page, "피드백");
const teacherWorksheetNote = `보호요인 보강 요청 ${Date.now()}`;
await page.getByLabel("워크시트 검수 메모").fill(teacherWorksheetNote);
await page.getByRole("button", { name: "수정요청" }).click();
@ -1226,6 +1239,7 @@ test.describe("session persistence", () => {
const sessionId = await createEndedSessionWithoutTurn(page);
await page.goto(`/learn/session/${sessionId}/review`);
await openReviewTab(page, "피드백");
await expect(page.locator(".sr-card--prepost")).toBeVisible({ timeout: 15_000 });
await expect(page.locator(".sr-prepost__actions")).toContainText("저장된 값 기준");
@ -1272,6 +1286,7 @@ test.describe("session persistence", () => {
expect(byKey.get("training_satisfaction:post")).toBe(Number(targetValues[5]));
await page.reload();
await openReviewTab(page, "피드백");
await expect(page.locator(".sr-card--prepost")).toBeVisible({ timeout: 15_000 });
await expect(page.getByText("3/3 쌍")).toBeVisible();
for (let index = 0; index < targetValues.length; index += 1) {