import { expect, test, type Locator, type Page } from "@playwright/test"; import { signInAsAdmin, signInAsTeacher } from "./support"; async function expectConnectedTabPanel(tab: Locator, panel: Locator) { const tabId = await tab.getAttribute("id"); const panelId = await panel.getAttribute("id"); expect(tabId).toBeTruthy(); expect(panelId).toBeTruthy(); await expect(tab).toHaveAttribute("aria-controls", panelId!); await expect(panel).toHaveAttribute("aria-labelledby", tabId!); } async function expectKeyboardSelection( page: Page, tablistName: string, startName: string, key: "ArrowRight" | "ArrowLeft" | "Home" | "End", expectedName: string, ) { const tablist = page.getByRole("tablist", { name: tablistName }); const start = tablist.getByRole("tab", { name: startName }); const expected = tablist.getByRole("tab", { name: expectedName }); const panel = page.getByRole("tabpanel"); await start.focus(); await start.press(key); await expect(expected).toBeFocused(); await expect(expected).toHaveAttribute("aria-selected", "true"); await expect(expected).toHaveAttribute("tabindex", "0"); await expect(start).toHaveAttribute("tabindex", startName === expectedName ? "0" : "-1"); await expectConnectedTabPanel(expected, panel); } test.describe("공통 Tabs behavior", () => { test("관리자 사용자·접근 권한 탭이 패널 연결과 roving keyboard를 공유한다 @single-run", async ({ page, }) => { await signInAsAdmin(page); await page.goto("/admin/users"); const userTabs = page.getByRole("tablist", { name: "사용자 관리 탭" }); const approval = userTabs.getByRole("tab", { name: /가입 승인/ }); const userPanel = page.getByRole("tabpanel"); await expect(userTabs).toBeVisible(); await expect(userTabs).toHaveAttribute("id", "admin-users-tabs"); await expect(userPanel).toHaveAttribute("id", "admin-users-tabs-panel"); await expect(userTabs).not.toHaveClass(/vg-surface/); await expectConnectedTabPanel(approval, userPanel); await expectKeyboardSelection( page, "사용자 관리 탭", "가입 승인", "ArrowRight", "사용자 목록", ); await expectKeyboardSelection( page, "사용자 관리 탭", "사용자 목록", "End", "활동 요약", ); await expectKeyboardSelection( page, "사용자 관리 탭", "활동 요약", "Home", "가입 승인", ); await page.goto("/admin/access"); const accessTabs = page.getByRole("tablist", { name: "접근 권한 탭" }); const roles = accessTabs.getByRole("tab", { name: "역할", exact: true }); const accessPanel = page.getByRole("tabpanel"); await expect(accessTabs).toBeVisible(); await expect(accessTabs).toHaveAttribute("id", "admin-access-tabs"); await expect(accessPanel).toHaveAttribute("id", "admin-access-tabs-panel"); await expect(accessTabs).not.toHaveClass(/vg-surface/); await expectConnectedTabPanel(roles, accessPanel); await expectKeyboardSelection( page, "접근 권한 탭", "역할", "End", "상담 프로토콜", ); await expectKeyboardSelection( page, "접근 권한 탭", "상담 프로토콜", "Home", "역할", ); }); test("페르소나 저작 탭이 같은 패널 연결과 방향키 계약을 사용한다 @single-run", async ({ page, }) => { await signInAsTeacher(page); await page.route("**/api/personas", async (route) => { if (route.request().method() !== "GET") return route.fallback(); await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify([]), }); }); await page.route("**/api/personas/review", async (route) => { if (route.request().method() !== "GET") return route.fallback(); await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify([]), }); }); await page.goto("/teach/personas?view=personas&mode=create&step=edit"); const tablist = page.getByRole("tablist", { name: "저작 섹션" }); const overview = tablist.getByRole("tab", { name: "개요", exact: true }); const panel = page.getByRole("tabpanel"); await expect(tablist).toBeVisible(); await expect(tablist).toHaveAttribute("id", "persona-authoring-tabs"); await expect(panel).toHaveAttribute("id", "persona-authoring-tabs-panel"); await expect(tablist).not.toHaveClass(/vg-surface/); await expectConnectedTabPanel(overview, panel); await expectKeyboardSelection( page, "저작 섹션", "개요", "ArrowRight", "임상", ); await expectKeyboardSelection(page, "저작 섹션", "임상", "End", "프롬프트"); await expectKeyboardSelection(page, "저작 섹션", "프롬프트", "Home", "개요"); }); });