test: close the empty-batch hole in the e2e unstubbed-request guard (closes #187)
Some checks failed
check / check (push) Has been cancelled
Some checks failed
check / check (push) Has been cancelled
The guard that reports unrecognised POST bodies used batch.every(), which is vacuously true on an empty array, so a POST with body [] was answered 200 [] and escaped the one mechanism whose job is to make unrecognised outbound traffic fail the suite rather than pass silently. Unreachable in practice today, which is exactly the qualifier that stops being true later. The comment explaining the guard also described a mechanism that does not exist: playwright-core decodes a binary body lossily rather than returning null, so such a body reaches the JSON parse as mojibake and is reported by the catch, while only an absent or empty body decodes to null and is reported by the type guard. Both are reported; the comment now describes the two real routes.
This commit was merged in pull request #267.
This commit is contained in:
8
TODO.md
8
TODO.md
@@ -44,6 +44,14 @@ undefined identifiers, which is how
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-08-12: Closed the empty-array hole in the end-to-end unstubbed-request
|
||||||
|
guard. `batch.every()` is vacuously true on `[]`, so a POST with body `[]` was
|
||||||
|
answered `200 []` instead of failing the suite; the guard now rejects an empty
|
||||||
|
batch, demonstrated green-before/red-after with a throwaway probe. The comment
|
||||||
|
claiming `postData()` returns `null` for undecodable bodies was corrected to
|
||||||
|
the two real paths — an absent or empty body decodes to `null`, a binary body
|
||||||
|
decodes lossily into invalid JSON
|
||||||
|
([#187](https://git.eeqj.de/sneak/AutistMask/issues/187)).
|
||||||
- 2026-08-12: The transaction confirmation screen has browser coverage. The
|
- 2026-08-12: The transaction confirmation screen has browser coverage. The
|
||||||
end-to-end suite reaches ConfirmTx for both the native ETH and the ERC-20 path
|
end-to-end suite reaches ConfirmTx for both the native ETH and the ERC-20 path
|
||||||
off a funded-balance fixture, and asserts the pending, funded, over-balance
|
off a funded-balance fixture, and asserts the pending, funded, over-balance
|
||||||
|
|||||||
@@ -297,17 +297,26 @@ async function handleRpc(route, postData, opts, report) {
|
|||||||
// ethers batches by default, so the body may be an array.
|
// ethers batches by default, so the body may be an array.
|
||||||
const batch = Array.isArray(payload) ? payload : [payload];
|
const batch = Array.isArray(payload) ? payload : [payload];
|
||||||
|
|
||||||
// Anything that is not a JSON-RPC object, or a batch of them, is not
|
// Anything that is not a JSON-RPC object, or a NON-EMPTY batch of
|
||||||
// RPC at all and must be reported like any other unrecognised
|
// them, is not RPC at all and must be reported like any other
|
||||||
// outbound traffic rather than dereferenced. request.postData()
|
// unrecognised outbound traffic rather than dereferenced.
|
||||||
// returns null both for a bodyless POST and for a body Playwright
|
//
|
||||||
// cannot decode as UTF-8 (sendBeacon with a Blob, or any binary
|
// The length check is not decoration: every() is vacuously true on an
|
||||||
// payload), so this is not an empty-string special case: it rejects
|
// empty array, so without it a POST with body [] was answered 200 []
|
||||||
// every non-object payload, exactly as the catch above rejects every
|
// and escaped the guard entirely (issue #187). No real batch is empty,
|
||||||
// unparseable one.
|
// so nothing legitimate is caught by it.
|
||||||
|
//
|
||||||
|
// Two distinct paths land a non-RPC body here, and neither is an
|
||||||
|
// empty-string special case. playwright-core's postData() is
|
||||||
|
// `buffer.toString("utf-8") || null`, so an absent or empty body
|
||||||
|
// decodes to null, JSON.parse("null") yields null, and the type guard
|
||||||
|
// below reports it. A binary body is instead decoded LOSSILY into
|
||||||
|
// mojibake — not null — which is not valid JSON, so the catch above
|
||||||
|
// reports that one. Both end up reported; only the route differs.
|
||||||
if (
|
if (
|
||||||
payload === null ||
|
payload === null ||
|
||||||
typeof payload !== "object" ||
|
typeof payload !== "object" ||
|
||||||
|
batch.length === 0 ||
|
||||||
!batch.every((req) => req !== null && typeof req === "object")
|
!batch.every((req) => req !== null && typeof req === "object")
|
||||||
) {
|
) {
|
||||||
report("unstubbed request: POST " + route.request().url());
|
report("unstubbed request: POST " + route.request().url());
|
||||||
|
|||||||
Reference in New Issue
Block a user