Skip to content

Commit

Permalink
Use detox to test Android app
Browse files Browse the repository at this point in the history
  • Loading branch information
levibuzolic committed May 18, 2021
1 parent ffc1a23 commit 5245041
Show file tree
Hide file tree
Showing 14 changed files with 864 additions and 31 deletions.
File renamed without changes.
72 changes: 72 additions & 0 deletions .github/workflows/detox.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Detox Android

on:
pull_request:
branches:
- master

jobs:
build:
runs-on: macos-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@v2

- uses: actions/setup-node@v2
with:
node-version: '14'

- uses: c-hive/gha-yarn-cache@v1
- name: Yarn
run: |
cd ExampleProject
yarn install --frozen-lockfile
- name: Use specific Java version for sdkmanager to work
uses: joschi/setup-jdk@v2
with:
java-version: '8'
architecture: 'x64'

- name: Cache Gradle Wrapper
uses: actions/cache@v2
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

- name: Cache Gradle Dependencies
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-caches-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-caches-
- name: Download Android Emulator Image
run: |
echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install "system-images;android-29;google_apis;x86"
echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd --force --name Pixel_3a_API_30_x86 --device "Nexus 5X" -k 'system-images;android-29;google_apis;x86'
$ANDROID_HOME/emulator/emulator -list-avds
- name: Android Emulator
timeout-minutes: 10
continue-on-error: true
run: |
echo "Starting emulator"
nohup $ANDROID_HOME/emulator/emulator -avd Pixel_3a_API_30_x86 -no-audio -no-snapshot -no-window &
$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done; input keyevent 82'
$ANDROID_HOME/platform-tools/adb devices
echo "Emulator started"
- name: Build for detox
run: |
cd ExampleProject
yarn run react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/
yarn run build-detox-android
- name: Android Detox
run: |
cd ExampleProject
yarn run test-detox-android
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ buck-out/

# Bundle artifact
*.jsbundle
ExampleProject/android/app/src/main/assets/index.android.bundle
44 changes: 44 additions & 0 deletions ExampleProject/.detoxrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"testRunner": "jest",
"runnerConfig": "e2e/config.json",
"apps": {
"ios": {
"type": "ios.app",
"binaryPath": "SPECIFY_PATH_TO_YOUR_APP_BINARY"
},
"android.debug": {
"type": "android.apk",
"binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
"build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug --no-daemon && cd .."
},
"android.release": {
"type": "android.apk",
"binaryPath": "android/app/build/outputs/apk/release/app-release.apk",
"build": "cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release --no-daemon && cd .."
}
},
"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.debug": {
"device": "emulator",
"app": "android.debug"
}
}
}
3 changes: 1 addition & 2 deletions ExampleProject/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function Row({label, value}) {
<View
style={styles.row}
accessibilityLabel={`${label}: ${value?.toString() ?? 'unknown'}`}>
<Text style={styles.label}>{label}:</Text>
<Text style={styles.label}>{`${label}: `}</Text>
<Text style={styles.value}>{value?.toString() ?? 'unknown'}</Text>
</View>
);
Expand Down Expand Up @@ -98,7 +98,6 @@ const styles = StyleSheet.create({
fontSize: 16,
color: '#444',
fontWeight: '700',
marginRight: 5,
},
value: {
fontSize: 16,
Expand Down
4 changes: 4 additions & 0 deletions ExampleProject/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
splits {
abi {
Expand Down Expand Up @@ -210,6 +212,8 @@ dependencies {
} else {
implementation jscFlavor
}

androidTestImplementation('com.wix:detox:+')
}

// Run this once to be able to run the application with BUCK
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Replace "com.example" here and below with your app's package name from the top of MainActivity.java
package com.example;

import com.wix.detox.Detox;
import com.wix.detox.config.DetoxConfig;

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
// Replace 'MainActivity' with the value of android:name entry in
// <activity> in AndroidManifest.xml
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);

@Test
public void runDetoxTests() {
DetoxConfig detoxConfig = new DetoxConfig();
detoxConfig.idlePolicyConfig.masterTimeoutSec = 90;
detoxConfig.idlePolicyConfig.idleResourceTimeoutSec = 60;
detoxConfig.rnContextLoadTimeoutSec = (com.example.BuildConfig.DEBUG ? 180 : 60);

Detox.runTests(mActivityRule, detoxConfig);
}
}
4 changes: 4 additions & 0 deletions ExampleProject/android/app/src/main/res/raw/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "Example",
"displayName": "Example"
}
4 changes: 4 additions & 0 deletions ExampleProject/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ allprojects {
google()
jcenter()
maven { url 'https://www.jitpack.io' }
maven {
// All of Detox' artifacts are provided via the npm module
url "$rootDir/../node_modules/detox/Detox-android"
}
}
}
8 changes: 8 additions & 0 deletions ExampleProject/e2e/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"testEnvironment": "./environment",
"testRunner": "jest-circus/runner",
"testTimeout": 120000,
"testRegex": "\\.e2e\\.js$",
"reporters": ["detox/runners/jest/streamlineReporter"],
"verbose": true
}
23 changes: 23 additions & 0 deletions ExampleProject/e2e/environment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const {
DetoxCircusEnvironment,
SpecReporter,
WorkerAssignReporter,
} = require('detox/runners/jest-circus');

class CustomDetoxEnvironment extends DetoxCircusEnvironment {
constructor(config, context) {
super(config, context);

// Can be safely removed, if you are content with the default value (=300000ms)
this.initTimeout = 300000;

// This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
// This is strictly optional.
this.registerListeners({
SpecReporter,
WorkerAssignReporter,
});
}
}

module.exports = CustomDetoxEnvironment;
42 changes: 42 additions & 0 deletions ExampleProject/e2e/test.e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-disable no-undef */

describe('Example', () => {
beforeAll(async () => {
await device.launchApp();
await device.reloadReactNative();
});

it('isJailBroken', async () => {
await expect(element(by.label('isJailBroken: true'))).toBeVisible();
});

it('canMockLocation', async () => {
await expect(element(by.label('canMockLocation: false'))).toBeVisible();
});

it('trustFall', async () => {
await expect(element(by.label('trustFall: true'))).toBeVisible();
});

it('hookDetected', async () => {
await expect(element(by.label('hookDetected: false'))).toBeVisible();
});

it('isOnExternalStorage', async () => {
await expect(element(by.label('isOnExternalStorage: false'))).toBeVisible();
});

it('AdbEnabled', async () => {
await expect(element(by.label('AdbEnabled: true'))).toBeVisible();
});

it('isDevelopmentSettingsMode', async () => {
await expect(
element(by.label('isDevelopmentSettingsMode: false')),
).toBeVisible();
});

it('isDebuggedMode', async () => {
await expect(element(by.label('isDebuggedMode: true'))).toBeVisible();
});
});
8 changes: 7 additions & 1 deletion ExampleProject/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint ."
"lint": "eslint .",
"build-detox-android": "detox build -c android.debug",
"test-detox-android": "detox test -c android.debug"
},
"dependencies": {
"jail-monkey": "../",
Expand All @@ -19,9 +21,13 @@
"@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0",
"babel-jest": "^26.6.3",
"detox": "^18.13.0",
"eslint": "7.14.0",
"jest": "^26.6.3",
"jest-circus": "^26.6.3",
"jest-environment-node": "^26.6.2",
"metro-react-native-babel-preset": "^0.64.0",
"mocha": "^8.4.0",
"react-test-renderer": "17.0.1"
},
"jest": {
Expand Down
Loading

0 comments on commit 5245041

Please sign in to comment.