ERP-node/frontend/scripts/screen94-124-verification.ts

164 lines
6.1 KiB
TypeScript
Raw Normal View History

/**
* 94(), 124( )
* -
* - , //,
*/
import { chromium } from "playwright";
import * as path from "path";
import * as fs from "fs";
const BASE_URL = "http://localhost:9771";
const SCREENSHOT_DIR = path.join(__dirname, "../verification-screenshots");
interface ScreenResult {
screenId: number;
name: string;
componentsOk: boolean;
tableVisible: boolean;
filterVisible: boolean;
buttonsVisible: boolean;
layoutHorizontal: boolean;
noError: boolean;
success: boolean;
}
type ScreenType = "form" | "list";
async function verifyScreen(page: any, screenId: number, name: string, type: ScreenType): Promise<ScreenResult> {
console.log(`\n--- 화면 ${screenId} (${name}) 검증 ---`);
await page.goto(`${BASE_URL}/screens/${screenId}`, { waitUntil: "domcontentloaded", timeout: 20000 });
// 로딩 완료 대기: "로딩중" 텍스트 사라질 때까지 최대 12초
await page.getByText("로딩중", { exact: false }).waitFor({ state: "hidden", timeout: 12000 }).catch(() => {});
// 리스트 화면: 테이블 로딩 대기. 폼 화면: 버튼/input 대기
if (type === "list") {
await page.waitForSelector("table, [role='grid'], thead, tbody", { timeout: 8000 }).catch(() => {});
} else {
await page.waitForSelector("button, input", { timeout: 5000 }).catch(() => {});
}
await page.waitForTimeout(2000);
const result: ScreenResult = {
screenId,
name,
componentsOk: false,
tableVisible: false,
filterVisible: false,
buttonsVisible: false,
layoutHorizontal: false,
noError: false,
success: false,
};
// 404/에러 메시지 확인
const has404 = (await page.locator('text="화면을 찾을 수 없습니다"').count()) > 0;
const hasError = (await page.locator('text="오류 발생"').count()) > 0;
result.noError = !has404;
// 테이블
const tableSelectors = ["table", "[role='grid']", "thead", "tbody", ".table-mobile-fixed"];
for (const sel of tableSelectors) {
if ((await page.locator(sel).count()) > 0) {
result.tableVisible = true;
break;
}
}
// 필터/검색
const filterSelectors = ["input", "select", "button:has-text('검색')", "button:has-text('필터')"];
for (const sel of filterSelectors) {
if ((await page.locator(sel).count()) > 0) {
result.filterVisible = true;
break;
}
}
// 버튼 (사이드바 포함, 화면에 버튼이 있으면 OK)
const buttonCount = await page.locator("button, [role='button']").count();
result.buttonsVisible = buttonCount > 0;
// 가로 레이아웃: 사이드바+메인 구조, flex/grid, 또는 테이블이 있으면 가로 배치로 간주
const hasFlexRow = (await page.locator(".flex-row, .md\\:flex-row, .flex").count()) > 0;
const hasGrid = (await page.locator(".grid, [class*='grid-cols']").count()) > 0;
const hasMain = (await page.locator("main, [role='main'], .flex-1, [class*='flex-1']").count()) > 0;
const hasSidebar = (await page.getByText("현재 관리 회사").count()) > 0 || (await page.getByText("VEXPLOR").count()) > 0;
result.layoutHorizontal = (hasMain && (hasFlexRow || hasGrid || result.tableVisible)) || hasSidebar;
// 컴포넌트 정상 배치 (테이블, 버튼, 또는 input/필터 중 하나라도 있으면 OK)
result.componentsOk = result.tableVisible || result.buttonsVisible || result.filterVisible;
// 성공: 폼 화면은 테이블 불필요, 리스트 화면은 테이블 필수
const baseOk = result.componentsOk && result.filterVisible && result.buttonsVisible && result.layoutHorizontal && result.noError;
result.success = type === "form" ? baseOk : baseOk && result.tableVisible;
return result;
}
async function main() {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ viewport: { width: 1280, height: 900 } });
const page = await context.newPage();
const results: ScreenResult[] = [];
try {
// 로그인 (Playwright는 새 브라우저이므로)
console.log("로그인...");
await page.goto(`${BASE_URL}/login`, { waitUntil: "domcontentloaded", timeout: 15000 });
await page.waitForTimeout(1000);
await page.fill("#userId", "wace");
await page.fill("#password", "qlalfqjsgh11");
await page.locator('button[type="submit"]').first().click();
await page.waitForURL((url) => !url.includes("/login"), { timeout: 15000 }).catch(() => {});
await page.waitForTimeout(3000);
// 화면 94
await page.screenshot({
path: path.join(SCREENSHOT_DIR, "s94-01-before.png"),
fullPage: true,
});
const r94 = await verifyScreen(page, 94, "수주", "form");
results.push(r94);
await page.screenshot({
path: path.join(SCREENSHOT_DIR, "s94-02-after.png"),
fullPage: true,
});
// 화면 124
await page.screenshot({
path: path.join(SCREENSHOT_DIR, "s124-01-before.png"),
fullPage: true,
});
const r124 = await verifyScreen(page, 124, "수주목록 리스트", "list");
results.push(r124);
await page.screenshot({
path: path.join(SCREENSHOT_DIR, "s124-02-after.png"),
fullPage: true,
});
// 결과 출력
console.log("\n=== 검증 결과 ===");
results.forEach((r) => {
console.log(
`화면 ${r.screenId} (${r.name}): ${r.success ? "성공" : "실패"}` +
` | 테이블:${r.tableVisible ? "O" : "X"} 필터:${r.filterVisible ? "O" : "X"} 버튼:${r.buttonsVisible ? "O" : "X"} 레이아웃:${r.layoutHorizontal ? "O" : "X"} 에러없음:${r.noError ? "O" : "X"}`
);
});
const allSuccess = results.every((r) => r.success);
console.log(`\n최종 판정: ${allSuccess ? "성공" : "실패"}`);
fs.writeFileSync(
path.join(SCREENSHOT_DIR, "s94-124-result.json"),
JSON.stringify({ results, finalSuccess: allSuccess ? "성공" : "실패" }, null, 2)
);
} catch (error: any) {
console.error("오류:", error.message);
await page.screenshot({ path: path.join(SCREENSHOT_DIR, "s94-124-error.png"), fullPage: true }).catch(() => {});
} finally {
await browser.close();
}
}
main();