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
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.

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.

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!

Learn more about
Testing
Here's everything we published recently on this topic.
We can help you move
it forward!
At Callstack, we work with companies big and small, pushing React Native everyday.
Quality Assurance
Combine automated and manual testing with CI/CD integration to catch issues early and deliver reliable React Native releases.
Release Process Optimization
Ship faster with optimized CI/CD pipelines, automated deployments, and scalable release workflows for React Native apps.
React Compiler Implementation
Use React Compiler to achieve instant performance benefits in your existing applications.
React Native Trainings
Equip your team with React Native skills through tailored training sessions.
