6.3 KiB
ADDED Requirements
Requirement: NetworkMonitor MUST assert absence of missing assets
NetworkMonitor (returned by attachNetworkMonitor(page)) SHALL expose assertNoMissingAssets() that fails when any 404 was observed for an image, font, script, or stylesheet resource type. The monitor SHALL also expose allow404(predicate: (entry) => boolean) to opt-out specific URLs from this assertion. Other 404s (e.g. for xhr/fetch resource types) are NOT subject to this assertion and remain governed by assertNoFailures().
Scenario: Missing image fails the assertion
- WHEN the page references
<img src="/missing.png">and the request returns 404 - AND
monitor.assertNoMissingAssets()is called - THEN the call throws
MissingAssetErrorwithcode === "TESTING_E2E.NETWORK.MISSING_ASSET"andcontext.urlcontaining/missing.png
Scenario: Allow-listed 404 does not fail
- WHEN
monitor.allow404((e) => e.url.endsWith("/beacon.gif"))is called before navigation - AND
/beacon.gifreturns 404 - AND
monitor.assertNoMissingAssets()is called - THEN the call returns without throwing
Scenario: Non-asset 404 does not fail this assertion
- WHEN an
xhrrequest to/api/fooreturns 404 - AND
monitor.assertNoMissingAssets()is called - THEN the call returns without throwing (the failure is reported by
assertNoFailures()instead)
Requirement: NetworkMonitor MUST assert absence of mixed content
NetworkMonitor SHALL expose assertNoMixedContent() that fails when the page is loaded over https:// AND any subresource was fetched over http://, OR when the browser reports a mixed-content blocking event. The assertion is a no-op when the page is loaded over http://.
Scenario: HTTP subresource on HTTPS page fails
- WHEN the page is
https://example.test/ - AND it includes
<script src="http://cdn.test/lib.js"> - AND
monitor.assertNoMixedContent()is called - THEN the call throws
MixedContentErrorwithcode === "TESTING_E2E.NETWORK.MIXED_CONTENT"andcontext.urlcontaininghttp://cdn.test/lib.js
Scenario: Plain HTTP page is exempt
- WHEN the page is
http://localhost:3000/ - AND
monitor.assertNoMixedContent()is called - THEN the call returns without throwing
Requirement: NetworkMonitor MUST assert absence of CORS errors
NetworkMonitor SHALL expose assertNoCorsErrors() that fails on any of: a request that failed with a net::ERR_CORS_* error code, a preflight (OPTIONS) response that did not satisfy the subsequent request, or a response missing a required Access-Control-Allow-Origin header that the browser blocked.
Scenario: CORS preflight failure fails the assertion
- WHEN an
OPTIONSpreflight returns withoutAccess-Control-Allow-Originand the browser cancels the follow-upPOST - AND
monitor.assertNoCorsErrors()is called - THEN the call throws
CorsErrorwithcode === "TESTING_E2E.NETWORK.CORS_ERROR"
Scenario: Same-origin requests are unaffected
- WHEN all requests are same-origin and complete normally
- AND
monitor.assertNoCorsErrors()is called - THEN the call returns without throwing
Requirement: NetworkMonitor MUST assert request graph against an allow-list
NetworkMonitor SHALL expose assertNoUnexpectedRequests({ allowed: (url: string) => boolean }) that fails when any observed request URL fails the allowed predicate. This assertion is opt-in and intended for tests requiring strict request-graph control.
Scenario: Unexpected request fails the assertion
- WHEN the page made a request to
https://tracker.test/pixel - AND
monitor.assertNoUnexpectedRequests({ allowed: (u) => u.startsWith("https://example.test") })is called - THEN the call throws
UnexpectedRequestErrorwithcode === "TESTING_E2E.NETWORK.UNEXPECTED_REQUEST"andcontext.url === "https://tracker.test/pixel"
Scenario: All allowed requests pass
- WHEN every request URL satisfies the predicate
- AND
monitor.assertNoUnexpectedRequests({ allowed })is called - THEN the call returns without throwing
Requirement: crawlInternalLinks MUST walk and verify internal links
The package SHALL export crawlInternalLinks(page, options?: { maxDepth?: number; sameOriginOnly?: boolean; ignore?: (url: string) => boolean }): Promise<CrawlReport> that BFS-walks all <a href> links from the entry page, follows internal links up to maxDepth (default 2), and asserts each link returns 2xx via HEAD with GET fallback. sameOriginOnly defaults to true. The returned CrawlReport SHALL list visited URLs, broken links, and any circular redirects encountered.
Scenario: Crawler reports broken internal link
- WHEN the page links to
/missingwhich returns 404 - AND
crawlInternalLinks(page)is called - THEN the returned report contains an entry whose
error.code === "TESTING_E2E.CRAWL.BROKEN_LINK"and whoseurlends in/missing
Scenario: Crawler honours sameOriginOnly default
- WHEN the page links to
https://external.test/foo - AND
crawlInternalLinks(page)is called with default options - THEN
https://external.test/foois NOT visited and is NOT reported as broken
Scenario: Crawler reports circular redirect
- WHEN
/aredirects to/band/bredirects to/a - AND
crawlInternalLinks(page)encounters this chain - THEN the report contains an entry whose
error.code === "TESTING_E2E.CRAWL.CIRCULAR_REDIRECT"
Scenario: Crawler reports max-depth exceeded
- WHEN the link graph contains paths deeper than
maxDepth - AND
crawlInternalLinks(page, { maxDepth: 1 })is called - THEN unvisited deeper links are reported with
error.code === "TESTING_E2E.CRAWL.MAX_DEPTH_EXCEEDED"
Requirement: Network and crawl errors MUST follow the structured-error contract
All errors thrown or reported by the new NetworkMonitor methods and crawlInternalLinks MUST be subclasses of TestingE2eError carrying { code, cause?, context? }. Codes MUST match ^TESTING_E2E\.(NETWORK|CRAWL)\.[A-Z_]+$.
Scenario: Code shape
- WHEN any of
MissingAssetError,MixedContentError,CorsError,UnexpectedRequestError,BrokenLinkError,CircularRedirectError,MaxDepthExceededErroris thrown - THEN
err instanceof TestingE2eErroris true ANDerr.codematches the regex