The browser harness lived in /tmp/opencode and an overnight reboot wiped it. It now lives in tests/ and survives reboots, is versioned and runs with one command. - tests/lib.mjs: shared helpers (Chromium auto-detect, seeding, IndexedDB fixtures, stub/extra instance spawn with process-group cleanup, check/finish). - tests/run-all.mjs + npm run test:e2e [filter]: runs the ten suites in order with a summary; suites that need a stub Ollama or VAPID keys start their own next start instance on 3208/3209, verify the port is free and kill the group on exit. Test scratch in tests/.tmp/ (gitignored). - Suites rebuilt and green against the current build: regression 38, mobile 94 (tab matrix, ... sheet, settings sheet, axe), wizard 83, native 31 (PWA/offline/share/back/undo/haptics/draft), i18n 13, freeze-loading 6, review 15, phase1 36 (backup/sync/usage limits), phase2 42 (learning engine/reminders), phase3 21 (homework check). 379 checks, 10/10 suites in one full run. - playwright-core + axe-core added as devDependencies; CHROME env or the newest ~/.cache/ms-playwright chromium is used. - README: new decision 45 documenting the harness; decision 44's verification note updated. The older suites' exact sources were lost with the wipe, so the rebuilt versions reconstruct the same feature areas rather than being byte-identical.
44 lines
1.3 KiB
JavaScript
44 lines
1.3 KiB
JavaScript
/**
|
|
* Runs every Freezmo browser suite in order.
|
|
*
|
|
* npm run test:e2e # everything
|
|
* npm run test:e2e -- phase1 # only suites whose name contains "phase1"
|
|
*
|
|
* Each suite is a standalone script that talks to the running app on :3207
|
|
* (FREEZMO_URL overrides). Suites that need a stub Ollama or extra server
|
|
* instance start their own on their own port and clean up after themselves.
|
|
*/
|
|
import { spawn } from "node:child_process";
|
|
import path from "node:path";
|
|
|
|
const SUITES = [
|
|
"regression",
|
|
"mobile-test",
|
|
"wizard-test",
|
|
"native-test",
|
|
"i18n-test",
|
|
"freeze-loading-test",
|
|
"phase1-test",
|
|
"phase2-test",
|
|
"phase3-test",
|
|
"review-test",
|
|
];
|
|
|
|
const filters = process.argv.slice(2);
|
|
const list = filters.length ? SUITES.filter((name) => filters.some((f) => name.includes(f))) : SUITES;
|
|
|
|
const here = path.dirname(new URL(import.meta.url).pathname);
|
|
const repo = path.resolve(here, "..");
|
|
|
|
let failed = 0;
|
|
for (const suite of list) {
|
|
console.log(`\n===== ${suite} =====`);
|
|
const code = await new Promise((resolve) => {
|
|
const child = spawn(process.execPath, [path.join(here, `${suite}.mjs`)], { cwd: repo, stdio: "inherit" });
|
|
child.on("close", resolve);
|
|
});
|
|
if (code !== 0) failed += 1;
|
|
}
|
|
|
|
console.log(`\n${list.length - failed}/${list.length} suites passed`);
|
|
process.exit(failed ? 1 : 0);
|