164 lines
6.1 KiB
TypeScript
164 lines
6.1 KiB
TypeScript
/**
|
|
* 화면 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();
|