66 lines
2.7 KiB
JavaScript
66 lines
2.7 KiB
JavaScript
/* 轻量 Playwright 回归测试运行器
|
||
* 用法:node tests/run.js [关键字过滤]
|
||
* 每个用例独立浏览器上下文(localStorage 隔离),HTTP 模式由内置静态服务器提供。 */
|
||
'use strict';
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const H = require('./helpers');
|
||
|
||
const filter = process.argv[2] || '';
|
||
const caseDir = path.join(__dirname, 'cases');
|
||
const files = fs.readdirSync(caseDir).filter(f => f.endsWith('.test.js')).sort();
|
||
|
||
let pass = 0, fail = 0;
|
||
const failures = [];
|
||
|
||
function makeT(name) {
|
||
return {
|
||
name,
|
||
ok(cond, msg) { if (!cond) throw new Error('断言失败: ' + msg); },
|
||
eq(a, b, msg) { if (a !== b) throw new Error(`断言失败: ${msg}\n 期望: ${JSON.stringify(b)}\n 实际: ${JSON.stringify(a)}`); },
|
||
includes(hay, needle, msg) { if (!String(hay).includes(needle)) throw new Error(`断言失败: ${msg}\n “${String(hay).slice(0, 200)}” 不包含 “${needle}”`); },
|
||
};
|
||
}
|
||
|
||
(async () => {
|
||
const server = await H.serveStatic(8177);
|
||
const cases = files.map(f => require(path.join(caseDir, f)))
|
||
.filter(c => !filter || c.name.includes(filter) || (c.title || '').includes(filter));
|
||
console.log(`\n▶ macos-web 回归测试 共 ${cases.length} 组${filter ? `(过滤: ${filter})` : ''}\n`);
|
||
for (const c of cases) {
|
||
const t = makeT(c.name);
|
||
const started = Date.now();
|
||
let ctxPages = [];
|
||
const env = {
|
||
...H, t,
|
||
http: server.url, file: H.FILE_URL,
|
||
track(p) { ctxPages.push(p); return p; },
|
||
};
|
||
try {
|
||
// 每用例 150s 超时保护,防止 evaluate 挂起拖死整个运行
|
||
await Promise.race([
|
||
c.run(env),
|
||
new Promise((_, rej) => setTimeout(() => rej(new Error('用例超时(150s)')), 150000)),
|
||
]);
|
||
pass++;
|
||
console.log(` ✓ ${c.name} ${c.title || ''} (${((Date.now() - started) / 1000).toFixed(1)}s)`);
|
||
} catch (e) {
|
||
fail++;
|
||
failures.push({ name: c.name, title: c.title, error: e });
|
||
console.log(` ✗ ${c.name} ${c.title || ''}`);
|
||
console.log(` ${String(e.message || e).split('\n').join('\n ')}`);
|
||
}
|
||
// 关闭本用例打开的上下文
|
||
for (const p of ctxPages) { try { await p.ctx.close(); } catch (e) {} }
|
||
}
|
||
await H.closeBrowser();
|
||
await server.close();
|
||
console.log(`\n──────────────────────────────`);
|
||
console.log(`通过 ${pass} / ${pass + fail},失败 ${fail}`);
|
||
if (failures.length) {
|
||
console.log('\n失败明细:');
|
||
failures.forEach(f => console.log(` ✗ ${f.name}: ${(f.title || '')}`));
|
||
}
|
||
process.exit(fail ? 1 : 0);
|
||
})().catch(e => { console.error('运行器异常:', e); process.exit(2); });
|