React Native ships with Jest pre configured. That's a good start, but it's only one piece of a testing stack that needs to cover everything from a single utility function to a full checkout flow running on a real Samsung phone.
The React Native docs cover basics well. The Jest tutorial for React Native walks through setup. This guide goes further into practical trade-offs, layers most teams skip, and why testing RN apps is structurally harder than testing web apps.
Why React Native testing is uniquely hard
React Native isn't a web app and it isn't a fully native app. It's JavaScript running on a separate thread that communicates with native platform code to render actual native views. This architecture creates testing problems that don't exist in either world.
The JS-native boundary. In old bridge architecture, every call from JavaScript to native code was serialized as JSON and sent asynchronously. A state update in JS didn't immediately update screen it had to cross bridge and get rendered by native thread. The New Architecture (JSI + Fabric + TurboModules) eliminates this serialization, enabling synchronous JS-to-native calls via direct C++ bindings. But whether you're on old bridge or JSI, Jest runs in Node.js on your laptop it doesn't boot native runtime, doesn't render native views, and doesn't load TurboModules. When you mock react-native in Jest, you're replacing entire native layer with stubs.
Platform-specific rendering. A <Text> component renders via UIKit on iOS and Android's TextView on Android. They handle line-breaking, font metrics, and text overflow differently. A label that fits on one line on iOS might wrap to two lines on Android and your Jest test, running in Node.js, renders neither.
Native module dependencies. Camera, biometrics, push notifications, geolocation, Bluetooth these all depend on native code that Jest can't execute. The standard workaround is mocking, but mocks only test what you told them to return, not what real module returns on a real device.
OEM skins. Samsung's One UI, Xiaomi's HyperOS, Oppo's ColorOSÂ each alters navigation bars, permission dialogs, battery behavior, and font scaling. Your JavaScript is identical. The native rendering layer underneath it isn't.
A complete testing strategy for React Native has to account for all of this. No single test type covers everything. Each layer catches a different class of bugs.
Layer 1: static analysis
Static analysis catches errors before you run any code. React Native projects come with ESLint and TypeScript out of box.
ESLint flags unused variables, missing dependencies in hook arrays, inconsistent formatting, and common anti-patterns. It runs in your editor as you type.
TypeScript catches type mismatches at compile time. If your API returns { price: number } but your component expects { price: string }, TypeScript flags it before you even save file.
What it catches: Typos, type mismatches, unused imports, missing hook dependencies. Roughly 30-40% of bugs that would otherwise surface during testing.
What it misses: Everything that requires running code logic errors, rendering bugs, integration failures.
Setup effort: Nearly zero if you started from React Native template. ESLint and TypeScript are already configured.
Layer 2: unit tests with Jest
Unit tests verify smallest pieces of your code individual functions, utility modules, reducers, formatters. They run in milliseconds.
The discount function going negative. A price formatter choking on zero. A date parser returning `NaN` for edge-case formats.
What it misses: Anything involving UI rendering, navigation, native modules, or component interaction. A cart total function that works perfectly in isolation might produce wrong result when component passes it data in an unexpected shape.
Speed: Thousands of tests in seconds. This is layer where you get fastest feedback.
Layer 3: component tests with React Native Testing Library
Component tests verify that your React components render correctly and respond to user interaction way they should. React Native Testing Library (RNTL) is standard for this in 2026.
RNTL encourages testing from user's perspective you query by text, accessibility label, or role, not by internal component state or prop values. This means your tests don't break when you refactor internals.
`react-test-renderer` is [deprecated as of React 19](https://react.dev/blog/2024/04/25/react-19-upgrade-guide). If you're still using it, migrate to RNTL. The deprecated library doesn't support React 19's concurrent features and won't receive updates.
What it catches: Rendering errors a button that doesn't appear, a validation message that's missing, an onPress handler that isn't connected. The test above catches if someone accidentally removes validation logic or breaks submit handler.
What it misses: How component looks on an actual screen. RNTL doesn't render pixels it tests component tree. A button that works in RNTL might be invisible on a real device because it's positioned off-screen or covered by another element.
Layer 4: snapshot tests
Snapshot tests capture a serialized representation of a component's rendered output and compare it against a saved baseline. If output changes, test fails.
The first time this runs, Jest saves output as a .snap file. On subsequent runs, it compares current output to saved snapshot. If a developer changes Header's padding, adds a new icon, or modifies text style, snapshot test fails flagging change for review.
When snapshots help: On stable, rarely-changed components a header, a footer, a brand badge. The snapshot catches accidental regressions to components nobody is actively working on.
When snapshots hurt: On actively-developed components where UI changes frequently. Every styling tweak, every text update, every layout adjustment triggers a snapshot failure. Developers start running jest -u to auto-approve all snapshot updates without reviewing them. At that point, snapshots test nothing they just add noise.
The honest take: Use snapshots sparingly. A handful of snapshots on your most stable, shared components is useful. Snapshots on every component in a fast-moving codebase creates a maintenance tax that erodes trust in test suite.
Layer 5: integration tests
Integration tests verify that multiple parts of your app work together a component that fetches data from an API, a screen that navigates to another screen, a form that saves to local storage.
In React Native ecosystem, integration tests live in an awkward middle ground. Jest can run them if you mock network layer (using tools like MSW or jest.mock), but you're still running in Node.js you're not testing native runtime.
, renders it, handles user interaction, and computes derived state (total). If API response shape changes or price calculation breaks when combined with rendering logic, this test catches it.
What it misses: The real API. The real network. The real native rendering. The mocked server returns exactly what you told it to real backend might return a different data shape after a deploy, and this test won't know.
The honest take on native module integration: Most RN teams mock every native dependency (biometrics, camera, geolocation, push notifications) and never validate that mock matches reality. A mock that returns { biometryType: 'FaceID' } while real module on a Pixel returns { biometryType: 'Fingerprint' } will pass every test and break in production. If you have native modules that are business-critical (payments, auth, biometrics), write at least a few smoke tests that run on a real device to validate module's actual behavior.
Layer 6: E2E tests on real devices
End-to-end tests walk through complete app from launch to a completed user flow on a real device or emulator. This is most expensive layer and one most teams under-invest in.
Detox is standard for RN E2E testing. It's a grey-box framework built by Wix that synchronizes with React Native's JS event loop, pending network requests, and animations. When it works, flakiness is below 2%. When it doesn't  Jupiter, a fintech, found Detox succeeded only 2 out of 10 times on physical devices in September 2025, with animation sync issues on other 8.
Appium is alternative black-box, cross-platform, language-agnostic. But it doesn't understand RN internals, so flakiness on RN apps runs 15-25% without heavy tuning.
Both run on emulators by default. Emulators run stock Android. They don't reproduce Samsung's One UI navigation insets, Xiaomi's Security popup on first launch, or real GPU rendering differences. A test that passes on a stock emulator can fail on a real Samsung Galaxy A14 because system font scaling is 1.3x by default and your button label truncates.
Drizz addresses real-device gap. Tests are written in plain English "Tap on Log in," "Type 'user@test.com' in email field," "Validate 'Welcome' is visible." Vision AI reads screen visually instead of finding elements by testID, so UI changes and OEM-specific rendering differences don't break tests. The popup agent handles manufacturer dialogs automatically. Tests run on real Android and iOS devices. Teams go from 15 tests per month to 200, with flakiness dropping from ~15% to ~5%. For a detailed comparison of RN-specific E2E frameworks, see Detox vs Appium vs Drizz.
How layers fit together
The testing pyramid for React Native looks like this:
Bottom (run on every commit): Static analysis (ESLint + TypeScript) catches type and syntax errors instantly. Unit tests (Jest) validate business logic in milliseconds. Component tests (RNTL) validate rendering and interaction in seconds.
Middle (run on every PR or nightly): Integration tests validate multi-component flows with mocked APIs. Snapshot tests guard stable components against accidental regressions.
Top (run before release): E2E tests on real devices validate full user flow across actual device matrix OEM skins, manufacturer popups, font scaling, GPU rendering, network conditions.
Push bugs down. If a bug can be caught by a unit test, don't wait for E2E to find it. Reserve expensive layers for bugs that only they can catch: integration seams, native module behavior, and real-device rendering.
FAQ
What testing framework does React Native use?
React Native ships with Jest by default. Most teams add React Native Testing Library for component tests and Detox or Drizz for E2E. ESLint and TypeScript handle static analysis.
Is react-test-renderer still supported?
No. It's deprecated as of React 19 and won't receive updates. Migrate to React Native Testing Library, which provides a better API and supports concurrent rendering features.
How do I test React Native apps on real devices?
Detox supports physical devices but requires complex native build configuration. Drizz runs plain-English tests on real Android and iOS devices using Vision AIÂ no testIDs, no native build setup needed.
What's difference between RNTL and Enzyme for React Native?
RNTL tests from user's perspective (query by text, role, label). Enzyme tests implementation details (query by props, state). Enzyme has fallen out of favor and doesn't support React 18+ well. Use RNTL.
How many tests should a React Native app have?
Follow pyramid: many unit tests (fast, cheap), fewer component tests, fewer integration tests, and a small number of high-value E2E tests covering login, checkout, payment, and onboarding.
Can I use same tests for Android and iOS?
Jest, RNTL, and snapshot tests run in Node.js they're platform-agnostic. Detox requires separate builds for each platform. Drizz runs same plain-English test on both Android and iOS without modification.
‍


