140 lines
4.6 KiB
TypeScript
140 lines
4.6 KiB
TypeScript
|
|
/**
|
||
|
|
* 옵션설정 (Option Settings) 페이지 반응형 동작 테스트
|
||
|
|
* - V2CategoryManagerComponent + ResponsiveGridRenderer
|
||
|
|
* - 화면: http://localhost:9771/screens/1421
|
||
|
|
*
|
||
|
|
* 실행: npx tsx scripts/test-option-settings-responsive.ts
|
||
|
|
*/
|
||
|
|
import { chromium } from "playwright";
|
||
|
|
import * as path from "path";
|
||
|
|
import * as fs from "fs";
|
||
|
|
|
||
|
|
const BASE_URL = "http://localhost:9771";
|
||
|
|
const API_URL = "http://localhost:8080/api";
|
||
|
|
const PAGE_URL = `${BASE_URL}/screens/1421`;
|
||
|
|
const CREDENTIALS = [
|
||
|
|
{ userId: "SUPER", password: "1234" },
|
||
|
|
{ userId: "wace", password: "qlalfqjsgh11" },
|
||
|
|
];
|
||
|
|
|
||
|
|
const OUTPUT_DIR = path.join(__dirname, "../test-output/option-settings-responsive");
|
||
|
|
|
||
|
|
async function loginViaApi(): Promise<string> {
|
||
|
|
for (const cred of CREDENTIALS) {
|
||
|
|
const res = await fetch(`${API_URL}/auth/login`, {
|
||
|
|
method: "POST",
|
||
|
|
headers: { "Content-Type": "application/json" },
|
||
|
|
body: JSON.stringify({ userId: cred.userId, password: cred.password }),
|
||
|
|
});
|
||
|
|
const data = await res.json();
|
||
|
|
if (data.success && data.data?.token) {
|
||
|
|
console.log(` Using credentials: ${cred.userId}`);
|
||
|
|
return data.data.token;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
throw new Error("Login failed with all credentials");
|
||
|
|
}
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||
|
|
|
||
|
|
const token = await loginViaApi();
|
||
|
|
console.log("1. Logged in via API");
|
||
|
|
|
||
|
|
const browser = await chromium.launch({ headless: true });
|
||
|
|
const context = await browser.newContext({
|
||
|
|
viewport: { width: 1400, height: 900 },
|
||
|
|
});
|
||
|
|
const page = await context.newPage();
|
||
|
|
|
||
|
|
const consoleErrors: string[] = [];
|
||
|
|
const reactHookErrors: string[] = [];
|
||
|
|
|
||
|
|
page.on("console", (msg) => {
|
||
|
|
const type = msg.type();
|
||
|
|
const text = msg.text();
|
||
|
|
if (type === "error") {
|
||
|
|
consoleErrors.push(text);
|
||
|
|
if (text.includes("order of Hooks") || text.includes("React has detected")) {
|
||
|
|
reactHookErrors.push(text);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
try {
|
||
|
|
console.log("2. Loading login page to inject token...");
|
||
|
|
await page.goto(`${BASE_URL}/login`, { waitUntil: "domcontentloaded", timeout: 15000 });
|
||
|
|
await page.evaluate((t: string) => {
|
||
|
|
localStorage.setItem("authToken", t);
|
||
|
|
document.cookie = `authToken=${t}; path=/; max-age=86400; SameSite=Lax`;
|
||
|
|
}, token);
|
||
|
|
|
||
|
|
console.log("3. Navigating to Option Settings page (screens/1421)...");
|
||
|
|
await page.goto(PAGE_URL, { waitUntil: "domcontentloaded", timeout: 15000 });
|
||
|
|
await page.waitForTimeout(5000);
|
||
|
|
|
||
|
|
const report: string[] = [];
|
||
|
|
|
||
|
|
const widths = [
|
||
|
|
{ w: 1400, name: "1-desktop-1400px" },
|
||
|
|
{ w: 1100, name: "2-tablet-1100px" },
|
||
|
|
{ w: 900, name: "3-tablet-900px" },
|
||
|
|
{ w: 600, name: "4-mobile-600px" },
|
||
|
|
{ w: 1400, name: "5-desktop-1400px-restored" },
|
||
|
|
];
|
||
|
|
|
||
|
|
for (const { w, name } of widths) {
|
||
|
|
console.log(`\nResizing to ${w}px...`);
|
||
|
|
await page.setViewportSize({ width: w, height: w === 600 ? 812 : 900 });
|
||
|
|
await page.waitForTimeout(1500);
|
||
|
|
|
||
|
|
const filePath = path.join(OUTPUT_DIR, `${name}.png`);
|
||
|
|
await page.screenshot({ path: filePath, fullPage: false });
|
||
|
|
console.log(` Saved: ${filePath}`);
|
||
|
|
|
||
|
|
const hasCategoryColumn = (await page.locator('text=카테고리 컬럼').count()) > 0;
|
||
|
|
const hasUseStatus = (await page.locator('text=사용여부').count()) > 0;
|
||
|
|
const hasVerticalStack = (await page.locator('button:has-text("목록")').count()) > 0;
|
||
|
|
const hasLeftRightSplit = (await page.locator('[class*="cursor-col-resize"]').count()) > 0;
|
||
|
|
|
||
|
|
report.push(`[${w}px] Category column: ${hasCategoryColumn}, Use status: ${hasUseStatus}, Vertical: ${hasVerticalStack}, Split: ${hasLeftRightSplit}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log("\n" + "=".repeat(60));
|
||
|
|
console.log("OPTION SETTINGS RESPONSIVE TEST REPORT");
|
||
|
|
console.log("=".repeat(60));
|
||
|
|
report.forEach((r) => console.log(r));
|
||
|
|
|
||
|
|
if (consoleErrors.length > 0) {
|
||
|
|
console.log("\n--- Console Errors ---");
|
||
|
|
consoleErrors.slice(0, 10).forEach((e) => console.log(" ", e));
|
||
|
|
}
|
||
|
|
if (reactHookErrors.length > 0) {
|
||
|
|
console.log("\n--- React Hook Errors (order of Hooks) ---");
|
||
|
|
reactHookErrors.forEach((e) => console.log(" ", e));
|
||
|
|
}
|
||
|
|
|
||
|
|
fs.writeFileSync(
|
||
|
|
path.join(OUTPUT_DIR, "report.txt"),
|
||
|
|
[
|
||
|
|
"OPTION SETTINGS RESPONSIVE TEST REPORT",
|
||
|
|
"=".repeat(50),
|
||
|
|
...report,
|
||
|
|
"",
|
||
|
|
"Console errors: " + consoleErrors.length,
|
||
|
|
"React Hook errors: " + reactHookErrors.length,
|
||
|
|
...reactHookErrors.map((e) => " " + e),
|
||
|
|
].join("\n")
|
||
|
|
);
|
||
|
|
|
||
|
|
console.log("\nScreenshots saved to:", OUTPUT_DIR);
|
||
|
|
} catch (e) {
|
||
|
|
console.error("Error:", e);
|
||
|
|
throw e;
|
||
|
|
} finally {
|
||
|
|
await browser.close();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
main();
|