import { test, expect } from "@playwright/test"; // 대시보드 E2E TDD // - 비로그인 사용자는 /dashboard 접근 시 /login 으로 리다이렉트되어야 한다. // - 로그인 사용자는 /dashboard 에서 요약 지표 + 프로젝트 카드 리스트를 볼 수 있어야 한다. // - 백엔드/DB 에 의존하지 않도록 /api/dashboard/overview 를 Playwright 라우팅으로 목킹한다. test("비로그인 사용자가 /dashboard 에 접근하면 /login 으로 리다이렉트되어야 한다", async ({ page }) => { await page.route("**/api/dashboard/overview", async (route) => { await route.fulfill({ status: 401, contentType: "application/json", body: JSON.stringify({ message: "로그인이 필요합니다." }), }); }); await page.goto("/dashboard"); await expect(page.getByRole("heading", { name: "Log in" })).toBeVisible(); }); test("로그인 사용자가 /dashboard 에 접근하면 요약 지표와 프로젝트 카드 리스트, 일별 그래프를 볼 수 있어야 한다", async ({ page }) => { await page.route("**/api/dashboard/overview", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ summaryStats: { totalProjects: 2, totalSubmissions: 3, todaySubmissions: 1, last7DaysSubmissions: 3, }, projectStats: [ { projectId: "proj-1", title: "테스트 프로젝트 A", slug: "test-project-a", status: "DRAFT", totalSubmissions: 2, lastSubmissionAt: "2025-01-02T12:00:00.000Z", }, { projectId: "proj-2", title: "테스트 프로젝트 B", slug: "test-project-b", status: "PUBLISHED", totalSubmissions: 1, lastSubmissionAt: "2025-01-03T09:30:00.000Z", }, ], dailySubmissions: [ { date: "2024-12-26", count: 1 }, { date: "2025-01-02", count: 1 }, { date: "2025-01-03", count: 1 }, ], }), }); }); await page.goto("/dashboard"); // 대시보드 헤더가 보여야 한다. await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible(); // 상단 헤더 내비게이션이 보여야 한다. const dashboardLink = page.getByRole("link", { name: "Dashboard" }); await expect(dashboardLink).toBeVisible(); const projectsLink = page.getByRole("link", { name: "Projects" }); await expect(projectsLink).toBeVisible(); const submissionsLink = page.getByRole("link", { name: "All submissions" }); await expect(submissionsLink).toBeVisible(); const menuButton = page.getByRole("button", { name: "Menu" }); await expect(menuButton).toBeVisible(); // 상단 요약 위젯의 지표들이 기대 값으로 렌더되어야 한다. const totalProjects = page.getByTestId("dashboard-summary-total-projects"); await expect(totalProjects).toContainText("2"); const totalSubmissions = page.getByTestId("dashboard-summary-total-submissions"); await expect(totalSubmissions).toContainText("3"); const todaySubmissions = page.getByTestId("dashboard-summary-today-submissions"); await expect(todaySubmissions).toContainText("1"); const last7DaysSubmissions = page.getByTestId( "dashboard-summary-last7days-submissions", ); await expect(last7DaysSubmissions).toContainText("3"); // 프로젝트 카드 리스트가 2개 렌더링되어야 한다. const projectCards = page.getByTestId("dashboard-project-card"); await expect(projectCards).toHaveCount(2); await expect(projectCards.nth(0)).toContainText("테스트 프로젝트 A"); await expect(projectCards.nth(0)).toContainText("test-project-a"); await expect(projectCards.nth(0)).toContainText("2"); await expect(projectCards.nth(1)).toContainText("테스트 프로젝트 B"); await expect(projectCards.nth(1)).toContainText("test-project-b"); await expect(projectCards.nth(1)).toContainText("1"); // 일별 제출 수 그래프가 렌더링되어야 한다. const dailyChart = page.getByTestId("dashboard-daily-chart"); await expect(dailyChart).toBeVisible(); const dailyBars = page.getByTestId("dashboard-daily-chart-bar"); await expect(dailyBars).toHaveCount(3); // 메뉴 버튼을 클릭하면 로그아웃 항목이 보여야 한다. await menuButton.click(); await expect(page.getByRole("button", { name: "Log out" })).toBeVisible(); }); test("대시보드 헤더 메뉴에서 My page 로 이동할 수 있어야 한다", async ({ page }) => { await page.route("**/api/dashboard/overview", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ summaryStats: { totalProjects: 0, totalSubmissions: 0, todaySubmissions: 0, last7DaysSubmissions: 0, }, projectStats: [], dailySubmissions: [], }), }); }); await page.route("**/api/auth/me", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ id: "user-mypage", email: "mypage@example.com", tokenVersion: 1 }), }); }); await page.goto("/dashboard"); const menuButton = page.getByRole("button", { name: "Menu" }); await menuButton.click(); await page.getByRole("button", { name: "My page" }).click(); await expect(page).toHaveURL(/\/mypage/); await expect(page.getByRole("heading", { name: "My page" })).toBeVisible(); }); test("로그인 사용자가 / 에 접속하면 대시보드로 진입해야 한다", async ({ page }) => { await page.route("**/api/dashboard/overview", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ summaryStats: { totalProjects: 1, totalSubmissions: 0, todaySubmissions: 0, last7DaysSubmissions: 0, }, projectStats: [], dailySubmissions: [], }), }); }); await page.goto("/"); await expect(page).toHaveURL(/\/dashboard/); await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible(); });