Jest 62,362 (https://github.com/jestjs/jest 45,465 ) (MIT) has shipped with React Native 36,878 's templates from the start. In an Expo 6,418 project, install it with jest-expo, the preset matched to the SDK, plus React Native Testing Library 3,421 :
npx expo install jest-expo jest @types/jest -- --save-dev
npm install --save-dev @testing-library/react-native test-renderer@~1.2.0expo install chose jest-expo 57.0.5 and jest 29.7; npm 2,036 's latest Jest is 30.5, but jest-expo 57 still builds on Jest 29. Add "test": "jest" to scripts and a configuration file:
// Packages that publish untranspiled ES modules must go through Babel too
const esm = ['react-native', '@react-native', '@react-native-community', 'expo', '@expo',
'react-navigation', '@react-navigation', 'standard-navigation', '@formatjs'];
module.exports = {
preset: 'jest-expo',
setupFiles: ['./jest.setup.ts'],
transformIgnorePatterns: [`/node_modules/(?!(\\.pnpm|${esm.join('|')}))`],
testPathIgnorePatterns: ['/node_modules/', '/e2e/'], // Detox runs those on a device
};The preset compiles TypeScript and JSX with babel-preset-expo, as Metro does, mocks the native side of React Native (through @react-native/jest-preset) and of every Expo module, and resolves .android.tsx or .ios.tsx files (Testing Android Paths). transformIgnorePatterns is the setting you will fight with. Jest skips Babel 41,624 for node_modules, but many React Native packages publish ES modules that Node cannot load, so the pattern names packages to transform anyway. The plural-rules polyfill of i18next was missing, and the cart test failed with SyntaxError: Cannot use import statement outside a module in node_modules/@formatjs/intl-pluralrules/polyfill.js. Setting the option replaces the preset's list rather than extending it, so a first attempt that named only a few packages failed next inside Expo Router 6,418 's standard-navigation. And remember that a test runs in Node's V8 86,723 , not Hermes 11,328 , with everything native mocked: a green run proves your logic, not the app.