test(ai-character): 리소스 운영 E2E 보강

This commit is contained in:
Yu Sung
2026-08-01 01:30:52 +09:00
parent 3faca90135
commit 3759abf8b7
16 changed files with 1962 additions and 62 deletions

View File

@@ -16,6 +16,12 @@ async function zoomTo200Percent(page: Page): Promise<void> {
});
}
async function resetZoom(page: Page): Promise<void> {
await page.evaluate(() => {
document.documentElement.style.zoom = "";
});
}
async function expectNoHorizontalOverflow(page: Page): Promise<void> {
const hasHorizontalOverflow = await page.evaluate(
() => document.documentElement.scrollWidth > document.documentElement.clientWidth,
@@ -38,7 +44,7 @@ async function expectBannerDoesNotOverlap(banner: Locator, control: Locator): Pr
expect(bannerBox.y + bannerBox.height).toBeLessThanOrEqual(controlBox.y);
}
test("logs in through mock mode and opens the protected shell without backend fallback", async ({ page }) => {
test("opens the mock shell without backend fallback and keeps the 320px session usable", async ({ page }) => {
// Given
const interceptedApiContractRequests: string[] = [];
page.on("request", (request) => {
@@ -54,20 +60,33 @@ test("logs in through mock mode and opens the protected shell without backend fa
// Then
await expect(page.getByRole("status", { name: /Mock Preview/ })).toBeVisible();
await expect(page.getByRole("heading", { name: "AI 캐릭터", exact: true })).toBeVisible();
expect(interceptedApiContractRequests).toEqual([
const results = await new AxeBuilder({ page }).analyze();
const blockingViolations = results.violations.filter(
(violation) => violation.impact === "critical" || violation.impact === "serious",
);
expect(blockingViolations).toEqual([]);
expect(new Set(interceptedApiContractRequests)).toEqual(new Set([
"POST /admin/member/login",
"GET /api/v2/admin/ai-characters?page=0&size=20",
]);
});
test("logs out and logs in again with a fresh mock preview session", async ({ page }) => {
// Given
await loginThroughMockMode(page);
await expect(page.getByRole("heading", { name: "AI 캐릭터", exact: true })).toBeVisible();
]));
// When
await page.getByRole("button", { name: "로그아웃" }).click();
await expect(page).toHaveURL(/\/login$/);
await page.setViewportSize({ width: 320, height: 640 });
await zoomTo200Percent(page);
const loginBanner = page.getByRole("status", { name: /Mock Preview/ });
const email = page.getByLabel("이메일");
await expect(loginBanner).toBeVisible();
await expect(email).toBeVisible();
await expect(page.getByLabel("비밀번호")).toBeVisible();
await expect(page.getByRole("button", { name: "로그인" })).toBeVisible();
await expectBannerDoesNotOverlap(loginBanner, email);
await expectNoHorizontalOverflow(page);
await resetZoom(page);
await page.getByLabel("이메일").fill("admin@test.com");
await page.getByLabel("비밀번호").fill("password");
await page.getByRole("button", { name: "로그인" }).click();
@@ -75,36 +94,8 @@ test("logs out and logs in again with a fresh mock preview session", async ({ pa
// Then
await expect(page).toHaveURL(/\/ai-characters$/);
await expect(page.getByRole("heading", { name: "AI 캐릭터", exact: true })).toBeVisible();
});
test("keeps the mock login banner and core controls usable at 320px and 200 percent zoom", async ({ page }) => {
// Given
await page.setViewportSize({ width: 320, height: 640 });
await page.goto("/login");
// When
await zoomTo200Percent(page);
// Then
const banner = page.getByRole("status", { name: /Mock Preview/ });
const email = page.getByLabel("이메일");
await expect(banner).toBeVisible();
await expect(email).toBeVisible();
await expect(page.getByLabel("비밀번호")).toBeVisible();
await expect(page.getByRole("button", { name: "로그인" })).toBeVisible();
await expectBannerDoesNotOverlap(banner, email);
await expectNoHorizontalOverflow(page);
});
test("keeps the mock protected banner and shell controls usable at 320px and 200 percent zoom", async ({ page }) => {
// Given
await page.setViewportSize({ width: 320, height: 640 });
await loginThroughMockMode(page);
// When
await zoomTo200Percent(page);
// Then
const banner = page.getByRole("status", { name: /Mock Preview/ });
const menuButton = page.getByRole("button", { name: "모바일 메뉴 열기" });
await expect(banner).toBeVisible();
@@ -112,11 +103,7 @@ test("keeps the mock protected banner and shell controls usable at 320px and 200
await expect(page.getByRole("button", { name: "로그아웃" })).toBeVisible();
await expectBannerDoesNotOverlap(banner, menuButton);
await expectNoHorizontalOverflow(page);
});
test("keeps the mock banner in the mobile menu background and clears inert state at desktop widths", async ({ page }) => {
// Given
await loginThroughMockMode(page);
await resetZoom(page);
for (const desktopWidth of [1024, 1200]) {
await page.setViewportSize({ width: 320, height: 640 });
@@ -154,17 +141,3 @@ test("keeps the mock banner in the mobile menu background and clears inert state
expect(desktopState).toEqual({ bannerHidden: false, bannerInert: false, mainInert: false });
}
});
test("has no critical or serious axe violations in mock preview mode", async ({ page }) => {
// Given
await loginThroughMockMode(page);
// When
const results = await new AxeBuilder({ page }).analyze();
const blockingViolations = results.violations.filter(
(violation) => violation.impact === "critical" || violation.impact === "serious",
);
// Then
expect(blockingViolations).toEqual([]);
});