Files
siftlode/frontend/e2e/README.md
T
peter ef99f7b5c7 fix(auth): a Google connect names its tab's account too, and a refused tab says why
- /auth/google/connect is a navigation and carries no headers: the tab names the account it
  was built for in `expect`, checked by the same comparison as the request header
  (built_for_another_account); a mismatch lands on /?account=changed
- the link marker names the OAuth state of its own flow: an older flow coming back no longer
  spends the marker of the connect still open (which then returned as a plain sign-in)
- a 401 account_changed reloads the tab with a one-time flag, and the reloaded tab says it
  now shows the account signed in
- a refused switch to a suspended or not-yet-approved account says so in the signed-in
  app's words, naming the address a request was recorded for
- the prefs merge locks FOR NO KEY UPDATE, so a transaction that only added a row referring
  to the account does not hold the save up; a test pins the lock
- giving up a lost page closes a channel page open over it
- e2e README names the chromium-only specs
2026-10-21 02:05:33 +02:00

82 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# E2E characterization (golden-master) net
Playwright tests that lock the app's five core flows — **feed** (scroll + filter), **channel**
(open → back), **player** (open/close), **settings** (dirty-save + guard), and **page switching** —
so the Platform refactor can _prove_ it changed nothing. They assert current, correct behavior;
they deliberately do **not** encode the known Platform bugs (those get their own specs when the
sprints that fix them land).
## Run
```sh
siftlode e2e # against the baked localdev :8080 stack (authoritative)
siftlode e2e-ui # same, Playwright UI mode
siftlode e2e-seed # (re)seed the test account only, no tests
```
The localdev stack must be up (`siftlode dev`). `global.setup.ts` reseeds the account and logs in
once, sharing the session via `e2e/.auth/state.json` (git-ignored).
**A dropped localhost connect** — on a Windows host, a burst of test traffic can drop a loopback
connect now and then (every port, any program). The browser resends it and only waits (a loader
outlives an `expect` timeout); Node does not, so a request from the test side fails with
`connect ETIMEDOUT`. Those requests go through `retryConnect` (`e2e/retryConnect.ts`), which tries
that one error again and passes every other failure straight on. Don't run two e2e suites on the
same machine at once.
**Browsers** — every flow runs in three projects: `chromium` (Desktop Chrome), `webkit` (Desktop
Safari) and `ipad` (iPad gen 7 landscape: 1080×810, touch, mobile) — except `a11y`, `member` and
`devices`, which run on chromium only (`CHROMIUM_ONLY`; why is in the `docs/gates.md` row). Install the engines once per
machine with `npx playwright install chromium webkit`; run one project with
`npx playwright test --project=ipad`. WebKit catches what every iOS browser inherits from the engine
(JS, CSS/layout, event order). It does **not** reproduce iPad media refusals: Playwright's WebKit
decodes through the host OS (Media Foundation on Windows, GStreamer on Linux), and measured on
2026-09-14 it played an mp3-in-mp4 and an AV1 mp4 that a real iPad refuses. Check a media format
on a real iPad against the dev stack over the LAN (`http://<desktop LAN IP>:8080`, e.g. a
login-free `/watch/<token>` share link).
**Target** — `PW_BASE_URL` (default `http://127.0.0.1:8080`):
- **`:8080`** (baked SPA) is authoritative and same-origin. After a **frontend change you must
`siftlode dev` (rebuild)** for its baked SPA to carry the latest test hooks.
- **`:5173`** (Vite dev) serves source live — the fast refactor loop; it proxies `/api` to `:8080`,
so the stack must still be up. All five flows are proxy-safe:
```sh
PW_BASE_URL=http://localhost:5173 siftlode e2e
```
**Accessibility** — `a11y.spec.ts` runs axe-core's WCAG 2.x A + AA rules (`@axe-core/playwright`)
over every rail page, every admin page and the player, in `chromium` only (the rules read the DOM,
which the engines build alike). It does not judge colour contrast: axe files text on a gradient —
every glass surface — as "incomplete", not as a pass or a hit.
## Account & fixture
Tests run as a dedicated **admin** account `e2e@siftlode.local` (never a real account;
admin so the suite can reach the admin-only pages / render branches, matching the real primary
user), reset to a deterministic baseline every run by
[`scripts/e2e_seed.py`](../../scripts/e2e_seed.py) (run
in-container so it reuses the app's models + argon2 hasher): the top-3 organic channels subscribed,
one in-progress + one watched + one saved video, prefs pinned to `language: en`. A second account,
the plain **member** `e2e-member@siftlode.local`, gets the same baseline and its own session
(`e2e/.auth/member.json`). Two specs run as it: `member.spec.ts`, holding what a non-admin sees (no
admin entry, no admin call, no failed request, an admin link lands on the feed), and `devices.spec.ts`,
which signs it in on a desktop and an iPad at once and changes its channel layout on the server (put
back in a `finally`) — a spec that reads the member's server prefs must not run beside it. Credentials come from `E2E_EMAIL` (default
`e2e@siftlode.local`), `E2E_MEMBER_EMAIL` (default `e2e-member@siftlode.local`) and `E2E_PASSWORD`
(both accounts) — **required, no default**: run the suite through the ops wrapper, which exports it
from the secret store. Override the container name with
`E2E_API_CONTAINER`; skip the in-container seed with `E2E_SKIP_SEED=1`.
## Selectors
The app has no `data-testid`s of its own and all copy is i18n (en/hu), so the specs key on a thin
`data-testid` layer (added with this sprint) plus the locale pinned to `en`. Stable ARIA hooks that
already existed are used directly (`role="dialog"` on the player, `aria-current="page"` on the
active nav row, `aria-pressed` on the feed toggles).
## Typecheck
`npx tsc -p e2e/tsconfig.json --noEmit` (the specs are outside the app's `src` tsconfig).