-
Notifications
You must be signed in to change notification settings - Fork 0
Testing
npx playwright install chromium # first time only, downloads a browser
npm testtest/smoke.mjs drives a real headless Chromium against the built file://dist/index.html —
not a jsdom simulation — because a good chunk of what needs testing (File System Access API
availability, file:// origin behaviour, actual save-dialog interception) only shows up against a
real browser engine. Around 29 assertions across roughly two dozen scenarios.
-
URL and header parsing for the AI client — six endpoint-shape cases (plain OpenAI-style,
trailing slash, a proxy needing
/v1appended, an Azure deployment URL with a preserved query string, a gateway with its own query string) and a header-parsing edge case. -
Cold start over
file://— the seeded demo records render,crypto.subtleandisSecureContextare available in this context. -
Create a record, save it — via the download fallback (the test disables
showSaveFilePickerto force the path Firefox/Safari actually use), reopen the saved file, and confirm the new record survived the round-trip. - Encryption round-trip — set a weak passphrase (confirms the strength hint appears but nothing is blocked), save, confirm the saved source contains no trace of the plaintext, reopen with the wrong passphrase (rejected) and then the right one (decrypts, all records present).
- CSV export, dark mode (and that it persists across a save/reopen, including on the lock screen before decryption), settings round-trip in general.
-
AI dialect negotiation against a mock endpoint that deliberately rejects
max_tokensand a non-defaulttemperatureon its first two responses, forcing the real adaptation logic to run — then asserts the negotiated dialect is what actually got stored and reused on the next call. - A real chat exchange, an attached file actually reaching the model's context, and a deliberately mixed batch of AI-proposed actions — one valid update, one update with an invalid enum value, one create with an unknown field — asserting that the valid one applies, the invalid ones are named as rejected, and the record count only grows by the operations that actually succeeded.
- API key handling: not saved into the file without an explicit opt-in, prompted for on next open when missing, a working "switch AI off instead" escape hatch, and — when the opt-in is set — that it does land in the file.
-
Configuration export/import: a saved config contains no records and no key; loading a config
with a deliberately unknown field and a deliberately invalid
temperaturevalue drops/resets those and names it in the notice, rather than silently applying garbage. -
Branding: a colour change actually reaches the CSS custom property, and — the important one —
uploading a logo containing a
<script>tag and anonclickhandler results in neither surviving in the DOM, while the logo still renders in at least two of its four placements. - Screenshots at several points (light, dark, settings, drawer, mobile viewport) for a quick visual
spot-check, saved to
test/.out/(gitignored).
Every one of these bugs was actually caught by this suite during development, not found by manual inspection:
- A component
useEffectthat re-synced state from a stale prop on mount, racing a fast programmatic fill (exactly what.fill()does) and silently discarding the first keystroke — invisible to a human typing at normal speed, 100% reproducible under automation. - An internal call site calling a function with a since-changed signature, throwing only on the specific retry branch that a permissive mock endpoint would never exercise.
- A hardcoded test fixture path that happened to exist on one machine and nowhere else — passed locally, would have failed on every fresh clone and in CI.
If your change touches persistence, encryption, the AI client, or branding, add an assertion here
rather than relying on manual clicking — per CONTRIBUTING.md: "a feature without a test tends to
break silently three commits later, because nobody clicks through a single-file app by hand."
.github/workflows/build.yml runs on every push and pull request: npm ci, npm run build, a
sanity check that the built file is large enough to have actually inlined its script (a build that
silently produces a ~9 KB file is a known failure mode — see Limits and Troubleshooting)
and contains no external <script src= or <link href="http, then the full Playwright suite.
.github/workflows/pages.yml publishes the built file as a live demo on GitHub Pages on pushes to
main.