Quick Start

React Native Harness allows you to write Jest-style tests that run directly in your React Native app with full access to native modules. Let's get you set up in minutes.

Prerequisites

React Native Harness provides a dedicated react-native-harness command that wraps the Jest CLI under the hood, giving you all the powerful features of Jest including watch mode, code coverage, filtering, and more. This means you get the full Jest experience with seamless integration for running tests in real native environments.

Make sure you have Jest installed in your project. Most React Native projects come with Jest by default, so you should be all set! If Jest isn't installed yet, check out the Jest Getting Started guide to get it up and running.

Installation

Install React Native Harness as a development dependency:

npm
yarn
pnpm
bun
npm install react-native-harness

Configuration

1. Create Harness Configuration

Create a rn-harness.config.mjs file in your project root:

const config = {
  entryPoint: './index.js',
  appRegistryComponentName: 'YourAppName',

  runners: [
    {
      name: 'android',
      platform: 'android',
      deviceId: 'Pixel_8_API_35', // Your Android emulator name
      bundleId: 'com.yourapp', // Your Android bundle ID
    },
    {
      name: 'ios',
      platform: 'ios',
      deviceId: 'iPhone 16 Pro', // Your iOS simulator name
      bundleId: 'com.yourapp', // Your iOS bundle ID
      systemVersion: '18.0',
    },
  ],
};

export default config;
App Integration

The entryPoint and appRegistryComponentName properties tell React Native Harness how to locate and integrate with your React Native app. See the Configuration page for detailed information about these and all other configuration options.

2. Update Metro Configuration

Update your metro.config.js so React Native Harness will be able to use it to bundle its tests:

const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const { withRnHarness } = require('react-native-harness/metro');

const defaultConfig = getDefaultConfig(__dirname);

const customConfig = {
  // Your existing Metro config
};

module.exports = withRnHarness(mergeConfig(defaultConfig, customConfig));
Safe for Production

The withRnHarness function is a noop when you're not running Harness tests, so you don't need to worry about it affecting your app in production. It only kicks in when running tests!

3. Configure Jest

Update your jest.config.js to use the React Native Harness preset:

module.exports = {
  preset: 'react-native-harness',
};
Running Both Classic and Harness Tests

If you want to run both traditional Jest tests and Harness tests in the same app, you can use Jest's projects feature. This lets you separate your regular unit tests from your in-app Harness tests:

module.exports = {
  projects: [
    // Classic Jest tests
    {
      preset: 'react-native',
      testMatch: ['**/__tests__/**/*.test.{js,ts,tsx}'],
    },
    // Harness tests
    {
      preset: 'react-native-harness',
      testMatch: ['**/__tests__/**/*.harness.{js,ts,tsx}'],
    },
  ],
};

This way, you can keep your fast unit tests alongside your comprehensive in-app integration tests, and Jest will run them all together!

Writing Your First Test

Create a test file with a .harness.js or .harness.ts extension. Import testing utilities from react-native-harness instead of Jest:

// MyComponent.harness.js
import {
  describe,
  it,
  expect,
  beforeEach,
  afterEach,
} from 'react-native-harness';
import { NativeModules, Platform } from 'react-native';

describe('My First Harness Test', () => {
  beforeEach(() => {
    console.log('Setting up test...');
  });

  afterEach(() => {
    console.log('Cleaning up test...');
  });

  it('should access platform information', () => {
    expect(Platform.OS).toMatch(/ios|android/);
    expect(typeof Platform.Version).toBe('string');
  });

  it('should have access to native modules', () => {
    // Test real native modules - no mocks!
    expect(NativeModules).toBeDefined();
    expect(typeof NativeModules).toBe('object');
  });

  it('should run async tests', async () => {
    const result = await Promise.resolve('native testing');
    expect(result).toBe('native testing');
  });
});

Available Testing APIs

React Native Harness provides Jest-compatible APIs through react-native-harness:

Test Structure

  • describe(name, fn) - Group related tests
  • it(name, fn) or test(name, fn) - Define individual tests
  • it.skip() or test.skip() - Skip tests
  • it.only() or test.only() - Run only specific tests

Lifecycle Hooks

  • beforeAll(fn) - Run once before all tests
  • afterAll(fn) - Run once after all tests
  • beforeEach(fn) - Run before each test
  • afterEach(fn) - Run after each test

Assertions

Create expectations using expect(value) with matchers:

  • .toBe() - Strict equality
  • .toEqual() - Deep equality
  • .toBeTruthy() - Truthy values
  • .toBeFalsy() - Falsy values
  • .toContain() - Array/string contains
  • .toHaveLength() - Length check
  • .toMatch() - Regex match
  • .toBeInstanceOf() - Instance type
  • .toHaveProperty() - Object property

...and many more Jest-compatible matchers.

Building Your App

Before running tests, you need to build your app in debug mode and install it on your emulator or simulator. React Native Harness will inject itself into your existing app, taking over access to all included native modules.

Follow your framework's documentation to build and install the debug variant:

React Native Community CLI

npm
yarn
pnpm
bun
npm react-native run-android
npm
yarn
pnpm
bun
npm react-native run-ios

Expo

npm
yarn
pnpm
bun
npm expo run:android
npm
yarn
pnpm
bun
npm expo run:ios

Rock

npm
yarn
pnpm
bun
npm rock run:android
npm
yarn
pnpm
bun
npm rock run:ios

Running Tests

Now you're ready to run your tests! Use the react-native-harness command with the --harnessRunner flag to specify which platform to run on:

npm
yarn
pnpm
bun
npm react-native-harness --harnessRunner android
npm
yarn
pnpm
bun
npm react-native-harness --harnessRunner ios
Default Runner

If you don't provide the --harnessRunner flag, React Native Harness will use the runner specified in the defaultRunner property of your rn-harness.config.mjs file. If no defaultRunner is configured, you must explicitly provide the --harnessRunner flag.

Since the react-native-harness command wraps Jest CLI under the hood, you get all the powerful Jest CLI features out of the box:

  • Watch mode: react-native-harness --watch --harnessRunner android to automatically rerun tests when files change
  • Code coverage: react-native-harness --coverage --harnessRunner android to see how much of your code is tested
  • Run specific tests: react-native-harness MyComponent.harness --harnessRunner android to run only certain test files
  • Filter by name: react-native-harness --testNamePattern="specific test" --harnessRunner android to run tests matching a pattern

What's Next?

Congratulations! You now have React Native Harness set up and can write tests that run in real native environments.

Need React or React Native expertise you can count on?

Need to boost your app's performance?
We help React Native teams enhance speed, responsiveness, and efficiency.