Files
vexplor/scripts/browser-test-purchase-supplier.js
DDD1542 43ead0e7f2 feat: Enhance SelectedItemsDetailInputComponent with sourceKeyField auto-detection and FK mapping
- Implemented automatic detection of sourceKeyField based on component configuration, improving flexibility in data handling.
- Enhanced the SelectedItemsDetailInputConfigPanel to support automatic FK detection and mapping, streamlining the configuration process.
- Updated the database connection logic to handle DATE types correctly, preventing timezone-related issues.
- Improved overall component performance by optimizing memoization and state management for better user experience.
2026-02-26 16:39:06 +09:00

197 lines
6.8 KiB
JavaScript

/**
* 구매관리 - 공급업체관리 / 구매품목정보 CRUD 브라우저 테스트
* 실행: node scripts/browser-test-purchase-supplier.js
* 브라우저 표시: HEADLESS=0 node scripts/browser-test-purchase-supplier.js
*/
const { chromium } = require("playwright");
const BASE_URL = "http://localhost:9771";
const SCREENSHOT_DIR = "test-screenshots";
const CREDENTIALS = { userId: "topseal_admin", password: "qlalfqjsgh11" };
async function runTest() {
const results = { success: [], failed: [], screenshots: [] };
const browser = await chromium.launch({ headless: process.env.HEADLESS !== "0" });
const context = await browser.newContext({ viewport: { width: 1280, height: 900 } });
const page = await context.newPage();
const fs = require("fs");
if (!fs.existsSync(SCREENSHOT_DIR)) fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
const screenshot = async (name) => {
const path = `${SCREENSHOT_DIR}/${name}.png`;
await page.screenshot({ path, fullPage: true });
results.screenshots.push(path);
console.log(` [스크린샷] ${path}`);
return path;
};
const clickMenu = async (text) => {
const loc = page.getByText(text, { exact: true }).first();
if ((await loc.count()) > 0) {
await loc.click();
return true;
}
const alt = page.getByRole("link", { name: text }).or(page.locator(`a:has-text("${text}")`)).first();
if ((await alt.count()) > 0) {
await alt.click();
return true;
}
return false;
};
const clickRow = async () => {
const rows = await page.$$('tbody tr, table tr, [role="row"]');
for (const r of rows) {
const t = await r.textContent();
if (t && !t.includes("데이터가 없습니다") && !t.includes("로딩")) {
await r.click();
return true;
}
}
if (rows.length > 0) {
await rows[0].click();
return true;
}
return false;
};
const clickButton = async (regex) => {
const btn = page.locator("button").filter({ hasText: regex }).first();
try {
if ((await btn.count()) > 0 && !(await btn.isDisabled())) {
await btn.click();
return true;
}
} catch (_) {}
return false;
};
try {
console.log("\n=== 로그인 확인 ===\n");
await page.goto(`${BASE_URL}/login`, { waitUntil: "networkidle", timeout: 15000 });
if (page.url().includes("/login")) {
await page.fill("#userId", CREDENTIALS.userId);
await page.fill("#password", CREDENTIALS.password);
await page.click('button[type="submit"]');
await page.waitForTimeout(3000);
}
results.success.push("세션 확인");
// ========== 테스트 1: 공급업체관리 ==========
console.log("\n=== 테스트 1: 공급업체관리 ===\n");
console.log("단계 1: 구매관리 메뉴 열기");
if (await clickMenu("구매관리")) {
await page.waitForTimeout(3000);
results.success.push("구매관리 메뉴 클릭");
} else {
results.failed.push("구매관리 메뉴 미발견");
}
await screenshot("p1_01_purchase_menu");
console.log("단계 2: 공급업체관리 서브메뉴 클릭");
if (await clickMenu("공급업체관리")) {
await page.waitForTimeout(8000);
results.success.push("공급업체관리 메뉴 클릭");
} else {
results.failed.push("공급업체관리 메뉴 미발견");
}
await screenshot("p1_02_supplier_screen");
console.log("단계 3: 공급업체 선택");
if (await clickRow()) {
await page.waitForTimeout(5000);
results.success.push("공급업체 행 클릭");
} else {
results.failed.push("공급업체 테이블 행 미발견");
}
await screenshot("p1_03_after_supplier_select");
console.log("단계 4: 납품품목 탭/영역 확인");
const itemTab = page.getByText(/납품품목|품목/).first();
if ((await itemTab.count()) > 0) {
await itemTab.click();
await page.waitForTimeout(3000);
results.success.push("납품품목/품목 탭 클릭");
} else {
results.failed.push("납품품목 탭 미발견");
}
await screenshot("p1_04_item_tab");
console.log("단계 5: 품목 추가 시도");
const addBtn = page.locator("button").filter({ hasText: /추가|\+ 추가/ }).first();
let addBtnEnabled = false;
try {
addBtnEnabled = (await addBtn.count()) > 0 && !(await addBtn.isDisabled());
} catch (_) {}
if (addBtnEnabled) {
await addBtn.click();
await page.waitForTimeout(2000);
const modal = await page.$('[role="dialog"], .modal, [class*="modal"]');
if (modal) {
const modalRow = await page.$('[role="dialog"] tbody tr, .modal tbody tr');
if (modalRow) {
await modalRow.click();
await page.waitForTimeout(1500);
}
}
await page.waitForTimeout(1500);
results.success.push("추가 버튼 클릭 및 품목 선택 시도");
} else {
results.failed.push("추가 버튼 미발견 또는 비활성화");
}
await screenshot("p1_05_add_item");
// ========== 테스트 2: 구매품목정보 ==========
console.log("\n=== 테스트 2: 구매품목정보 ===\n");
console.log("단계 6: 구매품목정보 메뉴 클릭");
if (await clickMenu("구매품목정보")) {
await page.waitForTimeout(8000);
results.success.push("구매품목정보 메뉴 클릭");
} else {
results.failed.push("구매품목정보 메뉴 미발견");
}
await screenshot("p2_01_item_screen");
console.log("단계 7: 품목 선택 및 공급업체 확인");
if (await clickRow()) {
await page.waitForTimeout(5000);
results.success.push("구매품목 행 클릭");
} else {
results.failed.push("구매품목 테이블 행 미발견");
}
await screenshot("p2_02_after_item_select");
// SelectedItemsDetailInput 컴포넌트 확인
const hasDetailInput = await page.$('input[placeholder*="품번"], [class*="selected-items"], input[name*="품번"]');
results.success.push(hasDetailInput ? "SelectedItemsDetailInput 렌더링 확인" : "SelectedItemsDetailInput 미확인");
await screenshot("p2_03_final");
console.log("\n========== 테스트 결과 ==========\n");
console.log("성공:", results.success);
console.log("실패:", results.failed);
console.log("스크린샷:", results.screenshots);
} catch (err) {
results.failed.push(`예외: ${err.message}`);
try {
await page.screenshot({ path: `${SCREENSHOT_DIR}/error.png`, fullPage: true });
results.screenshots.push(`${SCREENSHOT_DIR}/error.png`);
} catch (_) {}
console.error(err);
} finally {
await browser.close();
}
return results;
}
runTest()
.then((r) => process.exit(r.failed.length > 0 ? 1 : 0))
.catch((e) => {
console.error(e);
process.exit(1);
});