React Native End-to-End Testing with Detox
Your mobile app can be tested in a variety of ways. Unit tests are one of them, in which you just test particular portions of your app. Component testing, sometimes known as "integration tests," also comprises mocking up the various parts of your app (as if the app would be complete). You may feel more confident about releasing your app if you have more test coverage.
End-to-end (E2E) testing involves running your software on a real device or a simulator and interacting with it as a user could in the real world. To put it simply, this implies that a computer or robot is navigating your app and determining whether or not a button may be clicked, a phrase can be entered into the search bar, or anything else.
In this blog, I will show you guys the simplest step to use Detox framework to perform E2E testing. After reading this blog, you will have basic knowledge about how to apply Detox to your React Native application.
What is Detox testing framework?
One of the leading developers in the React Native community, Wix, created the end-to-end framework for mobile apps known as Detox. Amazing projects like react-native-navigation and react-native-ui-lib are also maintained by Wix.
Detox offers excellent abstractions for choosing and starting actions on components. A typical test appears as the code below:
/* eslint-env detox/detox, mocha */
import { by, device, expect, element } from "detox"
describe("Example", () => {
beforeAll(async () => {
await device.launchApp()
})
beforeEach(async () => {
await device.reloadReactNative()
})
it("should have welcome screen", async () => {
await device.reloadReactNative()
await expect(element(by.text("username-input"))).toBeVisible()
})
})
The syntax looks very similar to what we usually do with Unit tests. Let’s get started
Setting up React Native project
I will assume that you already know how to bootstrap a new React Native application. I prefer using the command react-native init
to generate the code structure.
npx react-native init MyApp --template react-native-template-typescript
In this case, I’m using a typescript template to init my code base. For javascript lovers, feel free to use the javascript one . This step will be very straightforward. So I will quickly keep it
React Native team just released new architecture recently. I tested and found out that detox didn’t support it yet.
Setting up Detox
Because we are working with React native, please make sure that we already have:
-
Xcode
-
Java
-
Android SDK
-
Android Emulator (https://wix.github.io/Detox/docs/introduction/android-dev-env)
-
Brew (updated)
-
Node
Before installing the Detox library into your project. You will need to have some global cli.
Let’s install all of them step by step:
-
``yarn global add detox-cli or npm install detox-cli --global`
-
brew tap wix/brew && brew install applesimutils
The second step will take a little bit of time to complete. But it’s not that important, you can skip it.
The next step is to go to your root folder and install Detox as a Dev Dependency.
-
yarn add detox -D or npm install detox --dev —-save
-
yarn add jest-circus -D
Detox will use jest as a runner to run test cases. Jest is installed by default in React Native project. Please make sure the version of jest is above 28. If you are using react-native-reanimated library, you may face some issues with jest (unit test failing). You can check this issue in github, there are some workarounds to fix it https://github.com/software-mansion/react-native-reanimated/issues/3215
After that, we will initialize the configuration for Detox. This can easily be done by the command:
detox init -r jest
This command will generate some files:
- .detoxrc.json: This is a basic configuration file for detox
{
"testRunner": "jest",
"runnerConfig": "e2e/config.json",
"skipLegacyWorkersInjection": true,
"apps": {
"ios": {
"type": "ios.app",
"binaryPath": "SPECIFY_PATH_TO_YOUR_APP_BINARY"
},
"android": {
"type": "android.apk",
"binaryPath": "SPECIFY_PATH_TO_YOUR_APP_BINARY"
}
},
"devices": {
"simulator": {
"type": "ios.simulator",
"device": {
"type": "iPhone 11"
}
},
"emulator": {
"type": "android.emulator",
"device": {
"avdName": "Pixel_3a_API_30_x86"
}
}
},
"configurations": {
"ios": {
"device": "simulator",
"app": "ios"
},
"android": {
"device": "emulator",
"app": "android"
}
}
}
This is what it’s going to look like. You will have to edit this part:
"apps": {
"ios": {
"type": "ios.app",
"binaryPath": "SPECIFY_PATH_TO_YOUR_APP_BINARY"
},
"android": {
"type": "android.apk",
"binaryPath": "SPECIFY_PATH_TO_YOUR_APP_BINARY"
}
},
We need to update this part into this:
"apps": {
"ios": {
"type": "ios.app",
"build": "xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -sdk iphonesimulator -derivedDataPath ios/build"
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/MyApp.app",
},
"android": {
"type": "android.apk",
"binaryPath": "android/app/build/outputs/apk/beta/debug/app-beta-debug.apk",
"build": "cd android && ./gradlew assembleBetaDebug assembleBetaDebugAndroidTest -DtestBuildType=debug && cd .."
}
},
-
/e2e/config.json: This is the configuration file for Jest runner. You may need to update it in the future. We will just leave it for now
-
/e2e/environment.json
-
You may need to use
applesimutils
command to get the correct name of ios simulator devices. You can also go to Xcode and checkout the list of available devices
Writing your first test case
Before getting started writing test cases, we will need to refactor our coding environment to make everything look good:
-
Support typescript:
yarn add ts-jest -D
-
Add eslint plugin: yarn
add eslint-plugin-detox -D
-
Add
detox
to the plugins section of your.eslintrc
configuration file. You can omit theeslint-plugin-
prefix:
{ "plugins": ["detox"]}
- Add the following line to the top of your detox test files:
/* eslint-env detox/detox, mocha */
- Update /e2e/config.json to match typescript test case:
{
"preset": "ts-jest",
"maxWorkers": 1,
"testEnvironment": "./environment",
"testRunner": "jest-circus/runner",
"testTimeout": 120000,
"testRegex": "\\.spec\\.ts$",
"reporters": ["detox/runners/jest/streamlineReporter"],
"verbose": true
}
- Write your test cases in e2e folder with naming convention “*.spec.ts”
Our first test case will be look like:
/* eslint-env detox/detox, mocha */
import { by, device, expect, element } from 'detox';
describe('Example', () => {
beforeAll(async () => {
await device.launchApp()
})
beforeEach(async () => {
await device.reloadReactNative()
})
it('should have welcome screen', async () => {
await device.reloadReactNative()
await expect(element(by.text('Step One'))).toBeVisible()
})
})
Running your first test case
Before running your e2e test cases. You need to build your application first. Let’s use the command
detox build
This command will build your project and place the binary in the “binaryPath” directory (you can find it in .detoxrc.json). Then you can run to start testing
detox test
If everything is set up correctly, you will see the message show up in your terminal console:
PASS e2e/firstTest.spec.js (7.514s)
Example
✓ should have welcome screen (260ms)
Now, your e2e testing is ready. You can read the documentation of detox to write more test cases with complex logic: https://wix.github.io/Detox/docs/introduction/how-detox-works
Conclusion
You should definitely give Detox a try while testing your React Native applications. Amazing mobile end-to-end testing software is available in Detox. After using it for a while, I'd say it has the advantages and disadvantages listed below:
- exceptionally well-abstracted syntax for matchers and for actions
- Ability to execute tests in CI with excellent integration with Jest
You could occasionally experience configuration difficulties, and it might take some time to figure out the right fix. The best course of action for this issue is to visit and carefully examine GitHub Issues.
- mobile app