95 lines
3.5 KiB
TypeScript
95 lines
3.5 KiB
TypeScript
import { expect, test, type Page } from "@playwright/test";
|
|
import { fetchAvailablePersona, signInAsLearner, signInAsTeacher } from "./support";
|
|
|
|
interface SessionStartResponse {
|
|
session_id: string;
|
|
degraded: boolean;
|
|
}
|
|
|
|
async function expectResponseOk(response: { ok: () => boolean; text: () => Promise<string> }) {
|
|
if (!response.ok()) {
|
|
expect(response.ok(), await response.text()).toBeTruthy();
|
|
}
|
|
}
|
|
|
|
async function createSessionWithTurn(page: Page) {
|
|
const persona = await fetchAvailablePersona(page);
|
|
const startedResponse = await page.request.post("/api/sessions", {
|
|
data: {
|
|
persona_code: persona.code,
|
|
theory_mode: "humanistic",
|
|
},
|
|
});
|
|
await expectResponseOk(startedResponse);
|
|
|
|
const started = (await startedResponse.json()) as SessionStartResponse;
|
|
expect(started.degraded).toBe(false);
|
|
|
|
let turnResponse = await page.request.post(`/api/sessions/${started.session_id}/turn`, {
|
|
data: {
|
|
text: "오늘 많이 버거웠겠어요. 지금 가장 크게 남아 있는 마음은 어떤 건가요?",
|
|
},
|
|
});
|
|
for (let attempt = 0; attempt < 2 && !turnResponse.ok(); attempt += 1) {
|
|
await page.waitForTimeout(1000);
|
|
turnResponse = await page.request.post(`/api/sessions/${started.session_id}/turn`, {
|
|
data: {
|
|
text: "조금 천천히 이야기해도 괜찮습니다. 지금 마음에 남는 장면이 있나요?",
|
|
},
|
|
});
|
|
}
|
|
let expectedMinTurns = 2;
|
|
if (!turnResponse.ok()) {
|
|
expect(turnResponse.status(), await turnResponse.text()).toBe(503);
|
|
expectedMinTurns = 1;
|
|
}
|
|
|
|
const endedResponse = await page.request.post(`/api/sessions/${started.session_id}/end`);
|
|
await expectResponseOk(endedResponse);
|
|
|
|
return { sessionId: started.session_id, expectedMinTurns };
|
|
}
|
|
|
|
test.describe("session persistence", () => {
|
|
test("persists learner turns into DB-backed review and teacher dashboard @single-run", async ({ page }) => {
|
|
await signInAsLearner(page);
|
|
const { sessionId, expectedMinTurns } = await createSessionWithTurn(page);
|
|
|
|
const reviewResponse = await page.request.get(`/api/sessions/${sessionId}/review`);
|
|
await expectResponseOk(reviewResponse);
|
|
const review = await reviewResponse.json();
|
|
expect(review.session_id).toBe(sessionId);
|
|
expect(review.turns.length).toBeGreaterThanOrEqual(expectedMinTurns);
|
|
expect(review.turns[0].speaker).toBe("learner");
|
|
if (review.reviewReady) {
|
|
expect(review.degraded).toBe(false);
|
|
expect(review.summary).toContain("평가 AI");
|
|
} else {
|
|
expect(review.degraded).toBe(true);
|
|
expect(review.rubric).toHaveLength(0);
|
|
expect(review.goodMoments).toHaveLength(0);
|
|
expect(review.growthPoints).toHaveLength(0);
|
|
expect(review.summary).not.toContain("잘한 구체적");
|
|
}
|
|
|
|
const hasClientTurn = review.turns.some(
|
|
(turn: { speaker: string }) => turn.speaker === "client",
|
|
);
|
|
if (hasClientTurn) {
|
|
expect(review.clientFeedback).toEqual(expect.any(String));
|
|
expect(review.clientFeedback.length).toBeGreaterThan(0);
|
|
}
|
|
|
|
await signInAsTeacher(page);
|
|
const dashboardResponse = await page.request.get("/api/teacher/dashboard");
|
|
await expectResponseOk(dashboardResponse);
|
|
const dashboard = await dashboardResponse.json();
|
|
expect(dashboard.source).toBe("database");
|
|
expect(
|
|
dashboard.recent_sessions.some(
|
|
(session: { session_id: string; turn_count: number }) =>
|
|
session.session_id === sessionId && session.turn_count >= expectedMinTurns,
|
|
),
|
|
).toBe(true);
|
|
});
|
|
});
|