ERP-node/scripts/menu-copy-automation.ts

162 lines
6.1 KiB
TypeScript

/**
* 메뉴 복사 자동화 스크립트
*
* 실행: npx ts-node scripts/menu-copy-automation.ts
* 또는: npx playwright test scripts/menu-copy-automation.ts (playwright test 모드)
*
* 요구사항: playwright 설치 (npm install playwright)
*/
import { chromium, type Browser, type Page } from "playwright";
import * as fs from "fs";
import * as path from "path";
const BASE_URL = "http://localhost:9771";
const SCREENSHOT_DIR = path.join(__dirname, "../screenshots-menu-copy");
// 스크린샷 저장
async function takeScreenshot(page: Page, stepName: string): Promise<string> {
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
const filename = `${Date.now()}_${stepName}.png`;
const filepath = path.join(SCREENSHOT_DIR, filename);
await page.screenshot({ path: filepath, fullPage: true });
console.log(`[스크린샷] ${stepName} -> ${filepath}`);
return filepath;
}
async function main() {
let browser: Browser | null = null;
const screenshots: { step: string; path: string }[] = [];
try {
console.log("=== 메뉴 복사 자동화 시작 ===\n");
browser = await chromium.launch({ headless: false });
const context = await browser.newContext({
viewport: { width: 1280, height: 900 },
ignoreHTTPSErrors: true,
});
const page = await context.newPage();
// 1. 로그인
console.log("1. 로그인 페이지 이동...");
await page.goto(`${BASE_URL}/login`, { waitUntil: "networkidle" });
await takeScreenshot(page, "01_login_page").then((p) =>
screenshots.push({ step: "로그인 페이지", path: p })
);
await page.fill('#userId', "admin");
await page.fill('#password', "1234");
await page.click('button[type="submit"]');
await page.waitForTimeout(3000);
await takeScreenshot(page, "02_after_login").then((p) =>
screenshots.push({ step: "로그인 후", path: p })
);
// 로그인 실패 시 wace 계정 시도 (admin이 DB에 없을 수 있음)
const currentUrl = page.url();
if (currentUrl.includes("/login")) {
console.log("admin 로그인 실패, wace 계정으로 재시도...");
await page.fill('#userId', "wace");
await page.fill('#password', "1234");
await page.click('button[type="submit"]');
await page.waitForTimeout(3000);
}
// 2. 메뉴 관리 페이지로 이동
console.log("2. 메뉴 관리 페이지 이동...");
await page.goto(`${BASE_URL}/admin/menu`, { waitUntil: "networkidle" });
await page.waitForTimeout(2000);
await takeScreenshot(page, "03_menu_page").then((p) =>
screenshots.push({ step: "메뉴 관리 페이지", path: p })
);
// 3. 회사 선택 - 탑씰 (COMPANY_7)
console.log("3. 회사 선택: 탑씰 (COMPANY_7)...");
const companyDropdown = page.locator('.company-dropdown button, button:has(svg)').first();
await companyDropdown.click();
await page.waitForTimeout(500);
const topsealOption = page.getByText("탑씰", { exact: false }).first();
await topsealOption.click();
await page.waitForTimeout(1500);
await takeScreenshot(page, "04_company_selected").then((p) =>
screenshots.push({ step: "탑씰 선택 후", path: p })
);
// 4. "사용자" 메뉴 찾기 및 복사 버튼 클릭
console.log("4. 사용자 메뉴 찾기 및 복사 버튼 클릭...");
const userMenuRow = page.locator('tr').filter({ hasText: "사용자" }).first();
await userMenuRow.waitFor({ timeout: 10000 });
const copyButton = userMenuRow.getByRole("button", { name: "복사" });
await copyButton.click();
await page.waitForTimeout(1500);
await takeScreenshot(page, "05_copy_dialog_open").then((p) =>
screenshots.push({ step: "복사 다이얼로그", path: p })
);
// 5. 대상 회사 선택: 두바이 강정 단단 (COMPANY_18)
console.log("5. 대상 회사 선택: 두바이 강정 단단 (COMPANY_18)...");
const targetCompanyTrigger = page.locator('[id="company"]').or(page.getByRole("combobox")).first();
await targetCompanyTrigger.click();
await page.waitForTimeout(500);
const dubaiOption = page.getByText("두바이 강정 단단", { exact: false }).first();
await dubaiOption.click();
await page.waitForTimeout(500);
await takeScreenshot(page, "06_target_company_selected").then((p) =>
screenshots.push({ step: "대상 회사 선택 후", path: p })
);
// 6. 복사 시작 버튼 클릭
console.log("6. 복사 시작...");
const copyStartButton = page.getByRole("button", { name: /복사 시작|확인/ }).first();
await copyStartButton.click();
// 7. 복사 완료 대기 (최대 5분)
console.log("7. 복사 완료 대기 (최대 5분)...");
try {
await page.waitForSelector('text=완료, text=성공, [role="status"]', { timeout: 300000 });
await page.waitForTimeout(3000);
} catch {
console.log("타임아웃 또는 완료 메시지 대기 중...");
}
await takeScreenshot(page, "07_copy_result").then((p) =>
screenshots.push({ step: "복사 결과", path: p })
);
// 결과 확인
const resultText = await page.locator("body").textContent();
if (resultText?.includes("완료") || resultText?.includes("성공")) {
console.log("\n=== 메뉴 복사 성공 ===");
} else if (resultText?.includes("오류") || resultText?.includes("실패") || resultText?.includes("error")) {
console.log("\n=== 에러 발생 가능 - 스크린샷 확인 필요 ===");
}
console.log("\n=== 스크린샷 목록 ===");
screenshots.forEach((s) => console.log(` - ${s.step}: ${s.path}`));
} catch (error) {
console.error("오류 발생:", error);
if (browser) {
const pages = (browser as any).contexts?.()?.[0]?.pages?.() || [];
for (const p of pages) {
try {
await takeScreenshot(p, "error_state").then((path) =>
screenshots.push({ step: "에러 상태", path })
);
} catch {}
}
}
throw error;
} finally {
if (browser) {
await browser.close();
}
}
}
main().catch(console.error);