At Ensolvers, we try to write as many automated test cases we can, in different layers of the software products we build, since it helps auto-documenting the code, ensure software quality and eases maintenance.
In our several React Native projects, we use Detox, a testing and automation library. Detox allows simulating user behaviour like taps, swipe, scroll, etc. in particular components and then assert for results – for instance, UI transformations. In this way, it is possible to replicate a full use-case flow in the application to test it from end to end.
Step1: InstallationInstalling detox in an existing project is pretty simple
- Install Detox
- npm install detox –save-dev
- Install a test runner, you can choose Jest or Mocha (in my case was Jest):npm install jest –save-dev
- Set up test-code scaffolds (automated)
detox init -r jest
this will create a e2e folder with config files and a first test.
- Configuration
- IOS
Add detox configuration to packaje.json:
“detox”: {
“configurations”: {
“ios.sim.debug”: {
“binaryPath”: “ios/build/Build/Products/Debug-iphonesimulator/example.app”,
“build”: “xcodebuild -project ios/example.xcodeproj -scheme example -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build”,
“type”: “ios.simulator”,
“device”: {
“type”: “iPhone 11 Pro”
}
}
}
}
- Android
- Set sdk root adding following line to bashrc:
export ANDROID_SDK_ROOT=$HOME/Android/Sdk
- Add Detox dependency to your root buildscript (i.e. android/build.gradle):
// Note: add the ‘allproject’ section if it doesn’t exist
allprojects {
repositories {
// …
google()
maven {
// All of Detox’ artifacts are provided via the npm module
url “$rootDir/../node_modules/detox/Detox-android”
}
}
}
- Add the following dependencies and defaultConfig to your app buildscript (i.e. app/build.gradle):
//Please be aware that the minSdkVersion needs to be at least 18.
dependencies {
// …
androidTestImplementation(‘com.wix:detox:+’)
}
// …
android {
// …
defaultConfig {
// …
testBuildType System.getProperty(‘testBuildType’, ‘debug’)
testInstrumentationRunner ‘androidx.test.runner.AndroidJUnitRunner’
}
}
- Add Kotlin to your classpath in the root build-script (i.e.android/build.gradle):
buildscript {
ext {
// …
kotlinVersion = ‘1.3.71’
}
// …
dependencies {
// …
classpath “org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion”
}
}
- Create Android Test class:
Add a file android/app/src/androidTest/java/com/[your.package]/DetoxTest.java and fill as in the detox example app for NR. Don’t forget to change the package name to your project’s (create folder androidTest if you need).
- Add Detox configuration to package.json
“detox” : {
“configurations”: {
“android.emu.debug”: {
“binaryPath”: “android/app/build/outputs/apk/debug/app-debug.apk”,
“build”:
“cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..”,
“type”: “android.emulator”,
“device”: {
“avdName”: <your_emulator_abd_name>
}
},
“android.emu.release”: {
“binaryPath”: “android/app/build/outputs/apk/release/app-release.apk”,
“build”: “cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..”,
“type”: “android.emulator”,
“device”: {
“avdName”: <your_emulator_abd_name>
}
}
}
}
note: You can get your list of available emulators with the following commands:
cd $ANDROID_SDK_ROOT/emulator
./emulator -list-avds
Step 3: Writing a basic test case.
Let’s assume we want to start a test interacting with a TouchableOpacity. First thing we need is to define a testID so we can reference the ponent via a Detox test:
<View>
<TouchableOpacity testID=’MyUniqueId123′>
<Text>Some button</Text>
</TouchableOpacity>
</View>
Note: since Detox forces us to define IDs for the componentes, it is considered a “gray-box” testing framework due to the fact that the code will reflect the fact that it is tested with Detox through this property.
Create a .spec.js file inside e2e folder (or use the existing file firstTest.spec.js) and paste the following code:
//Define a test block
describe(‘App Tests’, () => {
//Reset the App before each test
beforeEach(async () => {
await device.reloadReactNative();
});
//Define a test case
it(‘test case description’, async () => {
//Your Code here, for example await element(by.id(‘id’)).tap()
});
})
Match the element and perform an action:
await element(by.id(‘MyUniqueId123’)).tap();
Set an expectation on the result:
await expect(element(by.id(‘AnotherUniqueId456’))).toBeVisible();
Step 4: Running the test.
Build the app:
detox build
Then, the tests can be run with the following commands
- Android:
detox test -c android.emu.debug
- IOS:
detox test -c ios.sim.debug
The command above will run the test (files with extension .spec.js) inside e2e folder.
That’s it. Your first failing Detox test is running!
Make more tests:
You can create more complex tests using the Detox API: