Introducing React Native Harness: Fast, Real-Device Testing for Native Modules

At Callstack, we’re passionate about improving the developer experience. We started with React Native Builder Bob, the go-to tool for creating and packaging libraries. Now, we're tackling the next big challenge: creating a better way to test native modules.

Today, we’re excited to introduce React Native Harness, a new testing framework designed to bridge the gap between the speed of Jest and the realism of end-to-end (E2E) testing. It allows you to run tests with a familiar Jest-like syntax directly on a device or emulator, giving you a fast, reliable way to validate real native behavior without the overhead of complex UI automation.

Get Started in Minutes

Ready to dive in? You can add Harness to your project with a single command:

npm install --save-dev react-native-harness

Next, create your first test file and add a simple assertion to see it in action. For example, let's test a simple feature of the MMKV storage library by verifying that a value is saved and retrieved correctly:

import { describe, test, expect } from 'react-native-harness';
import { MMKV } from 'react-native-mmkv';

describe('MMKV storage', () => {
  test('saves and retrieves a value', () => {
    const storage = new MMKV({ id: 'test-storage' });
    storage.set('greeting', 'Hello MMKV');
    const value = storage.getString('greeting');
    expect(value).toBe('Hello MMKV');
  });
});

‍

Then, configure your runners in a newly created rn-harness.config.mjs file:

const config = {
  include: ['./src/**/*.harness.{js,ts,jsx,tsx}'],
  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;
You will also have to update your Metro configuration and Babel preset. For a full walkthrough, our Quick Start Guide will help you get everything set up in just a few minutes. Or, if you prefer a visual guide, watch this step-by-step presentation by Łukasz Chludziński.

When ready, you can run the following command:

npx react-native-harness

And enjoy your test results:

The entire setup is fast and straightforward, especially if you already have a playground app in your repository.

The Challenge: Testing Native Modules

The React Native testing landscape offers powerful tools, each suited for a specific job.

  • Jest is blazing fast, perfect for testing pure JavaScript or TypeScript logic. It provides quick feedback and clear reporting. However, because it runs in a Node.js environment, any native functionality needs to be mocked, which means you can’t truly validate the native side of your code.
  • E2E testing tools like Maestro or Detox operate on the other end of the spectrum. They run on real devices, interact with your app like a user, and are excellent for validating complete user flows. The trade-off is that they are typically slower, more complex to set up, and can feel like overkill when the goal is to test a single native module.

This leaves a challenging middle ground for native module developers. How do you efficiently test the critical point where JavaScript meets native code? You need the realism of a device without the complexity of a full E2E suite. Harness is built to fill this gap, providing a simple, repeatable, and consistent way to ensure your native code works as expected on every platform.

A notable inspiration was Marc Rousavy's brilliant work on Nitro Modules. His approach involved embedding a custom test runner directly into the playground app, which allowed tests to execute in a complete React Native environment. We took this core idea, running tests on a real device, and generalized it into a more universal library. For details, check his original codebase.

How Harness Works

Harness lets you write tests that are portable, reliable, and completely separate from your app's core logic. Under the hood, it bundles your test files with Metro, executes them on a connected device or emulator, and reports the results directly back to your CLI.

It supports iOS, Android, and VegaOS out of the box and was designed with portability in mind. As long as your platform uses Metro as a bundler, bringing Harness to it is straightforward. This gives you the realism of native execution with a familiar, developer-friendly workflow.

Writing Your First Test

If you’ve ever used Jest, you’ll feel right at home with Harness. We use a Jest-style API and Vitest’s expect library, so you can start writing tests immediately with no new syntax to learn.

Here’s a simple example of a test file in Harness:

import { describe, test, expect, beforeEach, afterEach, harness } from 'react-native-harness';
import { MMKV } from 'react-native-mmkv';

let storage: MMKV;
let listeners: Array<(...args: any[]) => void> = [];

describe('MMKV storage', () => {
  beforeEach(() => {
    storage = new MMKV({ id: 'test-storage' });
    listeners = [];
  });

  afterEach(() => {
    storage.clearAll();
    listeners.forEach((listener) => {
      storage.removeOnValueChangedListener(listener)
    });
  });

  test('saves and retrieves a value', () => {
    storage.set('greeting', 'Hello MMKV');
    const value = storage.getString('greeting');
    expect(value).toBe('Hello MMKV');
  });
});

As you can see, the API is intuitive. Harness also supports mocking and spying through full compatibility with @vitest/spy.

CI/CD Ready

Reliable testing needs to extend beyond local development. Harness is designed to work smoothly in CI/CD environments. We even provide an example setup for GitHub Actions to give you a solid foundation for including real-device testing in your automated workflow.

Android tests running on CI with Harness. A few tests are failing.

Why It Matters

Harness isn't meant to replace Jest or E2E tests. Instead, it complements them. For JavaScript-heavy business logic, Jest remains the best tool. For comprehensive user-flow validation, E2E is invaluable. Harness shines when you need to verify native integrations.

It gives library authors and native module developers a pragmatic tool to build confidence and increase test coverage where it matters most.

See It In Action

We’ve already put Harness to the test in a real-world scenario. We integrated it into the popular react-native-mmkv library, where it’s now running as part of their CI pipeline.

The results were immediate. While submitting the pull request, Harness helped find two bugs that had previously gone unnoticed, proving its value right away.

quote marc rousavy

What’s Next for Harness

We’re just getting started. Our next step is to integrate Harness into more real-world projects to gather feedback, fine-tune the library, and shape its future based on your use cases. We’re also focused on expanding platform support and introducing deeper integrations with the React Native ecosystem. We want Harness to become the go-to solution for testing native modules: lightweight, reliable, and ready to grow with your workflow.

Wrapping Up

With React Native Harness, testing native modules is no longer a choice between speed and realism. You get the simplicity of a familiar testing API combined with the confidence of true device execution.

If you’re maintaining a React Native library or experimenting with native modules, give Harness a try, share your feedback, and help us make testing in React Native as smooth as the rest of your development workflow.

Check out Harness on Github. Happy testing!

‍

Insights

Learn more about Testing

How AI Agents Can Cut Manual QA by 30% — cover

Oct 30Article

How AI Agents Can Cut Manual QA by 30%

Explore an agentic QA workflow targeting 30% less manual effort across mobile, web, and TV, with test selection, failure triage, and validation.

Give QA Agents the Controls They Need With Appduct — cover

Oct 20Article

Give QA Agents the Controls They Need With Appduct

Use Appduct to give AI QA agents access to app functions for setting test conditions, triggering events, and checking results with UI automation.

cover

Oct 13Article

Agentic Mobile Testing With e2e and agent-device

See how e2e uses agent-device for AI-driven iOS and Android tests, combines exact assertions with agent actions, and replays cached steps without model calls.

Who Tests AI-Written Code? Inside TesterArmy With Szymon Rybczak — cover

Oct 12Podcast

Who Tests AI-Written Code? Inside TesterArmy With Szymon Rybczak

Szymon Rybczak explains how TesterArmy tests web and mobile apps with AI agents, creates test plans for pull requests, and fits into QA workflows.

cover

Aug 4Article

Automating Mobile QA With Cloud Agents

Code review and green CI checks do not prove a mobile app still works. Learn how cloud agents, agent-device, and runtime evidence can verify app behavior before merge.

cover

Jul 21Webinar

Behavior Review for AI-Native Delivery

AI can increase code output faster than teams can verify the real app. See why behavior review matters before merge.

cover

Jul 6Article

Introducing Sniffler: Run only the E2E tests your changes can affect

Sniffler maps changed files to affected E2E tests, so teams can avoid running the full suite on every pull request.

cover

Jun 17Talk

Automating Mobile QA with Cloud Agents

Michał Pierzchała will present Automating Mobile QA with Cloud Agents at Ship London on 17 June 2026.

cover

May 13Podcast

How AI Is Changing React Native Development and Testing

Zack Ebenfeld joins React Universe On Air to talk about how AI is changing React Native workflows, testing, QA, and day-to-day engineering work.

cover

Apr 14Article

Agent React DevTools: Give AI Agents Access to React Internals

Agent React DevTools gives AI agents access to the React component tree, state, and performance data, enabling deeper debugging and more reliable QA for React and React Native apps.

cover

Mar 19Live Stream

Agent Device, AI workflows, and mobile testing in practice

A discussion on Agent Device, AI-driven workflows, and testing mobile apps using simulators and accessibility data.

cover

Aug 23Podcast

Introducing E2E Tests to React Native Core

This episode of the React Native Show dives into the recent introduction of End-to-End (E2E) testing in RNTester. Join us as we unpack the thought process, technical considerations, and practical implementation of this new approach to testing in React Native.

cover

Mar 19Tutorial

The Hard Way vs. The React Native AI SDK Way: Stop Writing Custom Modules for Every Model

Learn how React Native AI uses a unified provider model to switch between cloud and on-device LLMs without rewriting application logic, enabling reliable AI experiences online and offline.

cover

Mar 12Tutorial

Build Smarter Apps: Tool Calling & AI Orchestration Explained

Learn how on-device models in React Native can call tools, interact with external APIs, and return structured outputs you can use directly in application logic.

cover

Mar 5Tutorial

MLC LLM + React Native: On-Device AI Without the Pain

Learn how to run third-party on-device LLMs in React Native using MLC LLM. Choose your models, run them efficiently across platforms, and keep a unified JavaScript API with React Native AI.

cover

Feb 24Tutorial

Intelligent Fallbacks with Apple Intelligence in React Native

Learn how to use Apple’s built-in Foundation Models in React Native apps, reduce memory usage, and enable fast, fully on-device AI with React Native AI Apple.

cover

Feb 10Tutorial

What Is the React Native AI SDK? A Complete Intro & Quickstart

Learn why on-device AI matters for React Native apps, how local LLMs behave offline, and what problems React Native AI is designed to solve from day one.

cover

Jan 29Tutorial

Implementing an Android TurboModule with Kotlin

Learn how to implement a React Native TurboModule on Android, from the TypeScript spec and Codegen to the Kotlin implementation and package registration.

cover

Jan 19Tutorial

Working with Different Threads in Swift TurboModules

Learn how JavaScript, native module, background, and main threads interact in React Native TurboModules, and how to use GCD queues to run async work safely in Swift.

cover

Jan 9Tutorial

How to Add Type-Safe Constants to Swift TurboModules

Learn how to expose typed, immutable constants from a Swift TurboModule using Codegen, and get full end-to-end type safety between native and JavaScript.

cover

Dec 30Tutorial

Adding Event Emitters to Your TurboModule in Swift

Learn how to emit native events from a Swift TurboModule and subscribe to them in JavaScript, including proper memory management and Codegen integration.

cover

Dec 22Tutorial

Writing Your First TurboModule in Swift

Learn how to build a fully working TurboModule in Swift, integrate it with Codegen, and bridge it through Objective‑C inside an Expo app.