Skip to main content

React Native Integration & Best Practices: Testing

Testing Setup

This section provides an overview of the testing setup for React Native applications.

Jest

We use Jest as our primary testing framework. Jest is a popular and well-supported testing framework that is easy to set up and use. The jest config for templates is inside the @archibald/testing package.

React Native Testing Library

For testing React Native components, we use React Native Testing Library. This library provides a set of utilities that make it easy to write and maintain tests for your React Native components.

You can run the app for the basic template on a simulator by running archibald serve -p app -n <ios|android>.

End-to-End (E2E) Testing: Maestro

Maestro is the native E2E runner in Archibald, shipped as @archibald/maestro. It is the native counterpart to Cypress and Playwright on the web, and all three are driven by the same archibald e2e command:

archibald add maestro # installs the integration and sets cli.e2e.framework = "maestro"
archibald e2e # runs the configured runner
archibald e2e -r maestro # override the runner for a single run
archibald maestro # the Maestro-specific command (flows, appId, env)

The active runner lives in archibald.json under cli.e2e.framework ("cypress", "playwright" or "maestro"). The templates ship with "cypress", because their default platform is the web storefront — set it to "maestro", or pass -r maestro, when you are testing the app. See E2E Overview and Maestro.

note

Detox is not part of Archibald — there is no integration package, dependency or configuration for it anywhere in the framework. Earlier revisions of this guide recommended it; Maestro is what is actually wired up.

Mocking Native Modules

Native modules have to be mocked when tests run under Node. The common ones are already handled: @archibald/testing/setup — the first import in every app-side jest.setup.ts — registers mocks for @react-native-async-storage/async-storage and react-native-safe-area-context for you.

// templates/shop/src/app/client/jest.setup.ts
import '@archibald/testing/setup';

import 'app/client/util/unistyles';
import 'react-native-gesture-handler/jestSetup';
import 'shop/client/utils/helpers/testing';

// Only project-specific modules need their own mocks:
jest.mock('expo-auth-session', () => ({
AuthRequest: jest.fn(),
ResponseType: { Code: 'code' },
makeRedirectUri: jest.fn(),
fetchDiscoveryAsync: jest.fn()
}));

jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock'));

AsyncStorage Mocking

Do not re-register this mock — @archibald/testing/setup swaps @react-native-async-storage/async-storage for an in-memory implementation whose methods are jest.fn()s, so you can assert on them directly:

import AsyncStorage from '@react-native-async-storage/async-storage';

expect(AsyncStorage.setItem).toHaveBeenCalledWith('cart', expect.any(String));

Snapshot Testing

Snapshot testing can be a useful tool for testing your UI components. However, it is important to use snapshot tests judiciously. Avoid using snapshot tests for complex components that are likely to change frequently. Instead, focus on using snapshot tests for simple, stable components.

Separation of Concerns in Testing

To maintain a robust test suite, separate UI tests from business logic tests:

  • Business Logic: Test hooks, utilities, and services in isolation using standard Jest. These tests should run fast and not depend on component rendering.
  • UI Components: Use React Native Testing Library to test component interactions and rendering. Focus on user behavior (pressing buttons, entering text) rather than implementation details.