If you are installing Detox for Android for the first time, you can skip right over to the setup section.
Follow our Migration Guide for instructions on how to upgrade from older versions.
-
In version 11 we switched to using Android Espresso of Android's new androidx.* support libraries. We did this in order to stay up to date with Google's latest features and bug fixes, in the hopes of using them to improve our own Android support (which gets better every day!).
-
In version 10, we've made Kotlin mandatory for integrating Detox into your Android project. In the very least, you must include the Kotlin gradle plugin in your project, as we shall see later on. Nevertheless, this is a breaking change so bear that in mind when upgrading. In any case, worry not of the impact on your app, as - unless you effectively use Kotlin in your own native code, there will be no impact on the final APK, in terms of size and methods count.
-
As of version 7 we require Android gradle plugin 3.0.0 or newer. This is a breaking change that makes it impossible to support previous Android gradle plugin versions.
https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html
For older Android gradle plugin support use
[email protected]
instead (previous setup guide here).Note: As a rule of thumb, we consider all old major versions discontinued; We only support the latest Detox major version.
Starting Detox 12.5.0, Detox is shipped as a precompiled
.aar
. To configure Detox as a compiling dependency, nevertheless -- refer to the Setting Detox up as a compiling dependency section at the bottom.
In your root buildscript (i.e. build.gradle
), register both google()
and detox as repository lookup points in all projects:
// 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"
}
}
}
In your app's buildscript (i.e. app/build.gradle
) add this in dependencies
section:
dependencies {
// ...
androidTestImplementation('com.wix:detox:+') { transitive = true }
androidTestImplementation 'junit:junit:4.12'
}
In your app's buildscript (i.e. app/build.gradle
) add this to the defaultConfig
subsection:
android {
// ...
defaultConfig {
// ...
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
}
Please be aware that the minSdkVersion
needs to be at least 18.
If your project does not already support Kotlin, add the Kotlin Gradle-plugin to your classpath in the root build-script (i.e.android/build.gradle
):
buildscript {
// ...
ext.kotlinVersion = '1.3.0'
dependencies {
// ...
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
Note: most guides advise of defining a global kotlinVersion
constant - as in this example, but that is not mandatory.
Note that Detox has been tested for version 1.1.0 of Kotlin, and higher!
Add the 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.
Add this part to your 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": "Nexus_5X_API_24"
}
},
"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": "Nexus_5X_API_26"
}
}
}
}
Pay attention to -DtestBuildType
, set either to debug
or release
according to the main apk type.
Following device types could be used to control Android devices:
android.emulator
. Boot stock SDK emulator with provided name
, for example Nexus_5X_API_25
. After booting connect to it.
android.attached
. Connect to already-attached android device. The device should be listed in the output of adb devices
command under provided name
.
Use this type to connect to Genymotion emulator.
If you are using custom productFlavors the config needs to be applied a bit differently. This example shows how a beta
product flavor would look for both debug and release build types:
"detox" : {
"configurations": {
"android.emu.beta.debug": {
"binaryPath": "android/app/build/outputs/apk/beta/debug/app-beta-debug.apk",
"build": "cd android && ./gradlew assembleBetaDebug assembleBetaDebugAndroidTest -DtestBuildType=debug && cd ..",
"type": "android.emulator",
"device": {
"avdName": "Pixel_API_29"
}
},
"android.emu.beta.release": {
"binaryPath": "android/app/build/outputs/apk/beta/release/app-beta-release.apk",
"build": "cd android && ./gradlew assembleBetaRelease assembleBetaReleaseAndroidTest -DtestBuildType=release && cd ..",
"type": "android.emulator",
"device": {
"avdName": "Pixel_API_29"
}
}
}
}
Using the android.emu.debug
configuration from above, you can invoke it in the standard way.
detox test -c android.emu.debug
While everything may seem on the working side right now, there are many issues with Google's Android emulators causing flakiness and inefficient usage, we recommend addressing. We highly recommend you take the time and apply the practices we've summed up in our Emulators Best Practices guide, in all relevant machines (dev computers, CI agents and scripts) and AVD's.
In apps running minification using Proguard, in order for Detox to work well on release builds, please enable some Detox proguard-configuration rules by applying the custom configuration file on top of your own. Typically, this is defined using the proguardFiles
statement in the minification-enabled build-type in your app/build.gradle
:
buildTypes {
// 'release' is typically the default proguard-enabled build-type
release {
minifyEnabled true
// Typical pro-guard definitions
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// Detox-specific additions to pro-guard
proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
}
}
This is an alternative to the setup process described under the previous section, on adding Detox as a dependency.
In your project's settings.gradle
add:
include ':detox'
project(':detox').projectDir = new File(rootProject.projectDir, '../node_modules/detox/android/detox')
In your root buildscript (i.e. build.gradle
), register google()
as a repository lookup point in all projects:
// Note: add the 'allproject' section if it doesn't exist
allprojects {
repositories {
// ...
google()
}
}
In your app's buildscript (i.e. app/build.gradle
) add this in dependencies
section:
dependencies {
// ...
androidTestImplementation(project(path: ":detox"))
androidTestImplementation 'junit:junit:4.12'
}
In your app's buildscript (i.e. app/build.gradle
) add this to the defaultConfig
subsection:
android {
// ...
defaultConfig {
// ...
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
}
Please be aware that the minSdkVersion
needs to be at least 18.
If you get an error like this:
Execution failed for task ':app:transformResourcesWithMergeJavaResForDebug'.
> com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK META-INF/LICENSE
You need to add this to the android
section of your android/app/build.gradle
:
packagingOptions {
exclude 'META-INF/LICENSE'
}
The problems and resolutions here are different if you're using Detox as a precompiled dependency artifact (i.e. an .aar
) - which is the default, or compiling it yourself.
Of all Kotlin implementation flavours, Detox assumes the most recent one, namely kotlin-stdlib-jdk8
. If your Android build fails due to conflicts with implementations coming from other dependencies or even your own app, consider adding an exclusion to either the "other" dependencies or detox itself, for example:
dependencies {
- androidTestImplementation('com.wix:detox:+') { transitive = true }
+ androidTestImplementation('com.wix:detox:+') {
+ transitive = true
+ exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
+ }
}
Detox should work with kotlin-stdlib-jdk7
, as well.
A typical error output formed by Gradle
in this case is as provided, for example, in #1380:
Could not determine the dependencies of task ':detox:compileDebugAidl'.
> Could not resolve all task dependencies for configuration ':detox:debugCompileClasspath'.
> Could not resolve org.jetbrains.kotlin:kotlin-stdlib:1.3.0.
Required by:
project :detox
> Cannot find a version of 'org.jetbrains.kotlin:kotlin-stdlib' that satisfies the version constraints:
Dependency path 'OurApp:detox:unspecified' --> 'com.squareup.okhttp3:okhttp:4.0.0-alpha01' --> 'org.jetbrains.kotlin:kotlin-stdlib:1.3.30'
Dependency path 'OurApp:detox:unspecified' --> 'com.squareup.okio:okio:2.2.2' --> 'org.jetbrains.kotlin:kotlin-stdlib:1.2.60'
Dependency path 'OurApp:detox:unspecified' --> 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.0' --> 'org.jetbrains.kotlin:kotlin-stdlib:1.3.0'
Dependency path 'OurApp:detox:unspecified' --> 'com.facebook.react:react-native:0.59.5' --> 'com.squareup.okhttp3:okhttp:4.0.0-alpha01' --> 'org.jetbrains.kotlin:kotlin-stdlib:1.3.30'
Dependency path 'OurApp:detox:unspecified' --> 'com.facebook.react:react-native:0.59.5' --> 'com.squareup.okio:okio:2.2.2' --> 'org.jetbrains.kotlin:kotlin-stdlib:1.2.60'
Dependency path 'OurApp:detox:unspecified' --> 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.0' --> 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.0' --> 'org.jetbrains.kotlin:kotlin-stdlib:1.3.0'
Constraint path 'OurApp:detox:unspecified' --> 'org.jetbrains.kotlin:kotlin-stdlib' strictly '1.3.0' because of the following reason: debugRuntimeClasspath uses version 1.3.0
Constraint path 'OurApp:detox:unspecified' --> 'org.jetbrains.kotlin:kotlin-stdlib' strictly '1.3.0' because of the following reason: debugRuntimeClasspath uses version 1.3.0
> Could not resolve org.jetbrains.kotlin:kotlin-stdlib-common:1.3.0.
Required by:
project :detox
> Cannot find a version of 'org.jetbrains.kotlin:kotlin-stdlib-common' that satisfies the version constraints:
Dependency path 'OurApp:detox:unspecified' --> 'com.squareup.okhttp3:okhttp:4.0.0-alpha01' --> 'org.jetbrains.kotlin:kotlin-stdlib:1.3.30' --> 'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.30'
Constraint path 'OurApp:detox:unspecified' --> 'org.jetbrains.kotlin:kotlin-stdlib-common' strictly '1.3.0' because of the following reason: debugRuntimeClasspath uses version 1.3.0
(i.e. the project indirectly depends on different versions of kotlin-stdlib
, such as 1.3.0
, 1.3.30
, 1.2.60
)
Detox requires the Kotlin standard-library as it's own dependency. Due to the many flavours by which Kotlin has been released, multiple dependencies often create a conflict.
For that, Detox allows for the exact specification of the standard library to use using two Gradle globals: detoxKotlinVersion
and detoxKotlinStdlib
. You can define both in your root build-script file (i.e.android/build.gradle
):
buildscript {
// ...
ext.detoxKotlinVersion = '1.3.0' // Detox' default is 1.2.0
ext.detoxKotlinStdlib = 'kotlin-stdlib-jdk7' // Detox' default is kotlin-stdlib-jdk8
}
As reported in issue #1450, sometimes the application under test would properly launch on an emulator/device when running Detox, but the test runner will hang and will not start running the actual tests.
More specifically, when this happens:
- Detox and the tests runner launch successfully, alongside the app being run (unless
launchApp: false
has been passed todetox.init()
), but the first test simply hangs forever (as explained). - Eventually, the test runner would time-out.
- The last reported Detox-logs before time-out would indicate the device failing to connect to the Detox tester on the host. For example:
detox[12345] DEBUG: [DetoxServer.js/CANNOT_FORWARD] role=testee not connected, cannot fw action (sessionId=11111111-2222-3333-4444-555555555555)
A common reason for this set of symptoms to take place is the lack of a clear-text network traffic policy configuration in app - the kind that would allow both the app and Detox to work properly. These Android developers blog posts (1, 2) elaborate on what should be configured for apps and how, in great length. The pain-point in this context is that in SDK 28, clear-text traffic was set to be denied by Android, by default. In that mode, Detox, which requires such traffic while testing, is blocked.
The solution here is therefore to first properly configure clear-text traffic and for all app flavors (e.g. release / debug) -- if you haven't already. Second, the app needs to be configured to allow for clear-text traffic between the emulator and the running host. Examples:
- Applying
android:usesCleartextTraffic="true""
in the application tag of the mainAndroidManifest.xml
(not recommended). - (Untested) Applying a base config denying clear-text (i.e. using
cleartextTrafficPermitted=false
, or just by omitting it altogether), and enabling it for the special-localhost domain:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">10.0.2.2</domain>
</domain-config>
</network-security-config>
10.0.2.2
is the IP equivalent to the localhost on the computer hosting the Android emulator, on Google emulators. On Genymotion ones, it is10.0.3.2
.