- Added a new controller for managing process work standards, including CRUD operations for work items and routing processes. - Introduced routes for fetching items with routing, retrieving routings with processes, and managing work items. - Integrated the new process work standard routes into the main application file for API accessibility. - Created a migration script for exporting data related to the new process work standard feature. - Updated frontend components to support the new process work standard functionality, enhancing the overall user experience.
136 lines
5.1 KiB
TypeScript
136 lines
5.1 KiB
TypeScript
/**
|
|
* formData 로그 테스트 스크립트
|
|
* - http://localhost:9771/screens/1599 접속
|
|
* - P003 행 선택 → 추가 버튼 클릭 → 장비 선택 → 저장 전/후 콘솔 로그 수집
|
|
*
|
|
* 실행: npx tsx scripts/test-formdata-logs.ts
|
|
* (Playwright 필요: npx playwright install chromium)
|
|
*/
|
|
|
|
import { chromium } from "playwright";
|
|
|
|
const TARGET_URL = "http://localhost:9771/screens/1599?menuObjid=1762422235300";
|
|
const LOGIN = { userId: "topseal_admin", password: "1234" };
|
|
|
|
const TARGET_LOGS = ["🔵", "🟡", "🔴", "process_code", "splitPanelParentData"];
|
|
|
|
async function main() {
|
|
const browser = await chromium.launch({ headless: false });
|
|
const context = await browser.newContext();
|
|
const page = await context.newPage();
|
|
|
|
const consoleLogs: string[] = [];
|
|
const errors: string[] = [];
|
|
|
|
page.on("console", (msg) => {
|
|
const text = msg.text();
|
|
const type = msg.type();
|
|
if (type === "error") {
|
|
errors.push(`[CONSOLE ERROR] ${text}`);
|
|
}
|
|
const hasTarget = TARGET_LOGS.some((t) => text.includes(t));
|
|
if (hasTarget || type === "error") {
|
|
consoleLogs.push(`[${type}] ${text}`);
|
|
}
|
|
});
|
|
|
|
console.log("1. 페이지 이동:", TARGET_URL);
|
|
await page.goto(TARGET_URL, { waitUntil: "domcontentloaded", timeout: 20000 });
|
|
|
|
// 로그인 필요 여부 확인
|
|
const userIdInput = page.locator('input[name="userId"]').first();
|
|
if (await userIdInput.isVisible().catch(() => false)) {
|
|
console.log("2. 로그인 페이지 감지 - 로그인 진행");
|
|
await page.fill('input[name="userId"]', LOGIN.userId);
|
|
await page.fill('input[name="password"]', LOGIN.password);
|
|
await page.click('button[type="submit"]').catch(() => page.click('button:has-text("로그인")'));
|
|
await page.waitForTimeout(4000);
|
|
}
|
|
|
|
console.log("3. 5초 대기 (페이지 로드)");
|
|
await page.waitForTimeout(5000);
|
|
|
|
// 탭 확인 - 공정 마스터 (첫 번째 탭)
|
|
const firstTab = page.getByRole("tab", { name: /공정 마스터/i }).or(page.locator('button:has-text("공정 마스터")')).first();
|
|
if (await firstTab.isVisible().catch(() => false)) {
|
|
console.log("4. '공정 마스터' 탭 클릭");
|
|
await firstTab.click();
|
|
await page.waitForTimeout(1500);
|
|
}
|
|
|
|
// 좌측 패널 테이블 데이터 로드 대기
|
|
console.log("5. 좌측 패널 데이터 로드 대기");
|
|
await page.locator("table tbody tr").first().waitFor({ state: "visible", timeout: 25000 }).catch(() => {
|
|
throw new Error("좌측 테이블에 데이터가 없습니다. process_mng에 P003 등 데이터가 있는지 확인하세요.");
|
|
});
|
|
|
|
// P003 행 또는 첫 번째 행 클릭
|
|
let rowToClick = page.locator('table tbody tr:has(td:has-text("P003"))').first();
|
|
const hasP003 = await rowToClick.isVisible().catch(() => false);
|
|
if (!hasP003) {
|
|
console.log(" P003 미발견 - 첫 번째 행 클릭");
|
|
rowToClick = page.locator("table tbody tr").first();
|
|
}
|
|
await rowToClick.click();
|
|
await page.waitForTimeout(800);
|
|
|
|
// 우측 패널에서 '추가' 버튼 클릭 (모달 열기)
|
|
console.log("6. '추가' 버튼 클릭");
|
|
const addBtn = page.locator('button:has-text("추가")').first();
|
|
await addBtn.click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// 모달이 열렸는지 확인
|
|
const modal = page.locator('[role="dialog"], [data-state="open"]').first();
|
|
await modal.waitFor({ state: "visible", timeout: 5000 }).catch(() => {});
|
|
|
|
// 모달 내 설비 드롭다운/콤보박스 선택 (v2-select, entity-search-input 등)
|
|
console.log("7. 모달 내 설비 선택");
|
|
const trigger = page.locator('[role="combobox"], button:has-text("선택"), button:has-text("설비")').first();
|
|
if (await trigger.isVisible().catch(() => false)) {
|
|
await trigger.click();
|
|
await page.waitForTimeout(500);
|
|
const option = page.locator('[role="option"], li[role="option"]').first();
|
|
if (await option.isVisible().catch(() => false)) {
|
|
await option.click();
|
|
}
|
|
} else {
|
|
// select 태그인 경우
|
|
const selectEl = page.locator('select').first();
|
|
if (await selectEl.isVisible().catch(() => false)) {
|
|
await selectEl.selectOption({ index: 1 });
|
|
}
|
|
}
|
|
await page.waitForTimeout(800);
|
|
|
|
// 저장 전 콘솔 스냅샷
|
|
console.log("\n=== 저장 전 콘솔 로그 (formData 관련) ===");
|
|
consoleLogs.forEach((l) => console.log(l));
|
|
if (errors.length) {
|
|
console.log("\n=== 에러 ===");
|
|
errors.forEach((e) => console.log(e));
|
|
}
|
|
|
|
// 저장 버튼 클릭 (모달 내부의 저장 버튼)
|
|
console.log("\n8. '저장' 버튼 클릭");
|
|
const saveBtn = page.locator('[role="dialog"] button:has-text("저장"), [data-state="open"] button:has-text("저장")').first();
|
|
await saveBtn.click();
|
|
await page.waitForTimeout(3000);
|
|
|
|
// 저장 후 로그 수집
|
|
console.log("\n=== 저장 후 콘솔 로그 (formData 관련) ===");
|
|
consoleLogs.forEach((l) => console.log(l));
|
|
if (errors.length) {
|
|
console.log("\n=== 에러 ===");
|
|
errors.forEach((e) => console.log(e));
|
|
}
|
|
|
|
await page.waitForTimeout(2000);
|
|
await browser.close();
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error("테스트 실패:", e);
|
|
process.exit(1);
|
|
});
|