Unit/component: Vitest (web) or Jest (RN) + React Testing Library. E2E: Playwright (web), Maestro (RN). MSW for API mocks; Storybook for component dev.
RN e2e → Maestro (Expo's recommendation; it archived Detox)
API-heavy tests → MSW so the same mocks serve unit + e2e + dev
Holepunch / Bare app → brittle (the ecosystem's TAP runner) is idiomatic, not a deviation — see RB-E-P2P
unit/integration tests that must exercise real NATIVE modules → react-native-harness (early; pin versions)
native E2E suite too flaky to block CI → treat it as an API problem before a test problem (assert every step, find elements visually, gate new tests on repeated runs) — see the Shopify rebuild in reading
test discipline (what to test, TDD) → agentic-engineering-patterns
Options & tradeoffs
the field considered — and why each one isn’t the default here
network-level API mocking; same mocks reused across unit/e2e and dev
13.5M/wk · ships in 9/34
Playwright (1.62) / Maestro / Detox / Meticulous
e2e: Playwright web — 1.62 rebuilds component testing on stories + galleries and adds `retryStrategy: 'isolated'`; Maestro 2.0 (AI test-healing) is Expo's recommended native e2e (Expo archived Detox; Detox has a 'Copilot' beta); Maestro now bundles an MCP server so coding agents can drive simulators/emulators/devices, inspect UI, and generate E2E flows (claude mcp add maestro -- maestro mcp); Meticulous = record-based AI e2e
37.5M/wk · ships in 9/34
Storybook 10
component workshop; web + RN run side-by-side; Vite 8 + Playwright/Vitest test integration + MCP
agentic toolkit giving an AI assistant control of the iOS Simulator (drive + inspect the running app) to shorten the debug loop; new, niche
react-native-harness (Callstack) — NEW
Jest-style describe/it tests running ON real devices/simulators (iOS/Android/web) with native-module access — the on-device unit/integration layer between Node-Jest and black-box Maestro; v1.3 (2026-05), early
react-test-renderer is deprecated by React core; RNTL v14 runs its own react-reconciler-based test renderer rendering host elements only — don't reach for react-test-renderer in new test code
RN 0.85 (2026-04-07) moved the Jest preset out of the core package — set `preset: '@react-native/jest-preset'` in jest.config.js (was `preset: 'react-native'`). For native e2e, Expo now recommends Maestro (it archived its Detox support docs). Maestro's MCP server (verified vs docs.maestro.dev, 2026-07-07) puts device-driving + E2E-generation in the hands of coding agents — the agent-driven-testing trend consolidating around the tool the ecosystem already recommends. Jest-preset fact verified against the official RN 0.85 release blog. RENDERER FLIP (2026-07-10, verified vs the docs + the mdjastrzebski/test-renderer repo): RN Testing Library v14 (actively maintained) runs on its own react-reconciler-based test-renderer that renders HOST elements only — which is WHY its query model moved to host-element/role queries. The old react-test-renderer package from React core is deprecated — don't reach for it in new test code. PLAYWRIGHT 1.62 (2026-07-30, verified vs the release notes + registry): component testing is rebuilt around STORIES + GALLERIES — a story wraps a component in a scenario, a gallery renders stories on demand, and `mount('components/Expandable/Stateful')` navigates to the gallery and returns a scoped Locator. That closes most of the distance to Storybook's model, so "Storybook for the workshop, Playwright for e2e" is no longer the only sensible split on web. Also lands: an `AbortSignal` `signal` option on most operations (cancel long waits/navigations/assertions), WebP screenshots for visual comparison (quality 100 = lossless), and `testConfig.retryStrategy: 'isolated'`, which defers all retries to the end and runs them one by one in a single worker — the fix for flaky retries that interfere with the rest of the suite.
Canonical reading
Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.
The production evidence behind 'flaky native E2E is a framework problem, not a test problem'. Shopify's largest mobile app ran Appium via WebdriverIO with React Native test IDs since 2023 and had to pull the suite OUT of blocking CI; the rebuild put it back at 98% stability (individual test successes / total runs, up from 50%). Two changes did it. First, a builder-style API that makes flaky tests hard to write: every step carries an assertion (validated both ways — false before the action, true after), reusable named step sequences, and escape hatches deliberately named UNSAFE_ (UNSAFE_timeoutInSeconds, UNSAFE_testID) so they show up in review. Second, elements are found the way a user finds them — each step screenshots and matches visually, PaddleOCR for text and OpenCV for icons (grayscale, color-inverted variants, multiple sizes, adjacency rules to disambiguate duplicates) against Polaris design-system SVGs — which also removes the inspector round-trip from authoring and is why agents write correct tests on the first try. Plus a pre-promotion flakiness gate: a new test runs many times and is rejected above a failure threshold. Residual failures are network flakes and simulators failing to boot.
The bridge between this entry and RB-E-A11Y: querying by data-testid silently hides inaccessible markup, while role/label queries fail exactly when a real assistive-tech user would — so accessible queries are both the better test AND a free a11y audit. Sharpens the Testing-Library philosophy the two Dodds pieces establish.
The foundational testing-strategy essay: maximize confidence per effort by favoring integration tests over mock-heavy unit suites and coverage-chasing. The origin of the Testing-Trophy mindset.
Why tests coupled to internals are brittle (false failures on refactor, false passes on breakage) and why to test behavior the way users use it. The mental model behind Testing Library.
Depth (in-domain rules) is owned by the agentic-engineering-patterns skill — this entry is selection breadth.
The full explanation
The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.
About testing strategy & tooling in React & React Native
Diataxis: Explanation. This page builds understanding of how to think about testing —
the reasoning behind the tool picks. It is not a tutorial, and the discipline (what to test,
TDD, how much) is owned by the agentic-engineering-patterns skill. Read this for the why.
The one idea that organises everything: confidence per effort
Don't start from "unit vs integration vs e2e." Start from the question every test silently
answers: how much confidence does this buy, for how much cost to write and maintain? That
ratio — not dogma about test types — is the organising principle, and it produces the
Testing Trophy: a few end-to-end tests, a strong middle of integration tests, fewer
isolated unit tests, with static typing/linting as the base. Integration tests dominate because
they exercise real component interactions (high confidence) without the brittleness of mock-
heavy unit tests or the slowness of full e2e.
Two corollaries fall straight out, and they drive the tool choices:
Test behaviour, not implementation. Query by role/label like a user; don't assert on
internal state or reach for data-testid as a crutch. Tests coupled to internals fail on
refactors (false negatives) and pass on real breakage (false positives).
Mock at the boundary, not the module. Stub the network, not your own functions, so the
same mocks serve unit, integration, and dev.
The default, and why
Unit/component: Vitest (web) or Jest (RN) + React Testing Library.
E2E: Playwright (web), Maestro (RN). MSW for API mocks; Storybook for component dev.
The platform fork is about fit, not quality: Vitest is faster and Vite-native on the web;
Jest remains the RN default (note: RN 0.85 moved the preset out of core — set
preset: '@react-native/jest-preset', verified against the RN 0.85 blog). React Testing
Library is the constant on both because it enforces the behaviour-not-implementation rule by
construction. For e2e, Playwright owns the web; Maestro is Expo's recommendation for RN
(Expo archived its Detox support). MSW is the keystone that makes the Trophy practical — one
set of network mocks reused across every layer and in dev.
The landscape, and when each one wins
Jest / Vitest — the unit/component runners. Vitest on the web (speed, Vite integration),
Jest on RN (default, ecosystem). Pick by platform, not preference.
React Testing Library (14) — behaviour-first component testing; v14 adds React 19 support and
async APIs. It's not just a tool but a philosophy enforcer — its API makes implementation-
detail testing awkward on purpose.
MSW (Mock Service Worker) — network-level API mocking. The reason it matters: the same
handlers serve unit tests, integration tests, e2e, and local dev — so your mocks don't drift per
layer. Reach for it the moment tests are API-heavy.
Playwright / Maestro / Detox / Meticulous — the e2e tier. Playwright for web; Maestro (AI
test-healing) is the RN recommendation now that Expo archived Detox; Meticulous is record-based
AI e2e. E2e is the smallest, slowest, highest-confidence layer — keep it few and critical-path.
Storybook (10) — the component workshop (web + RN side by side), with Vitest/Playwright test
integration. It's where component development and visual/interaction testing meet.
Radon IDE — RN debugging in VS Code/Cursor (device panel, click-to-inspect, Profiler); a
DX-adjacent aid to the loop rather than a test type.
Tradeoffs and failure modes to name out loud
Inverting the Trophy. Piling up mock-heavy unit tests feels productive but buys little
confidence and breaks on every refactor. Push effort to the integration middle.
Testing implementation details.data-testid everywhere, asserting on state/private
methods — the canonical brittleness source. Query like a user (this also improves a11y; role
queries exercise the accessibility tree — see RB-E-A11Y).
Mocking your own modules instead of the network. Per-test function mocks drift from reality
and from each other; MSW at the boundary keeps them honest.
E2e as the main suite. Slow, flaky-prone, expensive to maintain. It's the thin top of the
Trophy, not the body.
Tests that aren't gated. A suite that doesn't run in CI rots — testing tooling only pays
off inside the RB-E-DX feedback loop.
How it interacts with the rest of the stack
DX (RB-E-DX). Tests only protect you if CI runs them on every PR; the testing tools and
the CI gate are two halves of one loop.
Data (RB-E-DATA). MSW lets you test data-fetching behaviour against realistic network
responses without hitting real servers.
Accessibility (RB-E-A11Y). Role/label-based queries (the RTL default) double as an a11y
check; test-IDs bypass that signal.
Discipline (agentic-engineering-patterns).What to test, when to write tests first, and
how much is owned there — this page is which tools, that skill is the practice.
In one paragraph
Choose tests by confidence per effort, which yields the Testing Trophy: a strong integration
middle, few e2e, unit where isolation helps, types/lint as the base. Test behaviour, not
implementation (React Testing Library enforces it) and mock the network, not your modules
(MSW, reused across every layer). Tooling forks by platform — Vitest/Jest + RTL for components,
Playwright (web) / Maestro (RN) for e2e — and none of it pays off unless CI runs it
(RB-E-DX); the discipline of what-to-test lives in agentic-engineering-patterns.
See also: RB-E-DX (CI gates the suite), RB-E-DATA (MSW + data-fetching tests), RB-E-A11Y
(role queries as an a11y signal). TDD / what-to-test discipline: the agentic-engineering-patterns
skill.