---
title: "Testing Your React Native Apps"
description: "A step-by-step guide to testing your React Native apps for iOS ecosystem."
url: https://www.callstack.com/blog/testing-your-react-native-apps
updated: 2026-10-24T08:39:38.166Z
---

# Testing Your React Native Apps

A step-by-step guide to testing your React Native apps for iOS ecosystem.

_By Mike Grabowski, CEO & Founder @ Callstack · Published 2016-05-03 · Category: Testing_

React.js is very straightforward due to the fact that the browser is the only environment we need to worry about. With React Native, however, the ecosystem is significantly more complex because it involves multiple platforms and testing suites for web, iOS, Android, and possibly even Windows soon.

In this series of posts, we will cover each platform and its tooling separately. Today we will start simply with iOS, which is the easiest and shortest to set up. Let’s check how snapshots can help us iterate fast and make our React Native upgrade process a breeze.

### Snapshots

Screenshot testing is great because it helps mediate the differences in all platforms and devices your app can be running. The process itself is rather simple: reference images stored on the disk are compared with the current state of the app. In the event they differ, the suite finishes with an error.

Some time ago React Native released an update which introduced a subtle, yet important UI change. The update caused all _\<ListView /\>_nodes to render with slightly different margins, which ended up breaking a lot of layouts. Having a convenient way to check our UI at a glance would’ve saved a lot of headache for many people. Fortunately, this type of problem is no longer an issue.

Take 10 minutes out of your day and let me show you how to save hours down the road! All that’s required is 1/2 cup of coffee.

### Prerequisites

#### Empty app

I have slightly modified the default React Native _Hello World_ example. Instead of rendering dummy text, it now renders an array of strings below the heading.

The folder structure is as follows:

