대시보드, GNB 추가
CI / test (push) Successful in 4m58s
CI / e2e (push) Has been skipped
CI / pr_and_merge (push) Successful in 1m45s

This commit is contained in:
2025-12-08 06:59:52 +09:00
parent b40be693ee
commit 9d8c4538c7
18 changed files with 1595 additions and 86 deletions
+140
View File
@@ -0,0 +1,140 @@
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: "로그인" })).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: "대시보드" })).toBeVisible();
// 상단 헤더 내비게이션이 보여야 한다.
const dashboardLink = page.getByRole("link", { name: "대시보드" });
await expect(dashboardLink).toBeVisible();
const projectsLink = page.getByRole("link", { name: "프로젝트 목록" });
await expect(projectsLink).toBeVisible();
const submissionsLink = page.getByRole("link", { name: "전체 제출 내역" });
await expect(submissionsLink).toBeVisible();
const menuButton = page.getByRole("button", { name: "메뉴" });
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: "로그아웃" })).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: "대시보드" })).toBeVisible();
});