Browse pages
Web Testing
This page states how the TypeScript web stacks realize the frontend testing principles (Frontend testing).
Intent#
This page states how the TypeScript web stacks realize the frontend testing principles (Frontend testing). It states the runners, libraries, and commands one web frontend requires. A provision here cites the neutral rule it realizes.
| Kind | Where it runs | What it proves |
|---|---|---|
| Logic | Vitest beside the module | A mapping, a computed window, a state decision |
| Structure | Vitest beside the suite | The module tree mirrors the backend |
| Route contract | Playwright against a running stack | Every route renders one floorplan and passes the browser checks |
| Evidence | Playwright against a running stack | A use case's Cases, with each declared refusal provoked by name |
React#
The React stack sets this mock boundary:
- The mocks rule forbids replacing the rendering library, the router, and the query library.
Svelte#
The Svelte stack sets this mock boundary:
- The mocks rule forbids replacing Svelte, SvelteKit, the query library, and the form library.
Standards#
Match test level to risk#
ruleguidanceRequirement A web frontend MUST use Vitest for pure logic, Playwright for navigation and integration, and the route contract for every address.
Rationale Vitest runs beside the module. Playwright runs against a running stack. Fast tests stay fast. Browser runs prove browser behavior. This realizes litespec/frontend/testing#match-test-level-to-risk.
Assert each declared refusal by its code#
ruleguidanceRequirement A web evidence specification for a use case declaring a refusal MUST reach that refusal and assert it by its Result's code.
Rationale The refusal alert carries the code in the rendered page, so the assertion names it directly. This realizes litespec/frontend/testing#assert-each-declared-refusal-by-its-code.
Example The refusal alert carries the code, so the assertion names it.
await expect(refusalFor(page, "failure/orders.not_found")).toBeVisible({ timeout: AFTER_ACTION });Keep mocks at owned boundaries#
ruleguidanceRequirement A web test MUST NOT replace a library its stack section names.
Rationale The React section names the rendering library, the router, and the query library. The Svelte section names Svelte, SvelteKit, the query library, and the form library. This realizes litespec/frontend/testing#keep-mocks-at-owned-boundaries.
Use network mocks for component tests#
ruleguidanceRequirement A web component or logic test that needs HTTP MUST serve its answers through network mocks generated from the published contract.
Rationale A mocked client proves the mock rather than the component. The generated client stays in its production path. This realizes litespec/frontend/testing#use-network-mocks-for-component-tests.
Example The handlers are msw handlers derived from the OpenAPI document and run in the browser worker and the Node server alike. The workspace keeps one mock-generation command that regenerates them.
Prove the module mirror in a structure test#
ruleguidanceRequirement A web frontend calling the API MUST hold a Vitest test resolving modules to backend use cases and naming no refused folder.
Rationale The mirror keeps each specification findable from its folder path after a backend use case changes. This realizes litespec/frontend/testing#prove-the-module-mirror-in-a-structure-test.
Example The structure check resolves each folder name against the backend's Application tree.
test("every module folder names a backend use case, and no folder is named for nothing", () => {
expect(checkModuleStructure(appRoot, applicationRoot)).toEqual([]);
});Run browser checks through the Playwright CLI#
ruleguidanceRequirement A browser suite MUST run through the Playwright CLI, addressable per route and per file.
Rationale The command line is the interface every runner shares: the developer, the drill, and the integration job. A check that runs only inside an editor plugin or a proxy runner cannot be repeated by the next investigator. This realizes litespec/frontend/testing#run-browser-checks-through-the-command-line.
Example One route contract runs on its own line, against the stack already running.
pnpm --filter @shop/webshop exec playwright test --project=routes --grep "cart keeps the route contract"Conventions#
Query by accessible behavior#
conventionguidanceDefault Scope a query to one floorplan through its data-floorplan attribute and address slot content by accessible role and name.
Replacement A project departs from this default through an Exception record.
Rationale The data-floorplan attribute is structural rather than an identifier, so it scopes without breaking the accessible query. This realizes litespec/frontend/testing#query-by-accessible-behavior.
Verification#
| ID | Mark | Evidence |
|---|---|---|
| litespec/frontend/web/testing#match-test-level-to-risk | guidance | Does each web test use Vitest for logic and Playwright for browser behavior? |
| litespec/frontend/web/testing#assert-each-declared-refusal-by-its-code | guidance | Does each web refusal assertion name its Result code in the page? |
| litespec/frontend/web/testing#keep-mocks-at-owned-boundaries | guidance | Does each web mock avoid the libraries its stack section names? |
| litespec/frontend/web/testing#use-network-mocks-for-component-tests | guidance | Does each web HTTP test run through msw handlers from the contract? |
| litespec/frontend/web/testing#prove-the-module-mirror-in-a-structure-test | guidance | Does the Vitest structure test resolve modules and name no refused folder? |
| litespec/frontend/web/testing#run-browser-checks-through-the-playwright-cli | guidance | Does each browser check run through the Playwright CLI per route and per file? |
| litespec/frontend/web/testing#query-by-accessible-behavior | guidance | Does each web query scope by data-floorplan and accessible names? |