Assumptions
Before we begin, this article assumes RN (expo or otherwise) is set up on your terminal and your app is up and running.
If not please see how to do that.
We will be proceeding with a setup built using React Native CLI.
Please ensure the builds are working before integration to make it easier later on to debug if need be.
There might be requirements such as specific ndk versions to be installed
P.S Either will do.
Our app is called rndetox
(it's weird. I know.)
There have been breaking changes implemented with detox v18,
Why Detox?
What does detox offer over others? I'll let their own page talk about it
🔰 Phase 1 - Setting up detox
By this time, your RN app should be up and running on a mac machine. Let's proceed setting up Detox.
Installing packages:
Install the following packages using your terminal
,
xcode-select --install
brew update && brew install node
brew tap wix/brew
brew install applesimutils
npm install -g detox-cli
npm install detox --save-dev
If jest is not already installed in your project,
npm install jest --save-dev
Use this command for detox to generate a jest scaffolding,
detox init -r jest
It will create a bunch of files under e2e
directory with preset configurations.
Add detox configuration:
The following configuration needs to be added in package.json
of the project,
📃 package.json
"detox": {
"configurations": {
"android.emu.debug": {
"binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
"build": "cd android && ./gradlew app:assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..",
"type": "android.emulator",
"device": {
"avdName": "detoxTestEmulator"
}
},
"android.emu.release": {
"binaryPath": "android/app/build/outputs/apk/release/app-release.apk",
"build": "cd android && ./gradlew app:assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..",
"type": "android.emulator",
"device": {
"avdName": "detoxTestEmulator"
}
},
"ios.sim.release": {
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/rndetox",
"build": "export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -workspace ios/a.xcworkspace -scheme a -configuration Release -sdk iphonesimulator -derivedDataPath ios/build",
"type": "ios.simulator",
"device": {
"type": "iPhone 11 Pro"
}
},
"ios.sim.debug": {
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/rndetox",
"build": "xcodebuild -workspace ios/a.xcworkspace -scheme a -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
"type": "ios.simulator",
"device": {
"type": "iPhone 11 Pro"
}
}
},
"test-runner": "jest"
}
What's happening through the configuration? 😅
Let's walk through.
android
"android.emu.release": {
"binaryPath": "android/app/build/outputs/apk/release/app-release.apk",
"build": "cd android && ./gradlew app:assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..",
"type": "android.emulator",
"device": {
"avdName": "detoxTestEmulator"
}
}
The android release configuration consists of :
- holds path to the built apk to test
- build commands with build type
- type and name of the emulator (this name should be the same as the emulator which should be created using android studio)
Note: On how to create emulators, here is a doc which details it.
ios
"ios.sim.release": {
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/rndetox",
"build": "export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -workspace ios/a.xcworkspace -scheme a -configuration Release -sdk iphonesimulator -derivedDataPath ios/build",
"type": "ios.simulator",
"device": {
"type": "iPhone 11 Pro"
}
}
The android release configuration consists of :
- path to built binary (
rndetox
is the name of our app hence it'srndetox
, it would be [app_name].app) - build commands with scheme and path to workspace as per the name of the app (ios/[app_name].xcworkspace)
- type and device the tests are to run on
With the detox configuration in place, iOS is all set to be worked with. 🎉
Android on the other hand, well.. " Needs a lot more work. " ⛄
Setup detox with android:
📃 android/app/build.gradle
Add the following lines to default
section
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type for detox
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
Add the following lines to dependencies
section
androidTestImplementation('com.wix:detox:+') { transitive = true }
androidTestImplementation 'junit:junit:4.12'
📃 android/app/src/androidTest/java/com/rndetox/DetoxTest.java
package com.rndetox; /* change to app package name */
import com.wix.detox.Detox;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DetoxTest {
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);
@Test
public void runDetoxTests() {
Detox.runTests(mActivityRule);
}
}
The above file should be created as per the hierarchical order android/app/src/androidTest/java/com/[app_name]/DetoxTest.java
📃 android/app/src/main/AndroidManifest.xml
The snippet should be added to the <application
tag, this is required for detox to perform as expected (what is this?)
android:usesCleartextTraffic="true"
📃 android/build.gradle
Change minSdkVersion
to 18
or higher, add kotlinVersion
if it's not already present under ext
.
It should look similar to this,
ext {
buildToolsVersion = "28.0.3"
minSdkVersion = 18
compileSdkVersion = 28
targetSdkVersion = 28
kotlinVersion = "1.3.61"
}
Add classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
under dependencies
dependencies {
// ...
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
Add the following maven
snippet under repositories
allprojects {
repositories {
// ... statements
maven {
// All of Detox' artifacts are provided via the npm module
url "$rootDir/../node_modules/detox/Detox-android"
}
}
}
With the above steps done, android is all set to go. 🎉
⚠️ To verify if this are going good, cross check with this commit which shows the required file changes. ⚠️
🔰 Phase 2 - Write a test
To see if things fall in place, let's add a test id and assert it.
📃 App.js
<Text testID="desc-text" style={styles.sectionDescription}>
📃 e2e/firstTest.spec.js
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
});
it('should have description text on welcome screen', async () => {
await expect(element(by.id('desc-text'))).toBeVisible();
});
});
🔰 Phase 3 - Build
Build a release
iOS:
npx detox build -c ios.sim.release -l verbose
If there are build errors, build on xcode to get details on the same
Android:
npx detox build -c android.emu.release -l verbose
If there are build errors, build on android studio to get details on the same
🔰 Phase 4 - Test
Test a release
iOS:
npx detox test -c ios.sim.release -l verbose
Android:
npx detox test -c android.emu.release -l verbose
Your tests should be passing with flying colors 🌈
🔰 Phase 5 - Setting up automation
Where is the fun without automating the entire workflow;
It's an 🐘 on it's own, will try to address them individually.
- Integration with CircleCI
- Integration with TravisCI
Check out the github repo for the entire codebase 🔥
If you have questions, let us know in the comments and we are looking forward for your feedback 🍻
Top comments (8)
Hi Jeevan thank you very much for this article.
i'm new in programming i was following detox documentation and your article but when i arrive to phase 3 to build a release fro Android i always get the same error. I've tried to find-out the solution before write you a comment and i would like to know if maybe you would know what's happening. Thanks in advanced.
// What i write
aklil@DESKTOP-0E8NOCM MINGW64 /d/e2e-detox(master)
$ detox build -c android.emu.release -l verbose
detox[3736] INFO: [build.js] cd android && ./gradlew app:assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..
// The error
'.' is not recognized as an internal or external command,
operable program or batch file
detox[3736] ERROR: [cli.js] Error: Command failed: cd android && ./gradlew app:assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..
After that Error i've forced reinstall npm install -g detox-cli and now it doesn't give the last error but when
i press enter after write the command:
detox build -c android.emu.release -l verbose
it keeps freeze, (it's a little advance) but it still doesn't work.
I am also having this problem although with iOS.
With the android however i am getting jest-runner error.
Did you find any good solution.
@Fazli As i happen to mention to the comment above, I'm not entirely sure the cause of the issue in this case, i've updated the repo to accommodate the latest version of jest/detox, kindly refer the same and let me know if it works for you.
I am going to try it now.
On my iOS build however the build just freezes.
Here is my repo:
github.com/fazlizekiqi/mobileApp
I would really appreciate for some help.
i was facing the same issue on windows
the issue was fixed by removing the '.' from " ./gradlew"
@willy I'm not entirely sure the cause of the issue in this case, i've updated the repo to accommodate the latest version of jest/detox, kindly refer the same and let me know if it works for you.
Hi, thanks for the nice article. I also find myself deep in configuration when setting up detox so I created an npm package to automate detox setup. Hope it helps the community: react-native-setup-detox
Hi Jeevan,
thanks for your article. How can I get a test coverage report like for example an html report. Please advise.
Thanks