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.
65 lines
5.2 KiB
Markdown
65 lines
5.2 KiB
Markdown
# Browser suites
|
||
|
||
End-to-end checks for Freezmo, driven by Playwright against a **running
|
||
production build**. Everything lives in this repo (nothing in `/tmp`), so a
|
||
reboot cannot wipe the harness.
|
||
|
||
## Requirements
|
||
|
||
- The app is running on `http://127.0.0.1:3207` (`systemctl --user start freezmo`).
|
||
- A Chromium build. The suites auto-detect the newest Playwright Chromium in
|
||
`~/.cache/ms-playwright/` (Linux) or `~/Library/Caches/ms-playwright/` (macOS);
|
||
override with `CHROME=/path/to/chrome`.
|
||
- `npm install` (dev deps: `playwright-core`, `axe-core`).
|
||
|
||
## Running
|
||
|
||
```bash
|
||
npm run build && systemctl --user restart freezmo # fresh build first
|
||
npm run test:e2e # every suite, in order
|
||
npm run test:e2e -- phase1 # only suites whose name contains "phase1"
|
||
```
|
||
|
||
Each suite prints `PASS`/`FAIL` lines and exits non-zero on failure; the runner
|
||
prints a per-suite summary at the end.
|
||
|
||
## Suites
|
||
|
||
| Suite | Covers |
|
||
| --- | --- |
|
||
| `regression.mjs` | Library, deck card + menu, study feed to results, homework entry, desktop shell + settings/health panel. |
|
||
| `aero-music-test.mjs` | Frutiger Aero's soundtrack player (the SoundCloud widget API is stubbed): nothing loads in light/dark, a random playlist track starts in Aero, the circle expands into the credit bar, pause/collapse/close wiring, the off choice persisting and Aero re-selecting re-arming it, phone geometry over the tab bar and the chat composer, and the control stepping aside under an immersive overlay. |
|
||
| `bubbles-test.mjs` | Ice-scene bubbles: stacking/layout contract, the open band (a plain clip, no mask) and a 41-phase sweep that no visible orb or bubble ever touches its edges, keyframes only transform+opacity, rise/sway/scale/fade phases, per-breakpoint counts (5/3/2), phone pacing, reduced motion, parking (hidden tab, unfocused window, dialog scrim), and the cost contract (static blobs, no blend-mode grain, no blur on static glass, no hidden blur under Aero's bake). |
|
||
| `mobile-test.mjs` | Five-tab bar at 360/390 × EN/CS × dark/light × reduced motion (labels, targets, no hamburger/drawer), the library ⋯ sheet (Import JSON / New folder), the settings sheet (touch targets, key flow, drag-to-close, backdrop), axe contrast audits. |
|
||
| `wizard-test.mjs` | Deck 3-step flow and homework flow, flat action bar, in-page mode switch, the loading lock, abort-on-leave. |
|
||
| `native-test.mjs` | Manifest/PWA head, offline banner + disabled generate, share target GET + POST, Back-gesture layers, undo toast, tab re-tap, haptics, draft restore. |
|
||
| `i18n-test.mjs` | EN/CS dictionary parity, locale switch, Czech desktop shell, Czech phone tab labels and plurals. |
|
||
| `freeze-loading-test.mjs` | The generation loading screen appears immediately, hides the action bar, Cancel returns with the notice. |
|
||
| `podcast-test.mjs` | Podcast mode against a stub Ollama and a stubbed speech engine: the third wizard segment, notes → a saved episode, the word-wrapped transcript, boundary-driven highlighting (and the timer fallback's contract), pause/resume-from-word, chapter jumps, speed changes that keep playing, the position saved on page-hide and resumed on reopen, the library tab, and the API's 400/stream guards. |
|
||
| `review-test.mjs` | Smart Review loading feedback under a stalled request, the session end-to-end, mistakes, and the health-probe cache. |
|
||
| `phase1-test.mjs` | Backup export/import, persistence row, nudge, encrypted sync (enable/join/push/delete + API validation), usage-limit handling (client + a stub Ollama). |
|
||
| `phase2-test.mjs` | Answer history + SRS from a real study run, review/mistakes, stats, exam mode, push reminders hidden without VAPID and validated with it. |
|
||
| `phase3-test.mjs` | Check my work (API + phone/desktop UI), follow-ups, guide step explain, turn-into-a-study-deck. |
|
||
| `chat-test.mjs` | Chat: streaming API (validation, allowlist, context travel, history window, thinking separation, usage-limit mapping), attachment extraction, entry points, streaming/stop, markdown + KaTeX, model/scope pickers, edit/regenerate, offline, reduced motion, plus history (IDB persistence, reload, rename/search/delete/undo, scope+model memory), assistant actions, the export payload and a two-device sync round-trip. |
|
||
|
||
## Extra instances
|
||
|
||
`phase1`, `phase2` and `phase3` start their own `next start` instance with a
|
||
stub Ollama (or VAPID keys) on a spare port (3208/3209). Each suite checks the
|
||
port is free first and kills the whole process group on exit, so ports do not
|
||
leak between suites. Scratch data for the VAPID test lives in `tests/.tmp/`
|
||
(gitignored).
|
||
|
||
## Diagnostics (not part of the run)
|
||
|
||
`node tests/bubble-perf.mjs [label]` measures the ice-scene frame cost with a
|
||
CDP performance trace (rAF frame timing, long tasks, main-thread busy time,
|
||
style recalcs) on a 4× throttled phone profile and a 2× desktop profile. It
|
||
always exits 0; the numbers are for tuning the bubble count/speed.
|
||
|
||
`node tests/heat-probe.mjs [webkit|chromium]` (macOS only) measures what an
|
||
idle screen actually costs the machine: headed Playwright WebKit and Chromium
|
||
on the real display, the browser's CPU, the GPU time of its processes and of
|
||
WindowServer, per screen and theme, against an `about:blank` baseline and with
|
||
the scene parked. Install the engines once with
|
||
`npx playwright-core install webkit chromium` and keep the window in front.
|