[GitHub Gist](https://gist.github.com/callstack-bot/4ea5ecd4d8a17c056d7c5a970385eb15)

There are two index files at the root of the folder:

- index.ios.js — default entry point for our app where we register _SampleApp_ by calling _AppRegistry.registerComponent,_
- index.test.js _—_ entry point for our integration tests that registers all _components_and _containers_. We will discuss this file later in this guide.

You can [browse it live on GitHub](https://github.com/callstack-io/react-native-snapshot-tests). It contains a working example of what we’ll be building today. Feel free to set it up on your Mac first and check the steps as we go!

### Step 1: Let’s make some space

Before we start writing our tests, we’ll have to create a new target for them.

To do so, go to File -\> New -\> Target and select _iOS Unit Testing Bundle_ from _Test_ section.

You can create as many targets as you want to organise your tests by their type, as in UIExplorer

Now define a name for your target.

In this guide, we are going to go with SampleAppSnapshotTests.

Your tests can be also written in Swift, but in this guide we are going to stick with Obj-C for consistency. Once you are happy with the product name, click “Finish” and let’s go to next step!

### Step 2: Link RCTTest

On iOS we are going to use RCTTest most of the time. It’s aReact Native module that contains helpers for making snapshot tests and more. We will discover them in next guides later. For now, let’s just _link_it so that we can start using it.

_Note: :_rnpm currently does not support linking to non-main target. That means you will need to follow the manual linking guide as described below. If any of these steps sound unfamiliar to you, be sure to check the [official guide on manual linking](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking).

First thing we’ll need to add RCTTest.xcodeproj to our _Libraries_ group.

Next, we’ll add libRCTTest.a under _Link binary with libraries_ section. You can find it in _Build Phases_. Note we are adding it to the test target so that our tests and its dependencies do not ship to the App Store.

Next, update _Header Search Paths_ of our SampleAppSnapshotTests target. Note the path is \`recursive\`.

Last but one step is to add two linker flags (ObjC and lc++) to our target

And finally, time to specify FB\_REFERENCE\_IMAGE\_DIR_._ It holds a path to the place on disk where our suite will store captured snapshots.

You can use the below value:

[GitHub Gist](https://gist.github.com/callstack-bot/65e90a1ef4c3d392d49df158f781a4aa)

FB\_REFERENCE\_IMAGE\_DIR=""$(SOURCE\_ROOT)/$(TARGET\_NAME)/ReferenceImages""

which will expand to /path/to/project/ios/SampleAppSnapshotTests/ReferenceImages

and add it to _Preprocessor Macros._

Now, we can finally go back to SampleAppSnapshotTests.m_._ It’s a default test file that Xcode creates every time we make a new test target.

### Step 3: Setting up the runner

After opening up the test file for the first time, you should see the following:

[GitHub Gist](https://gist.github.com/grabbou/4c37cc094b2849a35b2072c20134c3ef)

This is a default test case created by Xcode. Since it’s been set up for iOS tests in mind, we can delete all methods except setUp, which we will use in a bit.

We are going to extend our SampleAppSnapshotTests interface with a private property \_runner:

  
#import  
#import  
#import  
@interface SampleAppSnapshotTests : XCTestCase {  
 RCTTestRunner \*\_runner;  
}  


This will hold a reference to RCTTestRunner _—_ which we will use to run our components and make snapshots of them.

Next, we’ll replace our setUp method with the following:

[GitHub Gist](https://gist.github.com/callstack-bot/a9dc1a3ac58694e2514b31deabc4b85e)

The first argument to RCTInitRunnerForAppis a location where our entry test file lives. In this case — it’s in the root folder so we can just put its name.

On the second line, there’s recordMode defined. When set to _NO_, it will run all tests in order to compare the snapshot with the reference image which is stored on disk. When set to _YES_, it will capture snapshots of every test case and store them on disk for further use.

### Step 4: Writing our test case

Before we start with our first native test case, let’s take a look at our index.test.js file:

[GitHub Gist](https://gist.github.com/grabbou/7d7e98c57dacff1972657e036b0b7a77)

It has an array of components to test (called TO\_TEST_)._ We pass each item to _AppRegistry.registerComponent_. That means we can test any component present in this array directly.

Note: Before we pass a component to _AppRegistry.registerComponent,_ we wrap it with the SnapshotViewIOS_._ This is responsible for capturing underlying views and finishing the test case. Without it, our tests would hang forever.

We also pass initialProps on line 28. That means we change the way our components display on per test basis. We will explore this pattern later.

Let’s open SampleAppSnapshotTest.m again and add the below code under setUp method:

[GitHub Gist](https://gist.github.com/callstack-bot/9d25a2a87e9a6ca9a4dbbbf233c926df)

It’s our first test case! We are using _RCTTestRunner_ to run a test with the _AppContainer_ module_._

Note: Module name (in this case AppContainer) is the string you pass to _AppRegistry.registerComponent._ In our case, we register _containers_ and _components_ by their displayName(line 36 in index.test.js_)._

After performing that step, your entire file should look more or less like the one below:

[GitHub Gist](https://gist.github.com/grabbou/9e95c60cc102529258d3779153d21efe)

### Step 5: Running tests

Did you notice the small icon that appeared next to your test case?

It’s a small helper from Xcode that allows us to run a single test suite when clicked.

So let’s try to run our example by clicking the icon and see what happens!

The test most likely failed straight away! This is because there’s no image to compare against.

### Step 6: Recording snapshots

As we’ve seen already in the previous step, to actually run the test, we have to snapshot it first!

Let’s change the recordMode from _NO_ to _YES_ so that it looks as follows:

[GitHub Gist](https://gist.github.com/callstack-bot/f5b074187aa7ee7f3f88528d67895e25)

and run our suite again!

This time, our tests pass and there’s a new snapshot in ReferenceImages.

Now, we can turn off the recordMode by setting its value back to _NO_ and run the suite again.

Woo! Tests are green — the snapshot matches the current state of our app!

Tip: You can now edit app/containers/App.js and change e.g. backgroundColor. It will make our test fail as that’s rather a significant change! Don’t forget to revert the changes before continuing onto next step!

### Bonus A

#### Adjusting the snapshot size

As you‘ve noticed, the snapshot height is 2000 points long! This is the default size so that UIExplorer examples can fit in a single view.

We’ve aligned our view with flexbox to take all available space. That means the default snapshot dimensions don’t reflect real users phones. Time to change that!

Let’s turn on the recordMode back to _YES_ and add the following test case:

[GitHub Gist](https://gist.github.com/callstack-bot/4d7a596e7efc0c41ce0996fea1747757)

We are going to tell change RootView frame to be 320 x 568 (iPhone 6). Let’s run the tests again.

We should now have a new file inside our ReferenceImages folder.

That looks way better, doesn’t it?

Note: You can use this technique to snapshot different screen sizes. In this guide, we run all our tests on iPhone 5. As you can see, that didn’t stop us from capturing iPhone 6 snapshot.

### Bonus B

#### Mocking the data

Up to this point we’ve only snapshotted the views _as is_. Our view accepts _data_ as a prop. When we pass it an empty array, it renders an empty placeholder.

[GitHub Gist](https://gist.github.com/grabbou/f428ed8d3a3723b78861f1cf41815062)

Thanks to our index.test.js setup, we can pass arbitrary initialProps to the tested component. That allows us to manipulate its appearance on a per test basis. To do so, we will define yet another test case that passes an empty array as follows:

[GitHub Gist](https://gist.github.com/callstack-bot/15369be5dfcbe973478a96730c833df0)

Let’s turn on the recording mode again, run the tests.

Woo again! We’re also now able to snapshot an empty view. Our test coverage is increasing.

## Summary

I hope you enjoyed this short article, and if I have saved even a single person several hours of frustration with configuring testing, then I have done my job! Look for more articles in the near future for the other platforms.

You can find the [working example on Github](https://github.com/callstack-io/react-native-snapshot-tests). Check it out and let me know what you think in comments.

Good luck and have fun!
