106 lines
3.6 KiB
JavaScript
106 lines
3.6 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const { chromium } = require('playwright');
|
|
|
|
const ROOT = path.resolve(__dirname, '..');
|
|
const PROFILE = path.join(ROOT, 'diagnostics', 'erp-playwright-profile');
|
|
const RUN_ID = new Date().toISOString().replace(/[-:T.Z]/g, '').slice(0, 14);
|
|
const RUN_DIR = path.join(ROOT, 'diagnostics', 'single-team-test', `run-${RUN_ID}`);
|
|
const LOG_FILE = path.join(RUN_DIR, 'run.log');
|
|
|
|
const ORDER = {
|
|
product: '遇见老挝',
|
|
departureDate: '2026-07-12',
|
|
pax: { adult: 2, childBed: 1, childNoBed: 1, infant: 0, leader: 0 },
|
|
rooms: { SGL: 0, TWN: 0, TRP: 0, DBL: 2, HNM: 0, TL: 0 },
|
|
prices: { adult: 500, childBed: 200, childNoBed: 100, infant: 0, leader: 0 },
|
|
op: '测试',
|
|
sales: '琳琳',
|
|
};
|
|
|
|
fs.mkdirSync(RUN_DIR, { recursive: true });
|
|
|
|
function log(message, data) {
|
|
const line = `[${new Date().toISOString()}] ${message}${data === undefined ? '' : ` ${JSON.stringify(data)}`}`;
|
|
fs.appendFileSync(LOG_FILE, `${line}\n`, 'utf8');
|
|
console.log(line);
|
|
}
|
|
|
|
async function saveShot(page, name) {
|
|
const file = path.join(RUN_DIR, `${name}.png`);
|
|
await page.screenshot({ path: file, fullPage: false });
|
|
log('screenshot', { file });
|
|
}
|
|
|
|
async function getText(page) {
|
|
return await page.locator('body').innerText({ timeout: 5000 }).catch(() => '');
|
|
}
|
|
|
|
async function waitForLogin(page) {
|
|
await page.goto('https://ltjt.yunzhi.run/System/Mainlt.asp', { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
for (;;) {
|
|
const url = page.url().toLowerCase();
|
|
const body = await getText(page);
|
|
if (!url.includes('login') && (body.includes('业务操作') || body.includes('独立团计划表') || body.includes('首页'))) {
|
|
log('login-ok', { url: page.url(), title: await page.title() });
|
|
return;
|
|
}
|
|
log('waiting-login', { url: page.url(), title: await page.title() });
|
|
await saveShot(page, 'waiting-login');
|
|
await page.waitForTimeout(3000);
|
|
}
|
|
}
|
|
|
|
async function countAndClick(page, selector, label) {
|
|
const locator = page.locator(selector);
|
|
const count = await locator.count();
|
|
log('locator-count', { label, selector, count });
|
|
if (count !== 1) throw new Error(`${label} locator count ${count}: ${selector}`);
|
|
await locator.click({ timeout: 10000 });
|
|
}
|
|
|
|
async function main() {
|
|
log('run-start', { runDir: RUN_DIR, order: ORDER });
|
|
const context = await chromium.launchPersistentContext(PROFILE, {
|
|
headless: false,
|
|
viewport: { width: 1920, height: 1000 },
|
|
acceptDownloads: true,
|
|
downloadsPath: path.join(RUN_DIR, 'downloads'),
|
|
});
|
|
const page = context.pages()[0] || await context.newPage();
|
|
page.setDefaultTimeout(12000);
|
|
|
|
try {
|
|
await waitForLogin(page);
|
|
await page.goto('https://ltjt.yunzhi.run/System/Business/orders.asp', {
|
|
waitUntil: 'domcontentloaded',
|
|
timeout: 30000,
|
|
});
|
|
await page.waitForTimeout(1500);
|
|
await saveShot(page, 'orders-list');
|
|
|
|
await countAndClick(page, 'input[type="button"][value="下单"]', 'single-order-button');
|
|
await page.waitForTimeout(1500);
|
|
await saveShot(page, 'after-click-single-order');
|
|
|
|
const body = await getText(page);
|
|
log('after-click-body-snippet', body.slice(0, 1000));
|
|
log('manual-checkpoint', {
|
|
message: 'Single-order form opened. Automation paused here until field selectors are confirmed.',
|
|
runDir: RUN_DIR,
|
|
});
|
|
} catch (error) {
|
|
log('error', { message: error.message, stack: error.stack });
|
|
await saveShot(page, 'error');
|
|
throw error;
|
|
} finally {
|
|
log('leaving-browser-open', { runDir: RUN_DIR });
|
|
await new Promise(() => {});
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|