the cms for static site generators on atproto
lichen.page e2e feature-crawl
2 folders · 14 files

README.md

End-to-end crawl (e2e/) #

A standalone, browser-driven crawl of the whole application: it launches the real lichen server (the Rust lichen-server, started via the CLI on a free port) and walks every user-facing feature in a real browser (Playwright + Chromium), across many variations and with a dedicated adversarial/security pass.

It is not part of the unit suite. pytest -q has testpaths = ["tests"], so it never collects anything here; this crawl is a separate, slower, on-demand suite run by its own command. Running it does not change how pytest -q behaves or how long it takes.

Run it #

e2e/feature-crawl/run-e2e.sh

The script resolves the Nix Chromium and the C++ runtime Playwright needs, then runs python -m crawl. It exits non-zero if any check fails or any in-scope feature went uncovered. The crawl prints its checks as it goes and a pass/fail summary at the end.

Prerequisites: nix develop .#e2e, which provides playwright, chromium and stdenv.cc.cc.lib. No Playwright browser download is needed, since it drives the Nix Chromium directly.

Layout #

Path What it is
config.py Fixed test data: the accounts, hosts, viewports, sample content.
browser.py Launches the Nix Chromium (all hosts mapped to loopback); hands out isolated pages.
live_server.py Builds a throwaway root on disk, creates accounts via the real CLI, and runs a real server on a free port.
report.py Records every check, ties it to feature ids, and decides pass/fail.
coverage_map.py The expected-feature set (contract for "nothing goes unwalked").
steps.py Reusable composite steps (sign in).
pages/ One page object per screen — selectors and actions live here.
flows/ One module per feature area; each records what it proves.
crawl.py Wires the flows to the right server configurations and runs them.

Why real registrable hosts (*.lichen.page) #

Multi-site mode shares the session cookie across a site's subdomains by scoping it to the parent domain (extract_cookie_domain("dashboard.lichen.page") → .lichen.page). A browser rejects a cookie scoped to .localhost (a special-use TLD), so the crawl uses a real registrable domain and tells Chromium to resolve every hostname to loopback (--host-resolver-rules=MAP * 127.0.0.1). This exercises the real cross-subdomain auth path the app ships.

The coverage map, variation matrix, and edge-case/security catalog are written up in machine-docs/STATUS-fork-e2e.md; the findings ledger is machine-docs/RUST-E2E-FINDINGS.md.