Entry points (no sixth tab): Ask in the Library header (desktop button, phone icon), Ask about this deck in the deck menu, Ask a question on study/homework results (compact result travels as context), and a Chat row in the desktop sidebar. Phones get a full-screen route with back + New chat; the tab bar steps aside. - Client-side retrieval: chunk scoped decks (~800 tokens), BM25 against the question + recent turns, top chunks under ~7k tokens, each labelled with deck + section. Notes come from the deck's stored sourceText (already kept for Regenerate); decks without it fall back to generated content and the UI says so. - Stateless server: /api/chat validates against the CHAT_MODELS allowlist, trims the history to ~6k tokens, caps context at ~9k and streams token/thinking/done/error NDJSON. /api/chat/extract reduces attachments to text through the existing vision step. - UI: user bubbles + full-width assistant text, streaming with stop, auto-scroll that pauses with a jump-to-bottom button, safe markdown (React nodes, no HTML injection; KaTeX dynamically imported only when a message has math), Thinking row for reasoning, copy/regenerate/ edit-and-resend, model + context pickers (last model remembered), composer with visualViewport keyboard handling, safe-area, 16px textarea, Enter-to-send on desktop. - Usage-limit failures keep the draft and show the shared message with Settings/Ollama actions; stopping maps the reader abort to a clean stopped state; offline disables sending with a reason. - Settings: Keep notes text for chat toggle; deck menu: Delete notes text. RATE_LIMIT_CHAT + CHAT_MODELS in .env.example and README. - Tests: chat suite (63 checks, stub Ollama) wired into run-all. Full set: 12/12 suites, 487 checks. SW -> freezmo-v32. Also: tests/model-compare.mjs (diagnostic) benchmarks two models on the same notes (latency, repair rounds, activity types) so the gpt-oss vs gemma default can be decided on numbers; defaults unchanged.
55 lines
3.5 KiB
Markdown
55 lines
3.5 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/`; 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. |
|
||
| `bubbles-test.mjs` | Ice-scene bubbles: stacking/layout contract, keyframes only transform+opacity, rise/sway/scale/fade phases, per-breakpoint counts (5/3/2), phone pacing, reduced motion, tab-hidden parking. |
|
||
| `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. |
|
||
| `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. |
|
||
|
||
## 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.
|