fighting-konoha/tests/all.mjs

49 lines
3.2 KiB
JavaScript

// Uji otomatis satu perintah (RENCANA 5.4): node tests/all.mjs
// 1. sintaks node --check untuk semua berkas JS proyek (game, menu, konten, manifest karakter, uji); cepat, tanpa peramban
// 2. smoke node tests/harness.mjs smoke 7 karakter x easy/hard melawan CPU, gagal bila ada galat halaman
// 3. pasangan node tests/harness.mjs tests/pairs.mjs 49 pasangan arah dimainkan singkat oleh bot, galat konsol, jurus terpakai, data TIERS, Koleksi
// Keluar dengan kode 0 bila semuanya lolos, 1 bila ada yang gagal. Tidak mengubah berkas apa pun.
// Env: ALL_SKIP=sintaks,smoke,pasangan (lewati langkah) PAIRS_SECONDS (detik permainan per pasangan, bawaan 24) PW_CORE, CHROME_BIN, HEADED seperti tests/harness.mjs
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { spawnSync } from 'node:child_process';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const skip = new Set((process.env.ALL_SKIP || '').split(',').map(x => x.trim()).filter(Boolean));
const run = (args, opt = {}) => spawnSync(process.execPath, args, { cwd: root, encoding: 'utf8', maxBuffer: 64 << 20, ...opt });
const tail = (text, n) => String(text || '').trim().split('\n').slice(-n).join('\n');
// berkas JS yang diperiksa sintaksnya: tingkat atas, content/, manifest karakter, dan uji
function jsFiles() {
const out = [];
for (const f of fs.readdirSync(root)) if (/\.(js|mjs)$/.test(f)) out.push(f);
for (const dir of ['content', 'tests', 'tools']) if (fs.existsSync(path.join(root, dir))) for (const f of fs.readdirSync(path.join(root, dir))) if (/\.(js|mjs)$/.test(f)) out.push(`${dir}/${f}`);
for (const d of fs.readdirSync(path.join(root, 'assets'))) { const m = `assets/${d}/manifest.js`; if (fs.existsSync(path.join(root, m))) out.push(m); }
return out.sort();
}
const steps = [
['sintaks', () => {
const bad = [], files = jsFiles();
for (const f of files) { const r = run(['--check', f]); if (r.status !== 0) bad.push(`${f}: ${tail(r.stderr, 3)}`); }
return { ok: !bad.length, text: bad.length ? bad.join('\n') : `${files.length} berkas JS lolos node --check` };
}],
['smoke', () => { const r = run(['tests/harness.mjs', 'smoke']); return { ok: r.status === 0, text: tail(r.stdout + r.stderr, r.status === 0 ? 2 : 25) }; }],
['pasangan', () => { const r = run(['tests/harness.mjs', 'tests/pairs.mjs']); return { ok: r.status === 0, text: tail(r.stdout + r.stderr, r.status === 0 ? 8 : 30) }; }]
];
const rows = [];
for (const [name, fn] of steps) {
if (skip.has(name)) { rows.push([name, 'DILEWATI', 0, '']); continue; }
const t = Date.now(); let res;
try { res = fn(); } catch (e) { res = { ok: false, text: String(e.stack || e) }; }
const dt = (Date.now() - t) / 1000;
rows.push([name, res.ok ? 'LOLOS' : 'GAGAL', dt, res.text]);
console.log(`\n== ${name}: ${res.ok ? 'LOLOS' : 'GAGAL'} (${dt.toFixed(1)} dtk)\n${res.text}`);
}
const failed = rows.filter(r => r[1] === 'GAGAL');
console.log('\nRingkasan: ' + rows.map(r => `${r[0]} ${r[1]}${r[1] === 'DILEWATI' ? '' : ` (${r[2].toFixed(1)} dtk)`}`).join(' | '));
console.log(failed.length ? `ADA YANG GAGAL: ${failed.map(r => r[0]).join(', ')}` : 'SEMUA UJI LOLOS');
process.exit(failed.length ? 1 : 0);