You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

68 lines
2.9 KiB
TypeScript

// frontend/playwright/inbox.spec.ts
// phase-16+: 휴리스틱 제거 → 분류는 실 Ollama(수초·비결정). 정확한 라벨 대신 '흐름'을 검증한다.
import AxeBuilder from "@axe-core/playwright";
import { expect, test } from "@playwright/test";
import { resetSeed } from "./fixtures/seed-reset";
test.describe.configure({ mode: "serial" });
test.beforeAll(resetSeed);
test("캡처 → 분류 카드 → 확인 → 작업 등장(연합)", async ({ page }) => {
test.setTimeout(150_000); // 실 Ollama 35B 콜드스타트 + 분류 여유
await page.goto("/inbox");
const input = page.getByLabel("인박스에 빠르게 캡처");
await input.fill("다음 주에 한국 놀러가는 비행기 티켓 사기");
await input.press("Enter");
const fresh = page.locator(".sb-cap.fresh").first();
// 실 Ollama 분류(수초) → 확인 버튼 노출
await expect(fresh.getByRole("button", { name: /좋아요, 그렇게 해줘/ })).toBeVisible({
timeout: 90000,
});
await fresh.getByRole("button", { name: /좋아요, 그렇게 해줘/ }).click();
// 연합: 확인 → 작업 실체화. 결과(작업 페이지에 카드 등장)로 검증(card 재렌더 타이밍 무관).
await expect
.poll(
async () => {
await page.goto("/tasks");
await page.locator(".tree-row.folder", { hasText: "개인" }).click();
const p = await page.locator(".kcard").count();
await page.locator(".tree-row.folder", { hasText: "업무" }).click();
const w = await page.locator(".kcard").count();
return p + w;
},
{ timeout: 30000 },
)
.toBeGreaterThan(0);
});
test("다르게 분류 — 재분류 버튼 동작", async ({ page }) => {
test.setTimeout(150_000);
await page.goto("/inbox");
const input = page.getByLabel("인박스에 빠르게 캡처");
await input.fill("리포트 회신 보내기");
await input.press("Enter");
const fresh = page.locator(".sb-cap.fresh").first();
await expect(fresh.getByRole("button", { name: /다르게 분류/ })).toBeVisible({ timeout: 90000 });
// 재분류 클릭 → 카드 유지(타입 순환은 LLM 라벨에 의존하므로 정확값은 단언하지 않음)
await fresh.getByRole("button", { name: /다르게 분류/ }).click();
await expect(fresh).toBeVisible();
});
test("음성 스텁 — voice 아이콘 행", async ({ page }) => {
await page.goto("/inbox");
await page.getByLabel(/음성으로 캡처/).click();
await expect(page.locator(".cap-k.voice").first()).toBeVisible();
});
test("a11y — axe 위반 없음(color-contrast 제외)", async ({ page }) => {
await page.goto("/inbox");
await expect(page.getByRole("heading", { name: "스마트 인박스", exact: true })).toBeVisible();
const r = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.disableRules(["color-contrast"])
.analyze();
expect(r.violations).toEqual([]);
});