Move the browser suites into the repository

They lived in a scratch directory under /tmp, which was cleared overnight;
four of the five were simply gone. Whatever they were worth, they were
worth nothing kept there.

Rewritten against a shared lib.mjs. The old ones registered their users
through the sign-up form, which no longer exists — each suite now creates
a throwaway account through the admin API and deletes it afterwards, so a
run leaves the database as it found it. The previous generation left nine
accounts behind; those are gone too.

Three test hooks went into the app, each of which earns its place beyond
testing: aria-label on the note title (the sidebar search box is also a
text input, and a screen reader could not tell them apart either),
data-note-row on list rows, data-user on admin rows.

Two suites were flaky in ways worth naming, because both were the test
misreading the app rather than the app misbehaving:
- ticking a task then inserting a note link put the link inside the task
  list, since Control+End lands there. Verified against the server that
  the tick itself persists correctly; the suite now leaves the list first
  and asserts where the link ended up.
- the note-title lookup matched the sidebar's Trash entry, which wears the
  same emoji as a note row.

56 checks across five suites, all passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-08 14:30:08 +02:00
1 parent 41ba99c017
commit 311e992496
13 files changed
+915

No files matched your search

+28
View File
@@ -309,6 +309,34 @@ bug they cover actually happened:
- `hasPendingWrites` must cover the debounce window, not just requests in flight
- v1 note bodies must migrate without losing task state or smuggling in markup
### Browser suites
The unit tests cover the data layer; these drive a real browser against a real
server, because the failures that hurt most in this app were never visible in a
unit test — a stale response overwriting fresh strokes, a note link surviving in
memory but not through a reload.
```bash
docker compose -f docker-compose.dev.yml up -d --build # must be running
./e2e/run.sh # all suites
./e2e/run.sh editor drawing # only these
```
| Suite | Checks | What it holds down |
| --- | --- | --- |
| `admin` | 15 | no sign-up anywhere; `/api/admin/*` refused for non-admins even when called directly |
| `editor` | 12 | tables, task lists, note links, backlinks — and that each survives a reload |
| `search-attachments` | 12 | body-only matches, ranking, umlauts; images as blob URLs, not inline bytes |
| `history` | 10 | a large deletion is snapshotted, restoring works, restoring is itself undoable |
| `drawing` | 7 | strokes survive the poller, and match across four viewport widths |
Each suite creates a throwaway account through the admin API and deletes it
afterwards, so runs leave the database as they found it. They need an admin to
do that with — `marc`/`geheim123` by default, override with `INKNOTE_ADMIN` and
`INKNOTE_ADMIN_PASS`.
Screenshots land in `e2e/shots/`, which is worth a look when a check fails.
### How the frontend is arranged
`App.jsx` holds only *where the user is* — the open notebook, the open note, the