Configuration

React Native Harness can be configured through a configuration object that defines various aspects of your testing setup.

The most basic configuration would, assuming you support both iOS and Android platforms, look like this:

rn-harness.config.mjs

import {
  androidPlatform,
  androidEmulator,
} from '@react-native-harness/platform-android';
import {
  applePlatform,
  appleSimulator,
} from '@react-native-harness/platform-apple';

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

  runners: [
    androidPlatform({
      name: 'android',
      device: androidEmulator('Pixel_8_API_35'),
      bundleId: 'com.yourapp',
    }),
    applePlatform({
      name: 'ios',
      device: appleSimulator('iPhone 16 Pro', '18.0'),
      bundleId: 'com.yourapp',
    }),
  ],
};

export default config;

Entry Point and App Component

React Native Harness needs to know how to locate and integrate with your React Native app.

entryPoint

The path to your React Native app's entry point file.

{
  entryPoint: './src/main.tsx',
}

appRegistryComponentName

The name of the component registered with React Native's AppRegistry.

// In your app's entry point
import { AppRegistry } from 'react-native';
import App from './App';

AppRegistry.registerComponent('MyApp', () => App);
// In your rn-harness.config.mjs
{
  appRegistryComponentName: 'MyApp',
}
Expo

For Expo projects, the entryPoint should be set to the path specified in the main property of package.json. The appRegistryComponentName is typically set to main for Expo apps.

All Configuration Options

OptionDescription
entryPointRequired. Path to your React Native app's entry point file.
appRegistryComponentNameRequired. Name of the component registered with AppRegistry.
runnersRequired. Array of test runners (at least one required).
defaultRunnerDefault runner to use when none specified.
bridgeTimeoutBridge timeout in milliseconds (default: 60000).
bundleStartTimeoutBundle start timeout in milliseconds (default: 15000).
maxAppRestartsMaximum number of app restarts when app fails to report ready (default: 2).
resetEnvironmentBetweenTestFilesReset environment between test files (default: true).
webSocketPortWeb socket port for bridge communication (default: 3001).
detectNativeCrashesDetect native app crashes during test execution (default: true).
crashDetectionIntervalInterval in milliseconds to check for native crashes (default: 500).
disableViewFlatteningDisable view flattening in React Native (default: false).
coverageCoverage configuration object.
coverage.rootRoot directory for coverage instrumentation (default: process.cwd()).
forwardClientLogsForward console logs from the app to the terminal (default: false).

Test Runners

A test runner defines how tests are executed on a specific platform. React Native Harness uses platform-specific packages to create runners with type-safe configurations.

For detailed installation and configuration instructions, please refer to the platform-specific guides:

Default Runner

When you have multiple runners configured, you can specify which one to use by default when no runner is explicitly specified in the CLI command.

import {
  androidPlatform,
  androidEmulator,
} from '@react-native-harness/platform-android';
import {
  applePlatform,
  appleSimulator,
} from '@react-native-harness/platform-apple';

const config = {
  runners: [
    androidPlatform({
      name: 'android',
      device: androidEmulator('Pixel_8_API_35'),
      bundleId: 'com.myapp',
    }),
    applePlatform({
      name: 'ios',
      device: appleSimulator('iPhone 16 Pro', '18.0'),
      bundleId: 'com.myapp',
    }),
  ],
  defaultRunner: 'android', // Will use Android runner by default
};

If no defaultRunner is specified, you must explicitly provide the --harnessRunner flag when running tests:

# With default runner set (uses the runner specified in defaultRunner)
react-native-harness

# Without default runner (explicit runner required)
react-native-harness --harnessRunner android
react-native-harness --harnessRunner ios

Bridge Timeout

The bridge timeout controls how long React Native Harness waits for communication between the test runner and the React Native app. This is particularly important for slower devices or complex test setups.

{
  bridgeTimeout: 120000,  // 2 minutes in milliseconds
}

Default: 60000 (60 seconds) Minimum: 1000 (1 second)

Increase this value if you experience timeout errors, especially on:

  • Slower devices or simulators
  • Complex test suites with heavy setup

Bundle Start Timeout

The bundle start timeout controls how long React Native Harness waits for Metro to start bundling after the app is restarted. This timeout is used in conjunction with the app restart mechanism to detect when an app has failed to report ready.

{
  bundleStartTimeout: 30000,  // 30 seconds in milliseconds
}

Default: 15000 (15 seconds) Minimum: 1000 (1 second)

This timeout works with the maxAppRestarts setting to automatically restart the app when it fails to communicate with the test harness. If no bundling activity is detected within this timeout period, the app will be restarted automatically.

Maximum App Restarts

The maximum app restarts setting controls how many times React Native Harness will attempt to restart the app when it fails to report ready within the configured timeout periods.

{
  maxAppRestarts: 3,  // Allow up to 3 restart attempts
}

Default: 2 Minimum: 0

When set to 0, automatic app restarting is disabled. Higher values provide more resilience against flaky test environments but may increase test execution time. The app will be restarted when:

  • No bundling activity is detected within the bundleStartTimeout period
  • The bridge fails to establish communication within the bridgeTimeout period

Web Socket Port

The port used for the WebSocket bridge communication between the CLI and the device.

{
  webSocketPort: 4000,
}

Default: 3001

Change this if port 3001 is already in use on your system.

Environment-Specific Configurations

You can create different configurations for different environments:

rn-harness.config.mjs

import {
  androidPlatform,
  androidEmulator,
} from '@react-native-harness/platform-android';

const isDevelopment = process.env.NODE_ENV === 'development';
const isCI = process.env.CI === 'true';

const config = {
  runners: isDevelopment
    ? [
        // Development runners with local simulators
        androidPlatform({
          name: 'android',
          device: androidEmulator('Pixel_8_API_35'),
          bundleId: 'com.myapp.debug',
        }),
      ]
    : [
        // CI runners with headless or cloud devices
        androidPlatform({
          name: 'android',
          device: androidEmulator('emulator-5554'),
          bundleId: 'com.myapp.debug',
        }),
      ],

  bridgeTimeout: isCI ? 180000 : 60000, // Longer timeout in CI
};

export default config;

Coverage Root

The coverage root option specifies the root directory for coverage instrumentation in monorepository setups. This is particularly important when your tests run from a different directory than where your source files are located.

{
  coverageRoot: '../',  // Use parent directory as coverage root
}

Default: process.cwd() (current working directory)

This option is passed to babel-plugin-istanbul's cwd option and ensures that coverage data is collected correctly in monorepo scenarios where:

  • Tests run from an example/ directory but source files are in ../src/
  • Libraries are structured with separate test and source directories
  • Projects have nested directory structures that don't align with the current working directory

Without specifying coverageRoot, babel-plugin-istanbul may skip instrumenting files outside the current working directory, resulting in incomplete coverage reports.

When to use coverageRoot

Set coverageRoot when you notice 0% coverage in your reports or when source files are not being instrumented for coverage. This commonly occurs in create-react-native-library projects and other monorepo setups.

Need React or React Native expertise you can count on?