test(e2e): add a find-or-fail helper for collection lookups (#241)
Nine sites across five specs do `collection.find(...)` and dereference the result immediately. When the row is missing the test dies with "Cannot read properties of undefined" naming a line of test plumbing, which says nothing about what was expected — and that is exactly how favorites-filter:169 failed without producing a usable signal. The message names what was wanted and how many rows were searched. That distinction carries real diagnostic weight: "0 rows" means the fixture never landed, "37 rows" means it landed and the predicate is wrong, and those are different bugs to chase. It lives in its own module importing nothing, rather than in support/api.ts. That file imports @playwright/test, and vitest.config.ts runs tests/unit with environment: 'node' — putting six lines of pure logic there would drag a browser harness into the unit suite to test them. api.ts re-exports it so specs still reach it through fixtures. Throws rather than returning null, because every caller wants the row: an error at the point of the miss beats a null threaded through three more lines before something unrelated fails. Frontend: 30 unit tests pass, lint unchanged at 2 pre-existing warnings, build clean. Ref #241
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Picks one row out of a collection, failing loudly when it is not there.
|
||||
*
|
||||
* The pattern this replaces is `collection.find(...)` dereferenced straight
|
||||
* away — `customers.find(c => c.email === x).id`. When the row is missing the
|
||||
* test dies with "Cannot read properties of undefined" pointing at a line of
|
||||
* test plumbing, which says nothing about what was expected. The suite runs
|
||||
* fullyParallel against one shared database, so a lookup over a collection
|
||||
* other specs also write to can miss for reasons that have nothing to do with
|
||||
* the behaviour under test (#241).
|
||||
*
|
||||
* Deliberately imports nothing. It lives apart from `api.ts` so the Vitest
|
||||
* unit suite can cover it without pulling `@playwright/test` — and therefore a
|
||||
* browser harness — into a run configured for `environment: 'node'`.
|
||||
*
|
||||
* Throws rather than returning null: every caller wants the row, and an
|
||||
* Error at the point of the miss beats a null threaded through three more
|
||||
* lines before something else fails.
|
||||
*/
|
||||
export function findOrFail<T>(
|
||||
items: T[],
|
||||
predicate: (item: T) => boolean,
|
||||
description: string
|
||||
): T {
|
||||
const found = items.find(predicate);
|
||||
|
||||
if (found === undefined) {
|
||||
// The count matters as much as the description: "0 rows" means the
|
||||
// fixture never landed, while "37 rows" means it landed and the predicate
|
||||
// is wrong. Those are different bugs and the message should tell them
|
||||
// apart without a re-run.
|
||||
throw new Error(
|
||||
`expected to find ${description}, but none of the ${items.length} rows matched`
|
||||
);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
Reference in New Issue
Block a user