freezmo/tests/run-all.mjs
Martin Dvorak d95c5c7151 Podcast mode: notes read aloud with a lyric-style word highlight
The third segment of the note-powered wizards (Study deck / Homework /
Podcast) takes the same intake - photos, documents, pasted text, the share
target - and turns it into a spoken episode.

- prompts: PODCAST_SYSTEM_PROMPT writes for the ear (plain prose, no markdown,
  no visual references), chaptered into 3-8 sections around a length target.
- /api/podcast mirrors /api/generate's plumbing (rate limit, model gate,
  provider keys, heartbeats, the 2x deadline, the optional vision pass).
- storage: frezmo.podcasts.v1, zod-validated, included in the backup and the
  encrypted sync payload; a new library tab lists episodes with listen /
  rename / delete-with-undo, and the wizard switch deep-links in.
- player: the transcript is word-wrapped spans and the word under the voice
  rides a lyric-style highlight that keeps itself centred. Two clocks: exact
  onboundary events where the browser reports them, a per-word length timer
  where it does not (iOS Safari); the first boundary retires the timer.
  Pause = cancel + re-speak from the word, which makes resume, chapter jumps
  and tap-any-word-to-seek the same operation; the position saves on pause,
  page-hide and unmount, so reopening resumes. Speed rebuilds the engine and
  keeps playing; the Aero soundtrack pauses itself when the voice starts; a
  browser with no voice gets an honest note and a readable transcript.
- the script sits on a glass pane (plain paragraphs over Aero's grass failed
  contrast; the scan now covers the player too).

tests/podcast-test.mjs (17th suite) stubs the model and the speech engine and
drives the highlight by hand: 26 checks. All suites green, contrast clean.
Version 0.7.3, SW v95.
2026-10-16 11:42:15 +00:00

51 lines
1.5 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",
"activities-test",
"aero-music-test",
"bubbles-test",
"mobile-test",
"wizard-test",
"native-test",
"i18n-test",
"freeze-loading-test",
"phase1-test",
"phase2-test",
"phase3-test",
"podcast-test",
"security-test",
"chat-test",
"providers-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);