test: containerized Chrome end-to-end harness that drives the real popup (closes #181) #185
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
82c40e009d |
test: delete the unreachable seal() hook and guard non-object RPC bodies
check / check (push) Successful in 24s
Three review findings, no redesign. seal() was installed after session.close(), so onLate could never fire: once the context is destroyed no route handler and no console listener exists to record anything. It was dead code that the attribution table, run.js and harness.js all described as the final safety net. Deleted rather than moved — take() already drains everything the collector holds before teardown, so it covered nothing, and this harness must not ship a mechanism it cannot demonstrate. The now-unreachable `late > 0` term in the failure condition goes with it. handleRpc() parsed `postData || "null"` and then dereferenced the result, so a POST whose body Playwright reports as null — a bodyless request, or any payload it cannot decode as UTF-8, e.g. sendBeacon with a Blob — threw a TypeError inside the route handler and killed node mid-suite: truncated TAP, no summary, no failure line. Non-object payloads now take the same path as unparseable ones and are reported as unstubbed traffic, which is the entire point of that branch. README claimed unrecognised outbound requests are reported as failures, unqualified, while observation in fact ends TRAILING_WATCH_MS after the last test returns. The limit is now stated where it lands. |
||
|
|
a13862d991 |
test: make e2e error attribution total, and fix the README canary text
check / check (push) Successful in 19s
The error collector had a window API (mark/since) and twice a record fell outside somebody's window and was silently dropped, producing a green run that proved nothing: first the mark started after test 1, discarding everything recorded during launch; then the tail after the final test was never read at all, so a request escaping the fixtures at the end of the last test reported 5/5 passed and exit 0. Rather than patch a second boundary and invite a third, the window concept is gone. ErrorCollector exposes only take(), which always drains everything outstanding, so successive takes partition the whole record stream with no gaps, and seal(), which closes the stream at the end of the run and routes stragglers straight to a failure. Attribution is total by construction: launch through test 1 goes to test 1, each subsequent interval to the test that ends it, the tail to the suite. The tail also needs to exist before it can be drained. A request a test fires without awaiting reaches the route handler about 10ms after that test's function resolves, and closing the context does not wait for it, so with no window at all it died unobserved. The run now keeps collecting for a bounded 1.5s after the last test before teardown. Also: - README described a canary that was built, found to kill the service worker, and deleted. Replaced with what actually runs: the harness waits for the background worker's own startup blocklist fetch to reach the route handler and aborts if it does not. Documents --host-resolver-rules=MAP * ~NOTFOUND as defence in depth. - The canary's failure message asserted traffic was escaping to the real internet and blamed the -e flag. It cannot distinguish that from a lost startup race, so it now states what was observed and lists both causes. - E2E_TRACE_NETWORK was compared strictly to "1", so E2E_TRACE_NETWORK=true silently did nothing. Recognised on/off values are accepted and anything else is a hard error rather than a quiet default. - The measured margin that makes the canary sound is route install at 11-23ms against the worker fetch at 525-883ms, not the 30s timeout slack the comment cited. |
||
|
|
a3075f2f47 |
test: intercept the MV3 service worker's network in the e2e harness
check / check (push) Successful in 43s
ctx.route() does not see requests made by the background service worker unless Playwright is run with PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS=1, so the phishing blocklist fetch that src/background/index.js issues at worker startup was reaching raw.githubusercontent.com on the real internet on every run. phishingDomains.js swallows fetch failures, so nothing surfaced it, and the raw.githubusercontent.com stub in tests/e2e/network.js was unreachable code that made the gap look covered. script/test-e2e now sets the flag, with a comment recording what to do if a future Playwright drops it. The flag being experimental is not taken on trust: launch() waits for the worker's own startup request to arrive in the route handler and refuses to run the suite if it never does, so escaping traffic fails the run instead of passing unnoticed. Chrome is additionally started with --host-resolver-rules=MAP * ~NOTFOUND, so anything that does slip past interception cannot reach a real host. Also: errors and unstubbed requests recorded during launch are attributed to the first test rather than discarded, a suite that registers no tests now fails instead of exiting 0, a failure after the browser is up tears the context down instead of hanging the process, E2E_TRACE_NETWORK=1 prints every routed request tagged [sw] or [page], and the dead exports in harness.js and network.js are gone. |
||
|
|
d89629d090 |
test: containerized Chrome end-to-end harness that drives the real popup (closes #181)
check / check (push) Successful in 55s
`make check` was green while the AddToken screen crashed on every open. `script/lint` is only `prettier --check`, so a used-but-not-imported identifier is invisible until a browser evaluates it. This adds a suite that runs the real popup in a real Chrome and treats any uncaught page error or console.error as a failure. - `script/test-e2e` (with `make test-e2e` as a thin shim) builds `dist/chrome/` and runs `tests/e2e/run.js` inside the Playwright image, pinned by digest. `playwright-core` is pinned to the matching 1.56.0 through `yarn.lock`; the two must be bumped together because the browsers ship inside the image. - Deliberately outside `script/test` and `script/check`: REPO_POLICIES caps `make test` at 20 seconds. Nothing under `tests/e2e/` is named `*.test.js`, so jest cannot pick it up either. - Launches with `channel: "chromium"`; the default headless shell silently refuses to load extensions with no error at all. The extension id is read from the service worker URL, never hardcoded. - All http(s) traffic is intercepted at the browser level and served from fixtures, so the run is deterministic and offline. Unrecognised outbound requests are reported as failures rather than allowed. - A missing build or an unavailable container fails loudly; a skip that looks like a pass is the failure mode this is meant to prevent. - One allowlisted page error, for the libsodium WASM CSP fallback tracked as #182, which is otherwise untouched here. The suite was demonstrated failing against the unfixed tree with `pageerror: showView is not defined` and `pageerror: addressDotHtml is not defined`, so it carries the two one-line import fixes it caught: closes #150 — `showView` restored to the destructure in `src/popup/views/addToken.js`, dropped by |