Browser and mobile
Browser and mobile tests are the most expensive tests a team owns, so the tooling choice is mostly about diagnosis: how quickly a failure can be understood without reproducing it. That is why the trace viewer, not the API, is the argument.
Playwright
Section titled “Playwright”The default for browsers.
Auto-waiting. Actions wait for the element to be actionable before
interacting. This removes the largest single source of flakiness in browser
suites — the sleep standing in for synchronisation. See
determinism.
The trace viewer. The reason to choose it. A trace records every action with a DOM snapshot, the network, the console and a screenshot at each step; the viewer lets someone step through the failure and inspect the page as it was, from an artefact, with no environment. It converts most “let me run it locally” into a two-minute read. Record traces on first retry, keep them for failures.
Real cross-browser. Chromium, Firefox and WebKit, driven the same way. Two engines on the critical journeys is usually the right coverage — see the strategy on what is deliberately not tested.
Parallel by default, with isolated browser contexts. Each test gets a clean profile, clean storage, clean cookies, which removes the other large source of browser flakiness.
Network interception, so a journey can be tested against a controlled backend response — including the error responses that are hard to produce for real.
Addressing elements
Section titled “Addressing elements”The single decision that determines whether a browser suite survives a redesign, and it is a discipline rather than a tool.
Address by role and accessible name.
getByRole('button', { name: 'Place order' })It survives a restyle, a class rename and a DOM restructure, because it is bound to what the element is rather than to where it sits. And it fails when the element stops being reachable by an assistive technology — an accessibility regression caught in the ordinary pipeline, on the merge that introduced it. See accessibility.
Fall back to an explicit test id where no accessible name exists. data-testid
is a contract with the test suite; it is deliberate and it is greppable.
Never CSS classes, DOM position, or XPath. .btn-primary:nth-child(2) is a
test that fails on the next redesign and passes on the next bug.
The rest of the browser stack
Section titled “The rest of the browser stack”axe-core, via @axe-core/playwright, for the automated accessibility rules at
journey level. A few lines, run at key points in each critical journey.
Visual regression — Playwright’s built-in screenshot comparison, or a hosted service for cross-platform rendering. Worth it for a design system, where a component’s appearance is the deliverable; expensive elsewhere, because font rendering and antialiasing differ per platform and produce false failures that teach the team to approve diffs without looking. If it is adopted, run it on components in a fixed container image, not on full pages across environments.
Testing Library for component-level tests. Same addressing philosophy, in process, milliseconds — most of what people write browser tests for belongs here. See unit and component tooling.
Mobile
Section titled “Mobile”Maestro for the flow-level tests. Declarative YAML flows, tolerant of timing by design, and low enough friction that the tests actually get written. The right default for the small set of critical mobile journeys.
Appium when a matrix of real devices and OS versions is genuinely required, or when one suite has to drive both platforms. More powerful, considerably more setup, and it is a project rather than a decision.
XCUITest and Espresso — the native frameworks. Fastest and most stable on their own platform, and the right choice for a team building for one platform only; two suites for two platforms otherwise.
A device cloud for the matrix. Real devices for the release campaign, emulators for the pipeline.
The mobile version of the rule from end-to-end applies with more force, because mobile UI tests are slower and flakier than browser ones: a handful of critical flows, and everything else at view-model level in process.