Unit tests in a React Native app belong to the logic, not the screens.
Unit testing a React Native app means Jest as the runner, React Native Testing Library for anything that renders, and one decision about scope that most tutorials skip. A unit test is cheap when it covers a function that takes values and returns a value. It gets expensive fast when it covers a screen, because a screen wants a navigator, a store, a server and a few mocked native modules before it will even mount. So the useful answer to what you should unit test is shorter than a tutorial: the arithmetic, the dates, the validation, the parsing and the state machine. Every command and package name below comes from Expo's and React Native's own documentation, read on 10 October 2026. This is one slice of the wider pass at testing before launch.
What follows is what each kind of project already ships with, what you have to install by hand, how to write a component test that survives a refactor, and which tests rot. Then the limit nobody writes down. A green Jest suite cannot tell you the app opens on a phone.
Start hereThe short version
What is worth unit testing when the value is in the screens?
Start with the code that would be wrong in the same way on any platform. Money math: totals, discounts, tax, the function that turns a price in cents into a string. Dates and timezones, so you can prove what counts as today for a user in Auckland. Validation rules, so the form knows what it accepts before a screen does. The reducer or store that decides which state a screen is in. The layer that turns an API response into your own types, error cases included. Permission checks. Retry and backoff. None of those need a renderer, each one has a right answer, and each one fails quietly. That is the profile of a bug a unit test actually catches.
The test that is worth skipping is the one whose assertion would be, in effect, that React rendered. If a test needs the navigator, a provider, a fake server and three mocked modules before it runs, it is not a unit test any more. Price it like an integration test and decide whether you want it at that price.
React Native's own testing guide draws the same lines. Unit tests cover the smallest parts of code, like individual functions or classes. Component tests cover two things, rendering and interaction. End to end tests check that the app works on a device from the user's point of view. The guide is blunt about where to spend: cover the vital parts of your app with end to end tests, naming the authentication flow, core functionality and payments, and use the faster JavaScript tests for the non vital parts. That ordering is the part most testing advice leaves out.
What does a React Native project give you, and what do you add?
It depends which kind of project you have, and the two are not the same. React Native's documentation says the default React Native template ships with Jest, including a preset tailored to the environment, so you can be productive without tweaking configuration and mocks first. A project created with create-expo-app does not. Expo's default template, checked on 10 October 2026, carries two dev dependencies, TypeScript and the React types, and no test script at all. If you read one guide and then open the other project, that gap is where the confusion starts.
On Expo you install it. Expo's own guide gives the command: npx expo install jest-expo jest @types/jest --dev. The middle package is the one doing the work. jest-expo is described as a Jest preset that mocks the native part of the Expo SDK and handles most of the configuration required for your Expo project. Without it, the first import of an Expo module throws and the run never reaches your code. Then two additions to package.json: a test script, and a jest block whose preset is jest-expo. If the project uses TypeScript, add jest to the types array in tsconfig.json so the test globals resolve.
Rendering a component takes one more install, npx expo install @testing-library/react-native --dev. Do not reach for react-test-renderer out of habit. Expo marks it deprecated, because it does not support React 19 and above, and tells you to remove it from a project that still has it. React Native's guide marks React Test Renderer deprecated as well and points at the same replacement.
Two conventions save an argument later. Tests live in a __tests__ directory, either one at the root or one per area sitting beside the code it covers, and Expo is explicit that this is preference rather than a rule. Naming is not preference: the jest-expo preset collects any file ending in -test.ts or -test.tsx, so home-screen-test.tsx is picked up with no further configuration. And when an import from node_modules breaks the run, which it will, the fix is the transformIgnorePatterns regex in the Jest config. It lists the packages Jest should transpile instead of skipping.
Expo, unit testing with Jest, read 10 October 2026
Sort it first
What kind of test is this, really?
Pick the thing you want to be sure about. Most of the cost of a test suite comes from writing the wrong kind of test for the question.
The cart total is right
Pull the arithmetic into a function that takes the line items and returns the subtotal, the discount and the tax. Test that. The bug is in the sum, not in the layout.
How do you test a component without testing the whole screen?
Render the smallest thing that holds the behaviour, then make assertions the way a person would. React Native Testing Library gives you a render function and a set of queries. The first example in Expo's guide is three lines: render the screen, call getByText with the word the screen shows, and the test passes. The version that earns its keep adds interaction. fireEvent.changeText puts text in a field, fireEvent.press taps a button, and then you assert that what a user would now see is on the screen.
React Native's guide is specific about what to assert on and what to leave alone. The rule of thumb is to prefer things users can see or hear, which means rendered text or the accessibility helpers. What to avoid is named just as plainly: assertions on component props or state, and testID queries. The reason is maintenance, and the guide says so. Tests tied to props or state work, but they are not oriented toward how users interact with the component and they tend to break under refactoring. A test that types into a field and presses a button survives a rename, because the path a person takes through the screen did not change.
That also tells you which components deserve a test: the ones with a branch a person can reach. A Save button that stays disabled until the form is valid. A list that shows an empty state instead of a blank screen. An error message that appears when the request fails. A disabled control that becomes enabled. Each of those is a sentence you can write as a test name and check in one render, and each one is a bug somebody has shipped.
A screen whose only job is to lay out data it was handed is not one of those. Neither is navigation wiring, which breaks in ways Jest cannot see, nor anything that depends on a native module you would have to mock into behaving. For a sign-in or a checkout, go up a level and cover it with end to end testing on a device instead. Expo also publishes a separate testing configuration page for Expo Router, because once routing is involved you are writing integration tests and the setup is different.
Which tests pay for themselves, and which ones rot?
Snapshots rot first. React Native's guide lists the weak points without hedging. A snapshot is considered correct at the point it is created, even when the rendered output is actually wrong. When one fails, it is hard for the author or the reviewer to tell an intended change from evidence of a bug, and tempting to pass the update snapshot flag rather than investigate. The conclusion is the line worth keeping: snapshots do not ensure your component render logic is correct, they are merely good at guarding against unexpected changes. So use small ones, and prefer explicit expectations when in doubt. Expo goes further for anything visual and recommends end to end tests instead of snapshot unit tests.
Coverage numbers rot second. Jest will report them: set collectCoverage in the Jest config, use collectCoverageFrom to list what to leave out, and the run writes an HTML report you open in a browser. Read it once, find the file nobody has ever tested, write the two tests that matter. Then stop looking, because the cheapest way to move the number is to render every screen and assert nothing, which buys maintenance and catches no bugs.
The suites that survive are tied to a decision rather than to a layout. A pricing function keeps its tests for years, because the rule it encodes keeps mattering and the test still reads like the rule. A screen test outlives a redesign only when it asserts on text a person reads. A test that asserts a component received a prop called isLoading dies the first time somebody renames it, and takes an afternoon with it.
Two habits decide whether the suite is worth having at all. Run it in continuous integration from the first test, because a suite that only runs on one laptop is a note to self. And make failures readable: a red test you cannot explain costs the same as debugging a crash report with no stack trace, which is to say you are guessing. After that, treat the suite as part of app maintenance and not a launch task. It decays on every dependency bump whether or not anybody is watching, and the version of React that deprecated react-test-renderer is the proof.
Does any of this change if an AI wrote the app?
No, and that is the point of owning the code. A generated project is a real React Native and Expo codebase, so it inherits exactly the setup above: no test runner until you add one, jest-expo for the preset, React Native Testing Library for anything that renders, and the same question about what deserves a test.
Newly is an AI app builder. You describe an app in plain English and it writes a real React Native and TypeScript project you own, with two way GitHub sync, so the tests you add live in your repository rather than inside somebody's dashboard. It runs the app on cloud iOS and Android simulators while it builds, uploads iOS builds to TestFlight, publishes to Google Play internal testing and can build a standalone Android APK. It is $25 a month, with no free tier. It does not submit to the App Store for you, because Apple requires the owner of the content to submit.
What that changes is how you prompt. Ask for the function before you ask for the screen. Put the subtotal, the discount and the tax in one function that takes the cart and returns the amounts, and you get something a test can hold. Ask for a cart screen and the arithmetic arrives spread through a component, where the only test you can write is a slow one. The honest limit is the same for generated code as for handwritten code. A green suite says the logic you wrote tests for is right. It says nothing about whether the app opens on a phone, and no tool can tell you that from a laptop.
Questions people ask about unit testing React Native
Jest. React Native's own testing guide says the default React Native template ships with Jest, including a preset tailored to the environment, so you can write a test without configuring anything first. An Expo project is different: you install it yourself. Expo's guide gives the command, npx expo install jest-expo jest @types/jest --dev, then has you add a test script to package.json and set the Jest preset to jest-expo. Expo describes jest-expo as a Jest preset that mocks the native part of the Expo SDK and handles most of the configuration a project needs.
Build the part you can test, then the screen
Name the rules your app has to get right, keep each one in its own function, and the test file writes itself in an afternoon. The screens can then change as often as they need to.
Start building