All checks were successful
build-and-push / build (push) Successful in 36s
- playwright.config.ts: 로컬 스택(5380/8380) 대상 headless chromium - e2e/spin.spec.ts: 대시보드·네비·쪽지함·캘린더 일정 생성·프로젝트 생성 모달·검증, 구성원 역할(관리자 메뉴 숨김·관리 라우트 리다이렉트·프로필) - e2e/project-flow.spec.ts: 프로젝트 상세 개요/작업자/메일 탭, 타임라인 작업 추가→상세 모달→칸반 카드 - e2e/member-domains.spec.ts: 근무·휴가 신청 검증, 인센티브 게이지, 대시보드 내 이슈 - ?as=user 로 역할 전환(api.ts 포워딩 활용), afterAll API 정리 - npm run test:e2e 스크립트, test-results/·playwright-report/ gitignore Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
103 lines
4.8 KiB
TypeScript
103 lines
4.8 KiB
TypeScript
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();
|
|
});
|
|
});
|