Test Automation for React Native: Practical Guide (2026)

React Native straddles JavaScript and native. Testing it well means covering both sides — the JS logic (unit + integration tests) and the rendered UI (E2E tests that exercise the bridge). This guide c

March 18, 2026 · 3 min read · Testing Guides

React Native straddles JavaScript and native. Testing it well means covering both sides — the JS logic (unit + integration tests) and the rendered UI (E2E tests that exercise the bridge). This guide covers the 2026 recommended stack.

The test pyramid for RN

Unit tests are fast, run in Node without Metro. E2E tests exercise a real app. Integration splits the difference.

Jest + React Native Testing Library

For component-level testing:


import { render, fireEvent } from '@testing-library/react-native';

test('button click submits', () => {
  const onSubmit = jest.fn();
  const { getByText } = render(<SubmitButton onPress={onSubmit} />);
  fireEvent.press(getByText('Submit'));
  expect(onSubmit).toHaveBeenCalled();
});

Run in watch mode during development. Run in CI on every PR. Fast feedback.

Mocking native modules

Native modules (camera, push, deep link handlers) must be mocked for Jest:


jest.mock('@react-native-firebase/messaging', () => ({
  default: () => ({
    requestPermission: jest.fn(() => Promise.resolve(1)),
    getToken: jest.fn(() => Promise.resolve('fake-token')),
  }),
}));

Global mocks in jest.setup.js for modules used everywhere.

Detox

Detox is the RN-native E2E testing framework. It is synchronized with the app's JS runtime — tests wait for network idle and animation completion automatically:


describe('Login', () => {
  beforeEach(async () => { await device.reloadReactNative(); });
  it('should log in with valid credentials', async () => {
    await element(by.id('email')).typeText('test@example.com');
    await element(by.id('password')).typeText('password');
    await element(by.id('submit')).tap();
    await expect(element(by.id('home'))).toBeVisible();
  });
});

Pros:

Cons:

Appium

Cross-platform E2E. Works for RN apps but not RN-aware:


def test_login(driver):
    driver.find_element(AppiumBy.ACCESSIBILITY_ID, "email").send_keys("test@example.com")
    driver.find_element(AppiumBy.ACCESSIBILITY_ID, "password").send_keys("password")
    driver.find_element(AppiumBy.ACCESSIBILITY_ID, "submit").click()
    # Manual wait
    WebDriverWait(driver, 10).until(EC.presence_of_element_located((AppiumBy.ACCESSIBILITY_ID, "home")))

Pros:

Cons:

SUSA for RN

SUSA works with RN as with any other native app. It does not need to know about JS internals — it drives the OS-level rendered UI via ADB (Android) or Appium (iOS). Benefits:


susatest-agent test rnapp.apk --persona adversarial --steps 200

Accessibility testing for RN

RN accessibility:

Snapshot tests cover static semantics. Runtime tests require a screen reader and a human, or SUSA's accessibility_user persona.

Snapshot testing

React's snapshot testing for component trees:


expect(render(<UserCard user={user} />).toJSON()).toMatchSnapshot();

Catches accidental UI changes. Pitfall: snapshots become stale and auto-updated without review. Keep them small and reviewed.

Visual regression for RN

Storybook + Chromatic works well for component-level. Percy / Applitools work at E2E level. SUSA's cross-session visual diff covers the discovered UI surface.

Coverage

Track JS coverage (Jest --coverage). Aim for 70-80% on business logic. 100% is not the goal; meaningful coverage is.

Platform-specific code (iOS-only branches) often has lower coverage — acceptable if the platform-specific path is also tested end-to-end.

CI pipeline


name: RN CI
on: pull_request
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm ci
      - run: npm run lint
      - run: npm test -- --coverage
      - uses: codecov/codecov-action@v3
  e2e-android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: 33
          script: npm run test:detox:android
  e2e-ios:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - run: cd ios && pod install
      - run: npm run test:detox:ios

Common RN bugs to test for

  1. Bridge serialization — passing non-serializable data
  2. setState after unmount — "can't perform state update"
  3. FlatList key warnings — missing keys cause re-render cascades
  4. Image OOM — large images in lists
  5. Keyboard avoidance — KeyboardAvoidingView behavior differs iOS vs Android
  6. Deep link into app from cold start
  7. Push notification deep link

Each deserves a dedicated test.

Fabric / New Architecture

If you are on Fabric (new RN architecture), test migration carefully. Component behavior can change subtly. Snapshot tests detect drift. Full E2E pass on both old and new architectures during migration phase.

RN testing is mature in 2026. A team shipping weekly can have 70% unit coverage, 15% integration, 15% E2E with flake rate under 2%. That is the target.

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free