import { test, expect, Page } from "@playwright/test"; // 로컬 DEV_AUTH: 기본 로드는 super-admin(관리자), '/?as=user' 로드는 비관리자(김주임). const API = "http://localhost:8380/api"; const stamp = Date.now().toString().slice(-6); // 콘솔/페이지 에러를 모아 테스트에서 검증(치명적 JS 에러 감지). function trackErrors(page: Page): string[] { const errs: string[] = []; page.on("pageerror", (e) => errs.push("pageerror: " + e.message)); page.on("console", (m) => { if (m.type() === "error") errs.push("console: " + m.text()); }); return errs; } test.afterAll(async ({ request }) => { // E2E로 만든 프로젝트/일정 정리 const projs = await (await fetch(`${API}/projects`)).json().catch(() => []); for (const p of Array.isArray(projs) ? projs : []) { if (typeof p.name === "string" && p.name.includes("E2E")) { await fetch(`${API}/projects/${p.id}`, { method: "DELETE" }).catch(() => {}); } } const evs = await (await fetch(`${API}/calendar/events`)).json().catch(() => []); for (const e of Array.isArray(evs) ? evs : []) { if (typeof e.title === "string" && e.title.includes("E2E")) { await fetch(`${API}/calendar/events/${e.id}`, { method: "DELETE" }).catch(() => {}); } } }); test.describe("관리자(super-admin)", () => { test("대시보드 + 사이드바 네비", async ({ page }) => { const errs = trackErrors(page); await page.goto("/"); await expect(page.getByText(/안녕하세요/)).toBeVisible(); await expect(page.getByText("내 이슈")).toBeVisible(); // 사이드바: 일반 + 관리자 메뉴 await expect(page.getByRole("link", { name: "프로젝트", exact: true })).toBeVisible(); await expect(page.getByRole("link", { name: "캘린더" })).toBeVisible(); await expect(page.getByRole("link", { name: "프로젝트 관리" })).toBeVisible(); await expect(page.getByRole("link", { name: "회계" })).toBeVisible(); expect(errs, errs.join("\n")).toHaveLength(0); }); test("쪽지함 명칭", async ({ page }) => { await page.goto("/inbox"); await expect(page.getByRole("heading", { name: "쪽지함" })).toBeVisible(); }); test("캘린더 페이지 + 일정 생성", async ({ page }) => { const errs = trackErrors(page); await page.goto("/calendar"); await expect(page.getByRole("heading", { name: "캘린더" })).toBeVisible(); await page.getByRole("button", { name: "일정 추가" }).click(); const title = `E2E일정-${stamp}`; await page.getByPlaceholder("예: 고객 미팅").fill(title); // 분류/시작일은 기본값(기타/오늘) 사용 await page.getByRole("button", { name: "추가", exact: true }).click(); await expect(page.getByTitle(new RegExp(title))).toBeVisible(); expect(errs, errs.join("\n")).toHaveLength(0); }); test("프로젝트 생성(모달) → 목록 반영", async ({ page }) => { await page.goto("/admin/projects"); await expect(page.getByRole("heading", { name: "프로젝트 관리" })).toBeVisible(); await page.getByRole("button", { name: "프로젝트 생성" }).click(); const name = `E2E프로젝트-${stamp}`; await page.getByPlaceholder("예: CardioScan FDA 510(k)").fill(name); // 첫 번째 select = 업체: 첫 실제 항목 선택(생성 버튼 활성 조건) await page.locator(".fixed select").first().selectOption({ index: 1 }); await page.getByRole("button", { name: "생성", exact: true }).click(); await expect(page.getByRole("link", { name: new RegExp(name) })).toBeVisible(); }); test("검증: 프로젝트명 없으면 생성 비활성", async ({ page }) => { await page.goto("/admin/projects"); await page.getByRole("button", { name: "프로젝트 생성" }).click(); await expect(page.getByRole("button", { name: "생성", exact: true })).toBeDisabled(); }); }); test.describe("일반 구성원(?as=user)", () => { test("관리자 메뉴 숨김", async ({ page }) => { await page.goto("/?as=user"); await expect(page.getByText(/안녕하세요/)).toBeVisible(); await expect(page.getByRole("link", { name: "캘린더" })).toBeVisible(); await expect(page.getByRole("link", { name: "프로젝트 관리" })).toHaveCount(0); await expect(page.getByRole("link", { name: "회계" })).toHaveCount(0); await expect(page.getByRole("link", { name: "승인 관리" })).toHaveCount(0); }); test("관리자 라우트 접근 시 대시보드로 리다이렉트", async ({ page }) => { await page.goto("/admin/accounting?as=user"); await expect(page).toHaveURL(/\/$|\/\?/); // '/' 로 리다이렉트 await expect(page.getByText(/안녕하세요/)).toBeVisible(); }); test("내 프로필 접근", async ({ page }) => { await page.goto("/profile?as=user"); await expect(page.getByRole("heading", { name: "내 프로필" })).toBeVisible(); }); });