/** * 결재 템플릿 관리 및 결재함 E2E 테스트 * 실행: node scripts/run-e2e-test.js */ const { chromium } = require("playwright"); const BASE_URL = "http://localhost:9771"; const SCREENSHOT_DIR = ".agent-pipeline/browser-tests"; async function runTest() { const browser = await chromium.launch({ headless: true }); const context = await browser.newContext({ viewport: { width: 1280, height: 720 }, }); const page = await context.newPage(); const results = []; let allPassed = true; function pass(name) { results.push({ name, status: "PASS" }); console.log(`PASS: ${name}`); } function fail(name, reason) { results.push({ name, status: "FAIL", reason }); console.log(`FAIL: ${name} - ${reason}`); allPassed = false; } try { // 로그인 await page.goto(`${BASE_URL}/login`); await page.waitForLoadState("networkidle"); await page.getByPlaceholder("사용자 ID를 입력하세요").fill("wace"); await page.getByPlaceholder("비밀번호를 입력하세요").fill("qlalfqjsgh11"); await Promise.all([ page.waitForURL(url => !url.toString().includes("/login"), { timeout: 30000 }), page.getByRole("button", { name: "로그인" }).click(), ]); await page.waitForLoadState("networkidle"); pass("로그인"); // ========================================================= // 결재 템플릿 관리 페이지 // ========================================================= await page.goto(`${BASE_URL}/admin/approvalTemplate`); await page.waitForLoadState("domcontentloaded"); await page.waitForTimeout(3000); // 1. "결재 템플릿 관리" 제목 확인 try { await page.locator("h1").filter({ hasText: "결재 템플릿 관리" }).waitFor({ timeout: 10000 }); pass("결재 템플릿 관리 - 제목 확인"); } catch (e) { fail("결재 템플릿 관리 - 제목 확인", e.message); } // 2. "신규 등록" 버튼 확인 try { await page.getByRole("button", { name: "신규 등록" }).waitFor({ timeout: 10000 }); pass("결재 템플릿 관리 - 신규 등록 버튼 확인"); } catch (e) { fail("결재 템플릿 관리 - 신규 등록 버튼 확인", e.message); } // 3. 검색 입력란 확인 try { await page.getByPlaceholder("템플릿명 또는 설명 검색...").waitFor({ timeout: 10000 }); pass("결재 템플릿 관리 - 검색 입력란 확인"); } catch (e) { // placeholder가 다를 수 있으므로 input으로 재시도 try { await page.locator("input[type='text']").first().waitFor({ timeout: 5000 }); pass("결재 템플릿 관리 - 검색 입력란 확인 (input fallback)"); } catch (e2) { fail("결재 템플릿 관리 - 검색 입력란 확인", e.message); } } // 4. JS 에러 오버레이 확인 const hasError1 = await page.locator('[id="__next"] .nextjs-container-errors-body').isVisible().catch(() => false); if (!hasError1) { pass("결재 템플릿 관리 - JS 에러 없음"); } else { fail("결재 템플릿 관리 - JS 에러 없음", "에러 오버레이 감지됨"); } await page.screenshot({ path: `${SCREENSHOT_DIR}/result-template.png`, fullPage: true }); // ========================================================= // 결재함 페이지 // ========================================================= await page.goto(`${BASE_URL}/admin/approvalBox`); await page.waitForLoadState("domcontentloaded"); await page.waitForTimeout(3000); // 1. 탭 확인 try { await page.getByRole("tab", { name: /수신함/ }).waitFor({ timeout: 10000 }); pass("결재함 - 수신함 탭 확인"); } catch (e) { fail("결재함 - 수신함 탭 확인", e.message); } try { await page.getByRole("tab", { name: /상신함/ }).waitFor({ timeout: 10000 }); pass("결재함 - 상신함 탭 확인"); } catch (e) { fail("결재함 - 상신함 탭 확인", e.message); } // 2. JS 에러 오버레이 확인 const hasError2 = await page.locator('[id="__next"] .nextjs-container-errors-body').isVisible().catch(() => false); if (!hasError2) { pass("결재함 - JS 에러 없음"); } else { fail("결재함 - JS 에러 없음", "에러 오버레이 감지됨"); } await page.screenshot({ path: `${SCREENSHOT_DIR}/result-box.png`, fullPage: true }); } catch (e) { fail("테스트 실행", e.message); } finally { await browser.close(); } console.log("\n=== 테스트 결과 ==="); results.forEach(r => { const status = r.status === "PASS" ? "✓" : "✗"; console.log(`${status} ${r.name}${r.reason ? `: ${r.reason}` : ""}`); }); if (allPassed) { console.log("\nBROWSER_TEST_RESULT: PASS"); process.exit(0); } else { const failed = results.filter(r => r.status === "FAIL").map(r => r.name).join(", "); console.log(`\nBROWSER_TEST_RESULT: FAIL - ${failed}`); process.exit(1); } } runTest().catch(e => { console.error("치명적 오류:", e); console.log("BROWSER_TEST_RESULT: FAIL - 치명적 오류: " + e.message); process.exit(1); });