/** * 화면 150 검증 - 탑씰 영업 거래처관리 */ 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 = {}; try { await page.goto(`${BASE_URL}/login`, { waitUntil: "load", timeout: 90000 }); await page.waitForTimeout(2000); await page.fill("#userId", "admin"); await page.fill("#password", "1234"); await page.locator('button[type="submit"]').first().click(); await page.waitForURL((u: URL) => !u.includes("/login"), { timeout: 20000 }).catch(() => {}); 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: 20000 }).catch(() => {}); await page.waitForTimeout(3000); } const companyBtn = page.getByText("회사 선택").first(); if ((await companyBtn.count()) > 0) { const currentCompany = await page.getByText("현재 관리 회사").locator("..").textContent().catch(() => ""); if (!currentCompany?.includes("탑씰") && !currentCompany?.includes("COMPANY_7")) { await companyBtn.click(); await page.waitForTimeout(1500); const tapseal = page.getByText("탑씰", { exact: true }).first(); const company7 = page.getByText("COMPANY_7", { exact: true }).first(); if ((await tapseal.count()) > 0) { await tapseal.click(); } else if ((await company7.count()) > 0) { await company7.click(); } await page.waitForTimeout(2000); } } await page.goto(`${BASE_URL}/screens/150`, { 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: 20000 }).catch(() => {}); await page.waitForTimeout(3000); await page.goto(`${BASE_URL}/screens/150`, { waitUntil: "domcontentloaded", timeout: 60000 }); await page.waitForTimeout(3000); } await page.getByText("화면을 불러오는 중", { exact: false }).waitFor({ state: "hidden", timeout: 25000 }).catch(() => {}); await page.waitForTimeout(8000); const info = await page.evaluate(() => { const buttons = Array.from(document.querySelectorAll("button")).filter((b) => { const t = (b as HTMLElement).innerText?.trim() || ""; const r = (b as HTMLElement).getBoundingClientRect(); return t.length > 1 && r.x > 250 && r.width > 0; }); const viewportWidth = window.innerWidth; const leftThird = viewportWidth * 0.33; const rightThird = viewportWidth * 0.66; const btnDetails = buttons.map((b) => { const r = (b as HTMLElement).getBoundingClientRect(); const text = (b as HTMLElement).innerText?.trim().substring(0, 40); let group = "center"; if (r.x < leftThird) group = "left"; else if (r.x > rightThird) group = "right"; return { text, x: Math.round(r.x), y: Math.round(r.y), width: Math.round(r.width), height: Math.round(r.height), right: Math.round(r.right), group, }; }); const leftPanel = document.querySelector("[class*='border-r']"); const tables = document.querySelectorAll("table"); const rightPanel = document.querySelector("main")?.querySelectorAll("[class*='overflow'], [style*='overflow']"); const leftRect = leftPanel ? (leftPanel as HTMLElement).getBoundingClientRect() : null; const mainRect = document.querySelector("main")?.getBoundingClientRect(); const contentWidth = mainRect ? mainRect.width : viewportWidth; const leftWidthPercent = leftRect && contentWidth > 0 ? (leftRect.width / contentWidth) * 100 : null; let overlaps = false; for (let i = 0; i < btnDetails.length; i++) { for (let j = i + 1; j < btnDetails.length; j++) { const a = btnDetails[i]; const b = btnDetails[j]; if (Math.abs(a.y - b.y) < 30 && !(a.right < b.x || b.right < a.x)) overlaps = true; } } const rightTable = tables.length > 1 ? tables[1] : tables[0]; const rightTableRect = rightTable ? (rightTable as HTMLElement).getBoundingClientRect() : null; const rightTableScrollable = rightTable ? (() => { let el: Element | null = rightTable; while (el) { const s = window.getComputedStyle(el); if (s.overflowY === "auto" || s.overflowY === "scroll" || s.overflow === "auto") return true; el = el.parentElement; } return false; })() : null; return { buttonCount: buttons.length, buttonDetails: btnDetails, leftGroup: btnDetails.filter((b) => b.group === "left"), centerGroup: btnDetails.filter((b) => b.group === "center"), rightGroup: btnDetails.filter((b) => b.group === "right"), splitPanelVisible: !!leftPanel, leftWidthPercent: leftWidthPercent ? Math.round(leftWidthPercent) : null, rightWidthPercent: leftWidthPercent ? Math.round(100 - leftWidthPercent) : null, tableCount: tables.length, rightPanelHasTable: !!rightTable, rightTableScrollable, buttonsOverlap: overlaps, }; }); report.screen150 = info; await page.screenshot({ path: path.join(SCREENSHOT_DIR, "screen-150-tapseal.png"), fullPage: true }); console.log("screen-150-tapseal.png saved"); fs.writeFileSync( path.join(SCREENSHOT_DIR, "screen-150-tapseal-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, "screen-150-tapseal-error.png"), fullPage: true }).catch(() => {}); } finally { await browser.close(); } } main();