76 lines
2.7 KiB
TypeScript
76 lines
2.7 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import type { Page } from "@playwright/test";
|
|
|
|
import { apiBaseUrl } from "./api-base-url";
|
|
|
|
type ApiProbe = {
|
|
readonly message: string | null;
|
|
readonly status: number;
|
|
};
|
|
|
|
async function fetchMockApi(page: Page, path: string, init?: RequestInit): Promise<ApiProbe> {
|
|
return page.evaluate(
|
|
async ({ apiBaseUrl, init, path }) => {
|
|
const response = await fetch(`${apiBaseUrl}${path}`, init);
|
|
const body = (await response.json()) as { readonly message?: string | null };
|
|
|
|
return { message: body.message ?? null, status: response.status };
|
|
},
|
|
{ apiBaseUrl, init, path },
|
|
);
|
|
}
|
|
|
|
async function waitForMockWorker(page: Page): Promise<void> {
|
|
await page.goto("/");
|
|
await expect
|
|
.poll(() => page.evaluate(async () => {
|
|
const registration = await navigator.serviceWorker.ready;
|
|
|
|
return registration.active?.scriptURL.endsWith("/mockServiceWorker.js") ?? false;
|
|
}))
|
|
.toBe(true);
|
|
if (!(await page.evaluate(() => navigator.serviceWorker.controller !== null))) {
|
|
await page.reload();
|
|
}
|
|
await expect.poll(() => page.evaluate(() => navigator.serviceWorker.controller !== null)).toBe(true);
|
|
}
|
|
|
|
test("mock API exposes Korean auth and media error messages without backend fallback", async ({ page }) => {
|
|
// Given
|
|
await waitForMockWorker(page);
|
|
|
|
// When
|
|
const missingBearer = await fetchMockApi(page, "/api/v2/admin/ai-characters?page=0&size=20");
|
|
const forbiddenLogout = await fetchMockApi(page, "/member/logout", {
|
|
headers: { Authorization: "Bearer mock-member-jwt" },
|
|
method: "POST",
|
|
});
|
|
const unsupportedLoginMedia = await fetchMockApi(page, "/admin/member/login", {
|
|
body: "not-json",
|
|
headers: { "Content-Type": "text/plain" },
|
|
method: "POST",
|
|
});
|
|
|
|
// Then
|
|
expect(missingBearer).toEqual({ message: "인증 정보가 없습니다.", status: 401 });
|
|
expect(forbiddenLogout).toEqual({ message: "접근 권한이 없습니다.", status: 403 });
|
|
expect(unsupportedLoginMedia).toEqual({ message: "지원하지 않는 미디어 타입입니다.", status: 415 });
|
|
});
|
|
|
|
test("mock preview does not persist secrets or file bodies in browser storage", async ({ page }) => {
|
|
// Given
|
|
await page.goto("/login");
|
|
await page.getByLabel("이메일").fill("admin@test.com");
|
|
await page.getByLabel("비밀번호").fill("password");
|
|
await page.getByRole("button", { name: "로그인" }).click();
|
|
await expect(page).toHaveURL(/\/ai-characters$/);
|
|
|
|
// When
|
|
const storageDump = await page.evaluate(() => JSON.stringify({ local: { ...localStorage }, session: { ...sessionStorage } }));
|
|
|
|
// Then
|
|
expect(storageDump).not.toContain("password");
|
|
expect(storageDump).not.toContain("data:audio");
|
|
expect(storageDump).not.toContain("data:image");
|
|
});
|