From c379c0eae43d8142e4eb83bcb164b843a46323b3 Mon Sep 17 00:00:00 2001 From: Krzysztof Borowy Date: Sun, 17 Feb 2019 21:18:09 +0100 Subject: [PATCH 1/6] feat: add detox, setup basic tests --- .eslintrc | 5 +- example/android/app/build.gradle | 9 + .../com/asyncstorageexample/DetoxTest.java | 24 ++ example/android/build.gradle | 8 +- example/android/settings.gradle | 3 + example/e2e/asyncstorage.spec.js | 50 ++++ example/e2e/config.json | 4 + example/e2e/init.js | 19 ++ example/src/App.js | 37 ++- example/src/examples/ClearSingle.js | 6 +- example/src/examples/GetSet.js | 21 +- package.json | 27 +- yarn.lock | 256 +++++++++++++++++- 13 files changed, 436 insertions(+), 33 deletions(-) create mode 100644 example/android/app/src/androidTest/java/com/asyncstorageexample/DetoxTest.java create mode 100644 example/e2e/asyncstorage.spec.js create mode 100644 example/e2e/config.json create mode 100644 example/e2e/init.js diff --git a/.eslintrc b/.eslintrc index 61b3a62c..b8b5dcd1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -51,7 +51,10 @@ "setInterval": false, "setTimeout": false, "window": false, - "XMLHttpRequest": false + "XMLHttpRequest": false, + "device": true, + "element": true, + "by": true }, "rules": { diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 5af21ec5..4fb07439 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -103,6 +103,9 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" + testBuildType System.getProperty('testBuildType', 'debug') + missingDimensionStrategy "minReactNative", "minReactNative46" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } splits { abi { @@ -137,6 +140,12 @@ dependencies { implementation project(':rnAsyncStorage') implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}" implementation "com.facebook.react:react-native:+" // From node_modules + + // tests + androidTestImplementation(project(path: ":detox")) + androidTestImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.1' + androidTestImplementation 'com.android.support.test:rules:1.0.1' } // Run this once to be able to run the application with BUCK diff --git a/example/android/app/src/androidTest/java/com/asyncstorageexample/DetoxTest.java b/example/android/app/src/androidTest/java/com/asyncstorageexample/DetoxTest.java new file mode 100644 index 00000000..eeb9ae91 --- /dev/null +++ b/example/android/app/src/androidTest/java/com/asyncstorageexample/DetoxTest.java @@ -0,0 +1,24 @@ +package com.asyncstorageexample; + +import android.support.test.filters.LargeTest; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; + +import com.wix.detox.Detox; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class DetoxTest { + + @Rule + public ActivityTestRule mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false); + + @Test + public void runDetoxTests() throws InterruptedException { + Detox.runTests(mActivityRule); + } +} \ No newline at end of file diff --git a/example/android/build.gradle b/example/android/build.gradle index f84862ff..050db5f6 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -2,11 +2,13 @@ buildscript { ext { + kotlinVersion = '1.3.0' buildToolsVersion = "28.0.3" - minSdkVersion = 16 + minSdkVersion = 19 compileSdkVersion = 28 targetSdkVersion = 27 supportLibVersion = "28.0.0" + detoxKotlinVersion = kotlinVersion } repositories { google() @@ -14,9 +16,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } } diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 1d2109a8..9791199f 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -2,5 +2,8 @@ rootProject.name = 'AsyncStorageExample' include ':app' include ':rnAsyncStorage' +include ':detox' + project(':rnAsyncStorage').projectDir = new File(rootProject.projectDir, '../../android') +project(':detox').projectDir = new File(rootProject.projectDir, '../../node_modules/detox/android/detox') \ No newline at end of file diff --git a/example/e2e/asyncstorage.spec.js b/example/e2e/asyncstorage.spec.js new file mode 100644 index 00000000..299e943d --- /dev/null +++ b/example/e2e/asyncstorage.spec.js @@ -0,0 +1,50 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +describe('Async Storage', () => { + let restartButton; + let clearButton; + let increaseByTenButton; + let storedNumberText; + + beforeAll(async () => { + await device.reloadReactNative(); + restartButton = await element(by.id('restart_button')); + clearButton = await element(by.id('clear_button')); + increaseByTenButton = await element(by.id('increaseByTen_button')); + storedNumberText = await element(by.id('text_storedNumber')); + }); + + it('should load all examples', async () => { + await expect(element(by.id('examples_container'))).toExist(); + await expect(element(by.id('example-clear'))).toExist(); + await expect(element(by.id('example-get-set'))).toExist(); + }); + + it('should store value in async storage', async () => { + await expect(storedNumberText).toHaveText(''); + + const tapTimes = Math.round(Math.random() * 9) + 1; + + for (let i = 0; i < tapTimes; i++) { + await increaseByTenButton.tap(); + } + + await expect(storedNumberText).toHaveText(`${tapTimes * 10}`); + await restartButton.tap(); + await expect(storedNumberText).toHaveText(`${tapTimes * 10}`); + }); + + it('should clear async storage', async () => { + await increaseByTenButton.tap(); + await clearButton.tap(); + await restartButton.tap(); + await expect(storedNumberText).toHaveText(''); + }); +}); diff --git a/example/e2e/config.json b/example/e2e/config.json new file mode 100644 index 00000000..c421b857 --- /dev/null +++ b/example/e2e/config.json @@ -0,0 +1,4 @@ +{ + "setupTestFrameworkScriptFile": "./init.js", + "testEnvironment": "node" +} \ No newline at end of file diff --git a/example/e2e/init.js b/example/e2e/init.js new file mode 100644 index 00000000..78be9377 --- /dev/null +++ b/example/e2e/init.js @@ -0,0 +1,19 @@ +const detox = require('detox'); +const config = require('../../package.json').detox; +const adapter = require('detox/runners/jest/adapter'); + +jest.setTimeout(120000); +jasmine.getEnv().addReporter(adapter); + +beforeAll(async () => { + await detox.init(config); +}); + +beforeEach(async () => { + await adapter.beforeEach(); +}); + +afterAll(async () => { + await adapter.afterAll(); + await detox.cleanup(); +}); diff --git a/example/src/App.js b/example/src/App.js index d5c10fbc..42cdfffe 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -15,6 +15,7 @@ import { Text, TouchableOpacity, View, + ScrollView, } from 'react-native'; import SimpleGetSet from './examples/GetSet'; @@ -23,6 +24,7 @@ import ClearStorage from './examples/ClearSingle'; const EXAMPLES = [ { title: 'Simple Get/Set value', + testId: 'get-set', description: 'Store and retrieve persisted data', render() { return ; @@ -30,6 +32,7 @@ const EXAMPLES = [ }, { title: 'Clear', + testId: 'clear', description: 'Clear persisting data storage', render() { return ; @@ -54,26 +57,32 @@ export default class App extends Component { return ( Simulate Restart - {restarting - ? null - : EXAMPLES.map(example => { - return ( - - {example.title} - - {example.description} - - - {example.render()} + + {restarting + ? null + : EXAMPLES.map(example => { + return ( + + {example.title} + + {example.description} + + + {example.render()} + - - ); - })} + ); + })} + ); } diff --git a/example/src/examples/ClearSingle.js b/example/src/examples/ClearSingle.js index 41e95d14..a0c71cbd 100644 --- a/example/src/examples/ClearSingle.js +++ b/example/src/examples/ClearSingle.js @@ -34,7 +34,11 @@ export default class Clear extends Component { const {needRestart} = this.state; return ( -