Running in CI/CD
React Native Harness can be launched in CI environments like GitHub Actions, making it an excellent choice for automated testing of native functionality. In fact, React Native Harness's internal test suite runs using Harness itself in CI, proving its reliability and effectiveness in cloud environments.
Performance Overview
The amount of time needed to run Harness tests is typically around 5 minutes for test execution. However, depending on how your app is built and the complexity of your native modules, the total CI time can be as high as 20 minutes when including build times.
React Native Harness doesn't require you to constantly rebuild the app from scratch. You can reuse the same debug build as long as your native modules stay the same, significantly reducing CI execution time through intelligent caching.
Official GitHub Action
React Native Harness provides an official GitHub Action that simplifies running tests in CI/CD environments. It handles the setup of emulators, simulators, browsers, and test execution automatically.
Action
callstackincubator/react-native-harness
Pin the action to the same release tag as the react-native-harness version in your package.json (for example package 1.0.0 → uses: callstackincubator/react-native-harness@v1.0.0). The composite action and the npm package are released together; matching them avoids subtle mismatches between CLI behavior and the workflow steps.
The action automatically:
- Loads your React Native Harness configuration
- Sets up and configures the emulator, simulator, or browser based on your config
- Installs your app for native runners
- Runs the tests
- Uploads crash reports from
.harness/crash-reports/as workflow artifacts whenever a run produces them
The action reads your rn-harness.config.mjs file to determine the selected runner's platform and device configuration, so you don't need to duplicate emulator or simulator settings in your workflow. For Android emulator runners, the action still requires a full avd block in that config (see the Android platform guide).
Action Inputs
The action accepts the following inputs:
app(optional): Path to your built app (.apkfor Android,.appfor iOS). Not needed for web runnersrunner(required): The runner name from your Harness config (for example"android","ios", or"chromium")projectRoot(optional): The project root directory (defaults to the repository root)uploadVisualTestArtifacts(optional): Whether to upload visual test diff and actual images as artifactsharnessArgs(optional): Additional arguments to pass to the Harness CLIpackageManager(optional): Override package manager auto-detection. Supported values:npm,yarn,pnpm,bun,denocacheAvd(optional, Android only): Whether to cache the Android Virtual Device snapshot. Defaults totrue. This is most useful when your Android runner defines AVD details inrn-harness.config.mjs.preRunHook(optional): Inline shell script run inbashimmediately before Harness startsafterRunHook(optional): Inline shell script run inbashimmediately after Harness finishes and before artifacts are uploaded
Crash Artifacts
Harness monitors native crashes throughout the entire test lifecycle — including during app startup, before any test code runs. When the app crashes on launch (or at any point during the run), Harness captures the crash report and attaches a parsed stack trace to the failing test or startup error output.
Crash reports are persisted under .harness/crash-reports/ in the current working directory. Filenames include the Harness run timestamp and selected runner name so CI downloads are easy to correlate with a specific workflow run.
The official GitHub Action uploads .harness/crash-reports/**/* automatically (with if-no-files-found: ignore), so crash reports appear as downloadable workflow artifacts whenever a run produces them — no extra configuration needed.
Startup crashes are treated as a first-class failure. If your app crashes before the bridge connects, Harness immediately reports it with the native crash details rather than timing out.
GitHub Actions Example
The example workflow shared below is designed for React Native Community CLI setups. If you're using Expo or Rock, the workflow will be simpler as these frameworks provide their own build and deployment mechanisms that integrate seamlessly with CI/CD environments.
Here's a complete GitHub Actions workflow that demonstrates how to run React Native Harness tests on both Android and iOS platforms using the official action:
Complete Workflow Configuration
Hook Scripts
The official action can run optional shell hooks around the Harness invocation:
preRunHookruns inbashimmediately before the Harness CLI command.afterRunHookruns inbashimmediately after the Harness CLI command and before artifact upload, even if Harness fails.- Both hooks receive
HARNESS_PROJECT_ROOTandHARNESS_RUNNER. afterRunHookalso receivesHARNESS_EXIT_CODE.- A non-zero exit from either hook fails the action.
afterRunHookruns only when execution reached the Harness command.
On Android, both hooks execute inside the android-emulator-runner session, so they can safely use adb against the active emulator. On iOS, the hooks run after the simulator is booted and the app is installed. On web, the same inputs are available for consistency and run immediately before and after the Harness command.
Android Emulator Caching
For Android emulator runners, the official action can cache the emulator snapshot between runs.
- Enable this with
cacheAvd: true. - For best results, define the emulator's AVD details in your Android runner config.
- Use this when you want faster CI runs and a more consistent emulator setup.
If your workflow does not define AVD details, the action can still run the tests, but emulator snapshot caching is less useful.
Metro cache
React Native Harness can persist Metro's transformation cache under .harness/metro-cache in your project root. Enabling it in config (unstable__enableMetroCache: true) speeds up repeated Metro runs.
When you use the callstackincubator/react-native-harness GitHub Action, Metro cache restoration and saving is handled automatically for the resolved projectRoot. You do not need to add a separate actions/cache step for .harness/metro-cache.
Web in CI
The official action supports web runners as well. At the moment, the action installs Playwright Chromium automatically before running Harness.
If your workflow depends on a different browser setup, make that expectation explicit in your CI configuration.
Build Artifact Caching
The workflow includes build artifact caching to significantly reduce CI execution times. When native modules haven't changed, you can reuse the same debug builds instead of rebuilding from scratch.
How Caching Works
- Android: Caches the built APK file using
android-app-*keys based on Gradle configuration file hashes - iOS: Caches the built app bundle using
ios-app-*keys based on Podfile.lock and project file hashes
Cache Limitations
While caching is enabled in the workflow, it may not always be correctly purged when needed. GitHub Actions cache invalidation can sometimes miss subtle changes that should trigger a rebuild. If you encounter issues with stale builds or unexpected test failures, you may need to manually purge the cache through the GitHub UI:
- Go to your repository's Actions tab
- Click on Caches in the left sidebar
- Find and delete the relevant cache entries (
android-app-*orios-app-*)
Advanced Frameworks
If you're using frameworks like Expo or Rock, you'll benefit from sophisticated fingerprinting solutions that are guaranteed to correctly detect changes and rebuild when necessary.
Adapting for Your Project
React Native Community CLI Projects
For standard React Native Community CLI projects, adapt the workflow by:
- Update App Names: Replace
YourAppwith your actual app name in the iOS configuration - Verify Paths: Ensure build output paths match your project structure
- Test Command: Use
npx react-native-harness --harnessRunner [platform]to run tests on the specified platform
Expo Projects
For Expo projects, the workflow will be simpler using Expo Application Services (EAS):
- Use EAS Build (remote or local) instead of native build steps
- Leverage EAS's built-in caching and fingerprinting
- Install the app using EAS CLI tools
Rock Projects
For Rock projects:
- Use Rock's integrated build commands
- Benefit from Rock's advanced caching mechanisms
- Follow Rock's CI/CD best practices for optimal performance
