import { expect, test, type Page, type Response } from "@playwright/test"; import { expectNoHorizontalOverflow, fetchAvailablePersona, signInAsLearner } from "./support"; interface SessionStartResponse { session_id: string; } async function expectResponseOk(response: { ok: () => boolean; text: () => Promise }) { if (!response.ok()) { expect(response.ok(), await response.text()).toBeTruthy(); } } function isReviewResponse(sessionId: string) { return (response: Response) => { const url = new URL(response.url()); return ( response.request().method() === "GET" && url.pathname.endsWith(`/sessions/${sessionId}/review`) ); }; } async function createEndedSession(page: Page) { const persona = await fetchAvailablePersona(page, 1); const start = await page.request.post("/api/sessions", { data: { persona_code: persona.code, theory_mode: "humanistic", }, }); await expectResponseOk(start); const session = (await start.json()) as SessionStartResponse; const ended = await page.request.post(`/api/sessions/${session.session_id}/end`); await expectResponseOk(ended); return session.session_id; } test.describe("session review", () => { test("renders server review data without legacy transcript fixtures", async ({ page }) => { await signInAsLearner(page); const sessionId = await createEndedSession(page); const reviewResponsePromise = page.waitForResponse(isReviewResponse(sessionId)); await page.goto(`/learn/session/${sessionId}/review`); const reviewResponse = await reviewResponsePromise; await expectResponseOk(reviewResponse); const review = await reviewResponse.json(); expect(review.session_id).toBe(sessionId); expect(review.reviewReady).toBe(false); expect(review.turns).toHaveLength(0); await expect(page).toHaveURL(new RegExp(`/learn/session/${sessionId}/review$`)); await expect(page.getByText("축어록 없음")).toBeVisible(); await expect(page.getByText("감정 타임라인 대기")).toBeVisible(); await expect(page.getByText("개선점 대기")).toBeVisible(); await expect(page.getByRole("button", { name: "오디오 다시 듣기" })).toBeDisabled(); await expect(page.getByRole("button", { name: "PDF 내보내기" })).toBeDisabled(); await expect(page.getByText("32분 14초")).toHaveCount(0); await expect(page.getByText("시연")).toHaveCount(0); const filterMetrics = await page.locator(".sr-chip-toggle").evaluateAll((buttons) => buttons.map((button) => { const rect = button.getBoundingClientRect(); const style = window.getComputedStyle(button); return { height: Math.ceil(rect.height), whiteSpace: style.whiteSpace, }; }), ); expect(filterMetrics.every((item) => item.height <= 34 && item.whiteSpace === "nowrap")).toBe( true, ); await expectNoHorizontalOverflow(page); }); });