마이페이지, 리포트, 메일인증
This commit is contained in:
@@ -81,7 +81,7 @@ test("회원가입 후에는 /dashboard, /editor, /preview 에 정상 접근할
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-1", email, tokenVersion: 1 }),
|
||||
body: JSON.stringify({ id: "user-1", email, tokenVersion: 1, emailVerified: false }),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -105,6 +105,11 @@ test("회원가입 후에는 /dashboard, /editor, /preview 에 정상 접근할
|
||||
await expect(page).toHaveURL(/\/dashboard/);
|
||||
await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible();
|
||||
|
||||
// 이메일 인증 안내 배너가 보여야 한다.
|
||||
await expect(
|
||||
page.getByText(/Your email is not verified yet\./i),
|
||||
).toBeVisible();
|
||||
|
||||
// 2) /editor 접근 확인 – 로그인 페이지로 리다이렉트되면 안 된다.
|
||||
await page.goto("/editor");
|
||||
await expect(page.getByRole("heading", { name: "Page Editor" })).toBeVisible();
|
||||
|
||||
@@ -115,6 +115,43 @@ test("로그인 사용자가 /dashboard 에 접근하면 요약 지표와 프로
|
||||
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({
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
// 마이페이지(/mypage) E2E
|
||||
// - 비로그인 사용자는 /login 으로 리다이렉트되어야 한다.
|
||||
// - 로그인 사용자는 My page 헤더와 프로필/계정 관리 섹션을 볼 수 있어야 한다.
|
||||
// - 로그인 사용자는 마이페이지에서 이메일 인증 메일을 보낼 수 있어야 한다.
|
||||
|
||||
test("비로그인 사용자가 /mypage 에 접근하면 /login 으로 리다이렉트되어야 한다", async ({ page }) => {
|
||||
// /api/auth/me 를 401 로 목 처리해 비로그인 상태를 시뮬레이션한다.
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 401,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ message: "인증이 필요합니다." }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/mypage");
|
||||
|
||||
await expect(page).toHaveURL(/\/login/);
|
||||
await expect(page.getByRole("heading", { name: "Log in" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("로그인 사용자가 /mypage 에 접근하면 My page 헤더와 프로필/계정 관리 섹션이 보여야 한다", async ({ page }) => {
|
||||
const email = `mypage+${Date.now()}@example.com`;
|
||||
|
||||
// 로그인된 상태를 시뮬레이션하기 위해 /api/auth/me 를 200 으로 목 처리한다.
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-mypage", email, tokenVersion: 1 }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/mypage");
|
||||
|
||||
// 마이페이지 헤더와 기본 섹션들이 보여야 한다.
|
||||
await expect(page.getByRole("heading", { name: "My page" })).toBeVisible();
|
||||
await expect(page.getByText(email)).toBeVisible();
|
||||
|
||||
// 비밀번호/이메일 변경 섹션의 기본 라벨이 존재하는지만 확인한다.
|
||||
await expect(page.getByText(/Change password/i)).toBeVisible();
|
||||
await expect(page.getByText(/Change email/i)).toBeVisible();
|
||||
});
|
||||
|
||||
test("마이페이지 헤더에서 대시보드로 이동할 수 있어야 한다", async ({ page }) => {
|
||||
const email = `mypage-nav+${Date.now()}@example.com`;
|
||||
|
||||
// /api/auth/me 를 200 으로 목 처리해 로그인 상태를 시뮬레이션한다.
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-mypage-nav", email, tokenVersion: 1, emailVerified: true }),
|
||||
});
|
||||
});
|
||||
|
||||
// 대시보드 개요 API 를 목 처리해 /dashboard 진입 시 데이터를 안정적으로 반환한다.
|
||||
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.goto("/mypage");
|
||||
|
||||
const toDashboard = page.getByRole("link", { name: "Go to dashboard" });
|
||||
await expect(toDashboard).toBeVisible();
|
||||
|
||||
await toDashboard.click();
|
||||
|
||||
await expect(page).toHaveURL(/\/dashboard/);
|
||||
await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("로그인 사용자는 마이페이지에서 이메일 인증 메일을 보낼 수 있어야 한다", async ({ page }) => {
|
||||
const email = `verify+${Date.now()}@example.com`;
|
||||
|
||||
// 로그인된 상태를 시뮬레이션하기 위해 /api/auth/me 를 200 으로 목 처리한다.
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-verify", email, tokenVersion: 1 }),
|
||||
});
|
||||
});
|
||||
|
||||
// 이메일 인증 메일 전송 API 를 목 처리해 성공 응답을 시뮬레이션한다.
|
||||
await page.route("**/api/auth/request-email-verification", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
message: "Verification email has been sent.",
|
||||
verificationToken: "dummy-token",
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/mypage");
|
||||
|
||||
// 이메일 인증 안내 텍스트와 버튼이 보여야 한다.
|
||||
await expect(
|
||||
page.getByText(/If your email is not verified yet, you can send a verification email from here\./i),
|
||||
).toBeVisible();
|
||||
|
||||
const button = page.getByRole("button", { name: "Send verification email" });
|
||||
await expect(button).toBeVisible();
|
||||
|
||||
await button.click();
|
||||
|
||||
// 성공 메시지가 노출되어야 한다.
|
||||
await expect(page.getByText(/Verification email has been sent\./i)).toBeVisible();
|
||||
});
|
||||
@@ -227,6 +227,55 @@ test("프로젝트 목록에서 '폼 제출 내역' 링크를 클릭하면 해
|
||||
await expect(page.getByText("message: 안녕하세요")).toBeVisible();
|
||||
});
|
||||
|
||||
test("이메일 미인증 사용자는 프로젝트 목록에서 퍼블릭 페이지 열기 링크를 볼 수 없어야 한다", async ({ page }) => {
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-unverified", email: "unverified@example.com", tokenVersion: 1, emailVerified: false }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/projects", async (route) => {
|
||||
const request = route.request();
|
||||
const url = new URL(request.url());
|
||||
const method = request.method();
|
||||
|
||||
if (url.pathname === "/api/projects" && method === "GET") {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify([
|
||||
{
|
||||
id: "1",
|
||||
title: "테스트 프로젝트 A",
|
||||
slug: "test-project-a",
|
||||
status: "DRAFT",
|
||||
createdAt: new Date("2025-01-01T00:00:00.000Z").toISOString(),
|
||||
updatedAt: new Date("2025-01-01T00:00:00.000Z").toISOString(),
|
||||
},
|
||||
]),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await route.fulfill({
|
||||
status: 404,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ message: "Not implemented in E2E mock" }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/projects");
|
||||
|
||||
// 프로젝트 행은 보여야 한다.
|
||||
await expect(page.getByText("테스트 프로젝트 A")).toBeVisible();
|
||||
await expect(page.getByText("test-project-a")).toBeVisible();
|
||||
|
||||
// 이메일 미인증 상태에서는 'Open public page' 링크가 보이지 않아야 한다.
|
||||
await expect(page.getByRole("link", { name: "Open public page" })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("프로젝트 목록 헤더에서 대시보드로 이동할 수 있어야 한다", async ({ page }) => {
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
@@ -329,3 +378,31 @@ test("전체 제출 내역 페이지에서 공통 GNB와 메뉴가 보여야 한
|
||||
await menuButton.click();
|
||||
await expect(page.getByRole("button", { name: "Log out" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("Projects GNB 메뉴에서 My page 로 이동할 수 있어야 한다", async ({ page }) => {
|
||||
await page.route("**/api/projects", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify([]),
|
||||
});
|
||||
});
|
||||
|
||||
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("/projects");
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
// 리포트 페이지(/reports) E2E
|
||||
// - 로그인 사용자는 GNB 의 Reports 탭을 통해 /reports 로 이동할 수 있어야 한다.
|
||||
// - /reports 에서는 필터/요약 카드/그래프/프로젝트별 테이블 컨테이너가 렌더링되어야 한다.
|
||||
|
||||
test("로그인 사용자가 GNB Reports 탭을 통해 /reports 에 접근할 수 있어야 한다", async ({ page }) => {
|
||||
const email = `reports+${Date.now()}@example.com`;
|
||||
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-reports", email, tokenVersion: 1, emailVerified: true }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/projects", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify([
|
||||
{
|
||||
id: "p1",
|
||||
title: "Project A",
|
||||
slug: "project-a",
|
||||
status: "PUBLISHED",
|
||||
createdAt: "2025-01-01T00:00:00.000Z",
|
||||
updatedAt: "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/projects", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify([
|
||||
{
|
||||
id: "p1",
|
||||
title: "Project A",
|
||||
slug: "project-a",
|
||||
status: "PUBLISHED",
|
||||
createdAt: "2025-01-01T00:00:00.000Z",
|
||||
updatedAt: "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: "p2",
|
||||
title: "Project B",
|
||||
slug: "project-b",
|
||||
status: "DRAFT",
|
||||
createdAt: "2025-01-02T00:00:00.000Z",
|
||||
updatedAt: "2025-01-02T00:00:00.000Z",
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
// 대시보드 개요 API 를 목 처리해 /dashboard 진입 시 401/리다이렉트가 발생하지 않도록 한다.
|
||||
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/projects", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify([
|
||||
{
|
||||
id: "p1",
|
||||
title: "Project A",
|
||||
slug: "project-a",
|
||||
status: "PUBLISHED",
|
||||
createdAt: "2025-01-01T00:00:00.000Z",
|
||||
updatedAt: "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: "p2",
|
||||
title: "Project B",
|
||||
slug: "project-b",
|
||||
status: "DRAFT",
|
||||
createdAt: "2025-01-02T00:00:00.000Z",
|
||||
updatedAt: "2025-01-02T00:00:00.000Z",
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/reports/leads*", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ total: 0, items: [] }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/reports/overview*", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
summary: {
|
||||
totalSubmissions: 3,
|
||||
uniqueProjects: 2,
|
||||
avgPerDay: 1,
|
||||
},
|
||||
daily: [
|
||||
{ date: "2025-01-01", count: 1 },
|
||||
{ date: "2025-01-02", count: 2 },
|
||||
],
|
||||
byProject: [
|
||||
{ projectId: "p1", title: "Project A", slug: "project-a", submissions: 2, ratio: 2 / 3 },
|
||||
{ projectId: "p2", title: "Project B", slug: "project-b", submissions: 1, ratio: 1 / 3 },
|
||||
],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/dashboard");
|
||||
|
||||
const reportsTab = page.getByRole("link", { name: "Reports" });
|
||||
await expect(reportsTab).toBeVisible();
|
||||
|
||||
await reportsTab.click();
|
||||
|
||||
await expect(page).toHaveURL(/\/reports/);
|
||||
await expect(page.getByRole("heading", { name: "Reports" })).toBeVisible();
|
||||
|
||||
await expect(page.getByTestId("reports-summary-total-submissions")).toContainText("3");
|
||||
await expect(page.getByTestId("reports-daily-chart")).toBeVisible();
|
||||
await expect(page.getByTestId("reports-by-project-table")).toBeVisible();
|
||||
});
|
||||
|
||||
test("/reports 에서는 기간/프로젝트 필터와 기본 리포트 섹션이 렌더링되어야 한다", async ({ page }) => {
|
||||
const email = `reports2+${Date.now()}@example.com`;
|
||||
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-reports2", email, tokenVersion: 1, emailVerified: true }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/reports/overview*", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
summary: {
|
||||
totalSubmissions: 0,
|
||||
uniqueProjects: 0,
|
||||
avgPerDay: 0,
|
||||
},
|
||||
daily: [],
|
||||
byProject: [],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/reports");
|
||||
|
||||
await expect(page.getByRole("heading", { name: "Reports" })).toBeVisible();
|
||||
|
||||
// 기간/프로젝트 필터 컨트롤이 존재해야 한다.
|
||||
await expect(page.getByTestId("reports-filter-range-toggle")).toBeVisible();
|
||||
await expect(page.getByTestId("reports-filter-project")).toBeVisible();
|
||||
|
||||
// 요약/그래프/테이블 컨테이너가 렌더링되어야 한다.
|
||||
await expect(page.getByTestId("reports-summary-total-submissions")).toBeVisible();
|
||||
await expect(page.getByTestId("reports-daily-chart")).toBeVisible();
|
||||
await expect(page.getByTestId("reports-by-project-table")).toBeVisible();
|
||||
});
|
||||
|
||||
test("/reports 에서는 시간 패턴과 프로젝트 상태 요약 섹션도 함께 볼 수 있어야 한다", async ({ page }) => {
|
||||
const email = `reports3+${Date.now()}@example.com`;
|
||||
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-reports3", email, tokenVersion: 1, emailVerified: true }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/reports/overview*", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
summary: {
|
||||
totalSubmissions: 3,
|
||||
uniqueProjects: 2,
|
||||
avgPerDay: 1.5,
|
||||
},
|
||||
daily: [
|
||||
{ date: "2025-01-01", count: 1 },
|
||||
{ date: "2025-01-02", count: 2 },
|
||||
],
|
||||
byProject: [
|
||||
{ projectId: "p1", title: "Project A", slug: "project-a", submissions: 2, ratio: 2 / 3 },
|
||||
{ projectId: "p2", title: "Project B", slug: "project-b", submissions: 1, ratio: 1 / 3 },
|
||||
],
|
||||
timePatterns: {
|
||||
byWeek: [{ week: "2025-W01", count: 3 }],
|
||||
byMonth: [{ month: "2025-01", count: 3 }],
|
||||
byWeekday: [
|
||||
{ weekday: 1, count: 1 },
|
||||
{ weekday: 2, count: 2 },
|
||||
],
|
||||
byHour: [
|
||||
{ hour: 9, count: 1 },
|
||||
{ hour: 15, count: 2 },
|
||||
],
|
||||
},
|
||||
projectStatusSummary: {
|
||||
byStatus: [
|
||||
{ status: "PUBLISHED", projects: 1, submissions: 2 },
|
||||
{ status: "DRAFT", projects: 1, submissions: 1 },
|
||||
],
|
||||
},
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/reports");
|
||||
|
||||
await expect(page.getByRole("heading", { name: "Reports" })).toBeVisible();
|
||||
|
||||
await expect(page.getByTestId("reports-time-patterns")).toBeVisible();
|
||||
await expect(page.getByTestId("reports-project-status-summary")).toBeVisible();
|
||||
});
|
||||
|
||||
test("/reports 에서는 Leads 요약과 리드 리스트 테이블이 렌더링되어야 한다", async ({ page }) => {
|
||||
const email = `reports-leads+${Date.now()}@example.com`;
|
||||
|
||||
await page.route("**/api/auth/me", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: "user-reports-leads", email, tokenVersion: 1, emailVerified: true }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/reports/overview*", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
summary: {
|
||||
totalSubmissions: 3,
|
||||
uniqueProjects: 2,
|
||||
avgPerDay: 1.5,
|
||||
},
|
||||
daily: [],
|
||||
byProject: [],
|
||||
timePatterns: {
|
||||
byWeek: [],
|
||||
byMonth: [],
|
||||
byWeekday: [],
|
||||
byHour: [],
|
||||
},
|
||||
projectStatusSummary: { byStatus: [] },
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/api/reports/leads*", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
total: 2,
|
||||
items: [
|
||||
{
|
||||
id: "s1",
|
||||
projectId: "p1",
|
||||
projectSlug: "project-a",
|
||||
projectTitle: "Project A",
|
||||
createdAt: "2025-01-09T12:00:00.000Z",
|
||||
payload: { name: "Alice", email: "alice@example.com" },
|
||||
},
|
||||
{
|
||||
id: "s2",
|
||||
projectId: "p2",
|
||||
projectSlug: "project-b",
|
||||
projectTitle: "Project B",
|
||||
createdAt: "2025-01-08T09:00:00.000Z",
|
||||
payload: { name: "Bob" },
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/reports");
|
||||
|
||||
await expect(page.getByRole("heading", { name: "Reports" })).toBeVisible();
|
||||
|
||||
const leadsSection = page.getByTestId("reports-leads-table");
|
||||
await expect(leadsSection).toBeVisible();
|
||||
|
||||
// 요약 텍스트에 total 값이 반영되어야 한다.
|
||||
await expect(page.getByTestId("reports-leads-summary")).toContainText("2");
|
||||
|
||||
// 테이블 행이 두 개 렌더링되는지만 간단히 확인.
|
||||
await expect(leadsSection.getByRole("row")).toHaveCount(1 + 2); // 헤더 1 + 데이터 2
|
||||
});
|
||||
Reference in New Issue
Block a user