/** * 화면 1053, 156 버튼 위치 검증 * 1053: overlay buttons within split panel * 156: buttons in separate row above table */ 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"); 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 report: Record = { screen1053: {}, screen156: {} }; try { await page.goto(`${BASE_URL}/login`, { waitUntil: "domcontentloaded", timeout: 60000 }); await page.waitForTimeout(2000); await page.fill("#userId", "wace"); await page.fill("#password", "qlalfqjsgh11"); await page.locator('button[type="submit"]').first().click(); await page.waitForURL((u: URL) => !u.includes("/login"), { timeout: 20000 }).catch(() => {}); await page.waitForTimeout(3000); await page.goto(`${BASE_URL}/screens/156`, { waitUntil: "domcontentloaded", timeout: 45000 }); await page.waitForTimeout(2000); if (page.url().includes("/login")) { await page.fill("#userId", "wace"); await page.fill("#password", "qlalfqjsgh11"); await page.locator('button[type="submit"]').first().click(); await page.waitForURL((u: URL) => !u.includes("/login"), { timeout: 20000 }).catch(() => {}); await page.waitForTimeout(3000); } // Screen 1053 await page.goto(`${BASE_URL}/screens/1053?menuObjid=1762421920304`, { waitUntil: "domcontentloaded", timeout: 60000 }); await page.waitForTimeout(3000); if (page.url().includes("/login")) { await page.fill("#userId", "wace"); await page.fill("#password", "qlalfqjsgh11"); await page.locator('button[type="submit"]').first().click(); await page.waitForURL((u: URL) => !u.includes("/login"), { timeout: 25000 }).catch(() => {}); await page.waitForTimeout(5000); await page.goto(`${BASE_URL}/screens/1053?menuObjid=1762421920304`, { waitUntil: "domcontentloaded", timeout: 60000 }); await page.waitForTimeout(3000); } await page.getByText("화면을 불러오는 중", { exact: false }).waitFor({ state: "hidden", timeout: 35000 }).catch(() => {}); await page.waitForTimeout(40000); const splitPanelEl = page.locator("[class*='border-r'], [class*='split']").first(); await splitPanelEl.waitFor({ state: "visible", timeout: 15000 }).catch(() => {}); await page.waitForTimeout(3000); const info1053 = await page.evaluate(() => { const splitPanel = document.querySelector("[class*='border-r']") || document.querySelector("main"); const mainContent = document.querySelector("main") || document.body; const allBtns = Array.from(document.querySelectorAll("button")); const buttons = allBtns.filter((b) => { const t = (b as HTMLElement).innerText?.trim() || ""; const r = (b as HTMLElement).getBoundingClientRect(); return t.length > 1 && r.x > 250 && t.match(/등록|수정|삭제|품목|테이블|결재|수주|출하/); }); const splitRect = splitPanel ? (splitPanel as HTMLElement).getBoundingClientRect() : null; const mainRect = mainContent ? (mainContent as HTMLElement).getBoundingClientRect() : null; const buttonPositions = buttons.map((b) => { const r = (b as HTMLElement).getBoundingClientRect(); const text = (b as HTMLElement).innerText?.trim().substring(0, 20); return { text, x: r.x, y: r.y, right: r.right, width: r.width, height: r.height, isWithinSplitPanel: splitRect ? r.y >= splitRect.top - 20 && r.y <= splitRect.bottom + 20 : null, isAboveMain: mainRect ? r.y < mainRect.top + 100 : null, }; }); const table = document.querySelector("table"); const tableRect = table ? (table as HTMLElement).getBoundingClientRect() : null; const buttonsAboveTable = buttonPositions.every((p) => tableRect && p.y < tableRect.top - 10); return { splitPanelVisible: !!splitPanel, splitPanelRect: splitRect ? { top: splitRect.top, bottom: splitRect.bottom, left: splitRect.left, right: splitRect.right } : null, mainRect: mainRect ? { top: mainRect.top, bottom: mainRect.bottom } : null, buttonCount: buttons.length, buttonPositions, buttonsOverlaidOnSplitPanel: buttonPositions.some((p) => p.isWithinSplitPanel), buttonsInSeparateRowAbove: buttonsAboveTable, tableTop: tableRect?.top ?? null, }; }); report.screen1053 = info1053; await page.screenshot({ path: path.join(SCREENSHOT_DIR, "overlay-1053.png"), fullPage: true }); console.log("overlay-1053.png saved"); // Screen 156 await page.goto(`${BASE_URL}/screens/156?menuObjid=1762421920156`, { waitUntil: "domcontentloaded", timeout: 45000 }); await page.waitForTimeout(3000); await page.getByText("화면을 불러오는 중", { exact: false }).waitFor({ state: "hidden", timeout: 35000 }).catch(() => {}); await page.waitForTimeout(40000); const table156 = page.locator("table tbody tr").first(); await table156.waitFor({ state: "visible", timeout: 15000 }).catch(() => {}); await page.waitForTimeout(3000); const info156 = await page.evaluate(() => { const table = document.querySelector("table"); const tableRect = table ? (table as HTMLElement).getBoundingClientRect() : null; const buttons = Array.from(document.querySelectorAll("button")).filter( (b) => ((b as HTMLElement).innerText?.trim() || "").match(/결재|수주|수정|삭제|출하|테이블/) ); const buttonPositions = buttons.map((b) => { const r = (b as HTMLElement).getBoundingClientRect(); const text = (b as HTMLElement).innerText?.trim().substring(0, 20); return { text, x: r.x, y: r.y, right: r.right, width: r.width, isAboveTable: tableRect ? r.y < tableRect.top - 5 : null, }; }); const allButtonsAboveTable = buttonPositions.every((p) => p.isAboveTable); return { tableVisible: !!table, tableTop: tableRect?.top ?? null, buttonCount: buttons.length, buttonPositions, buttonsInSeparateRowAboveTable: allButtonsAboveTable, }; }); report.screen156 = info156; await page.screenshot({ path: path.join(SCREENSHOT_DIR, "overlay-156.png"), fullPage: true }); console.log("overlay-156.png saved"); fs.writeFileSync( path.join(SCREENSHOT_DIR, "overlay-report.json"), JSON.stringify(report, null, 2) ); console.log("\n=== Report ==="); console.log(JSON.stringify(report, null, 2)); } catch (error: any) { console.error("Error:", error.message); report.error = error.message; await page.screenshot({ path: path.join(SCREENSHOT_DIR, "overlay-error.png"), fullPage: true }).catch(() => {}); } finally { await browser.close(); } } main();