frontend-testing
Use when deciding how a frontend feature is to be verified, or when a frontend defect slipped through: which test layer catches which kind of defect (logic, component, accessibility, contract, journey
SKILL.mdskills/frontend-testing/SKILL.md
GitHubfrontend-testing
Step 6 and step 8 of the pipeline (WORKFLOW.md), next to skills/tdd (the doctrine and the
data-test-* selector convention), skills/testing-anti-patterns (what makes a test worthless) and
skills/qa-exploratory-testing (the human pass). Those say how to write a test and when. This block says
which layer is owed for which kind of defect on a user interface, because a frontend breaks in ways no
single layer sees. It names no framework and no tool, and it sets no coverage figure.
When
A frontend feature is planned or reviewed and the question is "how will we know it works", a defect is found in production or in review that the suite should have caught, or a project sets up its test pipeline for the first time.
Steps
List the ways this feature can be wrong, in the user's terms: wrong value shown, wrong state after an error, unreachable by keyboard, broken at a size, broken in another browser, looks different, breaks when the API changes, slow, fails only on a phone. Each item is a defect class.
Give each defect class to the lowest layer that can catch it. The table is the default; a class owned by no layer is a hole to say out loud.
Defect class Layer that catches it What it needs Wrong logic, formatting, derived state Unit test of the pure function or store no browser Component renders the right states from its inputs, emits the right events Component test (a real browser engine if it depends on layout, focus or scroll; a DOM emulation otherwise) data-test-*selectors,skills/tddMissing name, invalid ARIA, bad structure, duplicate ids An accessibility rule engine run inside the component test and again on the journeys the engine's report, read; it finds a fraction ( skills/accessibility§2.12)Keyboard path, focus order, announcements, zoom A manual pass with keyboard and screen reader on the critical journeys skills/qa-exploratory-testing,skills/accessibilityThe front end and the API drifting apart A consumer-driven contract test: the front end records what it relies on, the API's pipeline verifies it the contract-first spec of skills/api-designA user journey that crosses pages and services End-to-end test of the few journeys that carry the business at least two rendering-engine families Looks wrong, layout moved, theme broken Visual regression on stable fixtures pinned fonts, fixed data, frozen clock, animations off Touch, virtual keyboard, safe areas, low-end performance A pass on a real device before release emulation does not reproduce these Weight, load and interaction cost A budget check in the pipeline skills/webperf§4.10What no test imagined Browser error reporting in production release label and source maps ( skills/webperf§6.5), personal data scrubbed (business/data-protection),skills/observability-instrumentationWrite each test at that layer and no higher. A rule about a price format is a unit test, not a journey; a journey that exists to prove the format is the slow, flaky version of a unit test.
Keep end-to-end tests few, about journeys, and deterministic.
- A journey is something a user finishes (sign in, buy, export), asserted on its outcome; not every branch of every form.
- Waits are on conditions (an element, a response, a state), never fixed sleeps. Each test creates the data it needs and leaves none behind; tests do not depend on order or on each other.
- Run them on the engine families that matter to the audience (Chromium-based, Gecko-based, WebKit-based at least once before release), because layout, form controls, date inputs, focus rules and many newer features differ. The project's config lists the engines, and a family left out is recorded as left out.
- Selectors are the
data-test-*attributes ofskills/tdd, not CSS classes or visible text that a redesign or a translation changes. - When the runner is Playwright Test, its locators, waiting, saved sign-in state, network mocking, fixtures,
retries and traces are in
references/01-playwright.md(pinned to 1.63).
Make visual tests stable before trusting them. A visual test that fails for no reason is deleted within a month. Fix the data, freeze the clock and randomness, disable animation, load the exact fonts from the repository, and render in the same container image everywhere. Snapshot components in their states rather than whole pages. A human reviews each change and approves it deliberately; an automatic "update all" turns the layer into a rubber stamp. It complements assertions and never replaces them.
Place each layer by cost. Fast layers (static checks, unit, component, accessibility engine) run on every push. The slow ones (end-to-end across engines, visual regression, full budget measurement) run on merge or on a schedule, with a rule that a failure blocks release. A real-device pass is a release step with an owner.
A flaky test is a defect with a deadline. Quarantine it the first time (skip it visibly, record an owner and a date), find the cause (shared data, timing, order, environment), fix or delete. A suite people re-run until green proves nothing. This is
skills/testing-anti-patternsapplied to the pipeline.Optionally, measure whether tests assert. Mutation testing changes the code and checks that a test fails; it is slow, so aim it at logic-heavy pure modules, not at components. Coverage is a signal, never a target (
skills/testing-anti-patterns).
Output / checkpoint
For a feature: the defect classes, the layer owning each, and the tests added at each layer. For a missed
defect: the class it belonged to, why the owning layer did not catch it, and the test now added there. The
checkpoint is the one skills/tdd already writes; this block adds no new one.
Guardrails
- No tool, framework or threshold is imposed. A project picks its runner and engines; this block asks only that the choice be recorded.
- A layer that never fails is not a layer. If the accessibility engine or the visual diff has never caught anything, check that it runs and that it can fail.
- Never test the framework. Assert what the user sees and what the contract promises.
- Never replace the manual pass with the tool. Rule engines and screenshots cannot judge a name, a focus order or a layout's meaning.
- A contract test is not an integration test with a mock: the mock drifts, the contract is verified by the other side.
Mechanical checks
grep -nE 'axe|a11y|accessib' package.json
grep -rnE 'chromium|firefox|webkit' playwright.config.* wdio.conf.* 2>/dev/null
grep -rnE 'toHaveScreenshot|matchScreenshot|toMatchImageSnapshot' tests
grep -rnE 'Sentry\.init|Bugsnag\.start|datadogRum|window\.onerror' src
grep -rnE 'pact|contract' tests
grep -rnE 'waitForTimeout|sleep\(|cy\.wait\([0-9]' tests
grep -rnE '\.(skip|only)\(' tests
- The first confirms an accessibility engine is a dependency and the pipeline file runs it (grep the CI config for the same words).
- The second lists the engines in the end-to-end config; the answer is compared with the recorded list.
- Error reporting is initialised with a release identifier (read the call).
- Fixed waits and left-over
only/skipin tests are findings. - The runner and file names above vary by project; adapt the patterns, keep the intent.
Origin
The list of verification topics (accessibility in the pipeline, multi-engine runs, visual regression,
real-device passes, consumer contract tests, error monitoring, mutation testing) comes from reading the
public Front-End-Checklist repository (README and package metadata declare MIT; no licence file is
present, so only the topics were used, not its sentences), on 2026-10-02. The layer-to-defect table, the
placement by cost and the flaky-test policy are ours, following skills/tdd and
skills/testing-anti-patterns. Facts about contract testing follow the consumer-driven contract pattern as
documented by its practitioners; the WAI and WCAG pages are the source for what automated checks cannot
see. Deliberately not taken: a coverage percentage, a named test runner or screenshot service, and mock
guidance (already in skills/testing-anti-patterns). A separate e2e-testing block was not written: the
end-to-end doctrine is skills/tdd and the stability rules are step 4 here. Written, not yet run on
real work.
The Playwright reference (references/01-playwright.md) is rewritten from the runner's own documentation
(microsoft/playwright, docs/src, Apache-2.0), read 2026-10-02 at the 1.63 release notes: best practices,
locators, auto-waiting, assertions, authentication, mocking, fixtures, retries, parallelism, timeouts, trace
viewer, snapshots, web server and accessibility testing. No sentence or example is copied. Facts that move,
pinned to 1.63: the default timeouts (test 30 s, assertion 5 s), the trace modes, the locator list. Not read:
component testing, the test-agents pages, the reporter API, and the other language bindings. Refresh with
skills/source-freshness on the next minor.