diff --git a/.gitignore b/.gitignore index 5d64756..3333b1c 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,6 @@ buck-out/ # Bundle artifact *.jsbundle + +# Installation artifacts +bin/android-wait-for-emulator \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5292ddc --- /dev/null +++ b/.travis.yml @@ -0,0 +1,100 @@ +notifications: + email: false +os: linux +dist: trusty # NOTE-RT: This needs to be `trusty`, android builds just hang on `xenial` :\ +env: + global: + - ANDROID_PLATFORM_VERSION=9 + - ANDROID_API_VERSION=28 + - ANDROID_TOOLS_BUILD_VERSION=4333796 # NOTE-RT: To match `ANDROID_API_VERSION` + - ANDROID_BUILD_TOOLS_VERSION=28.0.3 + - ANDROID_EMULATOR_PLATFORM_VERSION=6.0 + - ANDROID_EMULATOR_API_VERSION=23 + - ANDROID_EMULATOR_ABI=armeabi-v7a +jobs: + allow_failures: + - stage: E2E + name: Android (local) + include: + - language: node_js + node_js: 10 + cache: yarn + - stage: E2E + name: Android (local) + sudo: required + language: android + jdk: oraclejdk8 + cache: yarn + android: + components: + - tools + - platform-tools + before_install: + - export ANDROID_HOME=~/android-sdk + - export ANDROID_SDK_ROOT=$ANDROID_HOME + - | + if [ $TRAVIS_OS_NAME == "linux" ]; then + export DISPLAY=:99.0; + sh -e /etc/init.d/xvfb start; + sleep 3; # give xvfb some time to start + fi + - wget -q "https://dl.google.com/android/repository/sdk-tools-linux-$ANDROID_TOOLS_BUILD_VERSION.zip" -O android-sdk-tools.zip + - unzip -q android-sdk-tools.zip -d ${ANDROID_HOME} + - rm android-sdk-tools.zip + - PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/platform-tools + - mkdir -p ~/.android + - touch ~/.android/repositories.cfg + - yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses + - | + $ANDROID_HOME/tools/bin/sdkmanager \ + "tools" \ + "platform-tools" \ + "emulator" \ + "build-tools;$ANDROID_BUILD_TOOLS_VERSION" \ + "system-images;android-$ANDROID_EMULATOR_API_VERSION;google_apis;$ANDROID_EMULATOR_ABI" \ + "patcher;v4" \ + "platforms;android-$ANDROID_API_VERSION" \ + "platforms;android-$ANDROID_EMULATOR_API_VERSION" \ + "extras;google;google_play_services" \ + "extras;google;m2repository" \ + "extras;android;m2repository" > /dev/null + - openssl aes-256-cbc -K $encrypted_78b6aab41b54_key -iv $encrypted_78b6aab41b54_iv -in android/app/my-release-key.keystore.enc -out android/app/my-release-key.keystore -d + - export NODE_VERSION=${TRAVIS_NODE_VERSION:=10} + - nvm install $NODE_VERSION + - npm install -g yarn + install: + - yarn install + - npm run build:android + before_script: + - echo no | $ANDROID_HOME/tools/bin/avdmanager create avd -n $(node -p 'require("./package.json").name') -k "system-images;android-$ANDROID_EMULATOR_API_VERSION;google_apis;$ANDROID_EMULATOR_ABI" # NOTE-RT: This should really be `yarn run emulator:android:create` + # NOTE-RT: The following here should really be `npm run pree2e` + - EMU_ADDITIONAL_OPTIONS="-no-boot-anim -no-audio -no-window -memory 2048" + - EMU_PARAMS="-gpu off" + - $ANDROID_HOME/emulator/emulator -avd $(node -p 'require("./package.json").name') $EMU_PARAMS $EMU_ADDITIONAL_OPTIONS ${EMU_DEBUG} & echo $! > /tmp/$(node -p 'require("./package.json").name').emulator.android.pid; echo "Started Android emulator (`cat /tmp/$(node -p 'require("./package.json").name').emulator.android.pid`) from /tmp/$(node -p 'require("./package.json").name').emulator.android.pid" + - ./bin/android-wait-for-emulator + - $ANDROID_HOME/platform-tools/adb devices + - $ANDROID_HOME/platform-tools/adb shell input keyevent 82 & + - npm run appium:kill + - npm run appium:start + script: + - ANDROID_PLATFORM_VERSION=$ANDROID_EMULATOR_PLATFORM_VERSION JEST_TIMEOUT=600000 DEVICE_TIMEOUT=300000 DRIVER_INITIALIZATION_TIMEOUT=30000 npm run appium:test + after_script: + - npm run poste2e # NOTE-RT: Make sure we kill things and clean up + - android delete avd -n $(node -p 'require("./package.json").name') # NOTE-RT: This should really be `npm run emulator:android:delete` +# - name: E2E tests (iOS) +# os: osx +# language: objective-c +# podfile: ios/Podfile +# osx_image: xcode10.2 +# cache: +# - yarn +# - cocoapods +# before_install: +# - export NODE_VERSION=${TRAVIS_NODE_VERSION:=10} +# - nvm install $NODE_VERSION +# - npm install -g yarn +# install: +# - yarn install +# - pushd ios && pod install && popd ios + + diff --git a/README.md b/README.md index f3f11b5..92f48b3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ### Make it run with ```bash -npm install +yarn install ``` ### Create your Signed APK (For android) @@ -25,18 +25,23 @@ keytool -genkeypair -v -keystore my-release-key.keystore -alias my-key-alias -ke mv my-release-key.keystore android/app/ # Build the APK -npm run bs:android +yarn run bs:android ``` -### Run tests +### Run tests locally ```bash # Run unit & integration tests -npm test +yarn test -# Run E2E tests locally -npm run test:e2e +# Create an AVD to run tests against locally +yarn run emulator:android:create +# Run E2E tests locally +yarn run test:e2e +``` +### Run tests in the cloud +```bash # Setup for uploading to cloud services export APP_PATH=$(pwd)/android/app/build/outputs/apk/release/app-release.apk export APP_EXTENSION=apk @@ -51,14 +56,22 @@ export TESTOBJECT_ACCESS_KEY= export BROWSERSTACK_USERNAME= export BROWSERSTACK_ACCESS_KEY= +# BrowserStack free trial per https://www.perfecto.io/perfecto-free-trial/ +export PERFECTO_USERNAME= +export PERFECTO_PASSWORD= + # Upload and run tests on Sauce Labs (emulated) -npm run upload:e2e:sauce -npm run test:e2e:sauce +yarn run upload:e2e:sauce +yarn run test:e2e:sauce # Upload and run tests on Sauce Labs (real devices) -npm run upload:e2e:testobject -npm run test:e2e:testobject +yarn run upload:e2e:testobject +yarn run test:e2e:testobject # Run it on BrowserStack -npm run upload:e2e:browserstack -npm run test:e2e:browserstack +yarn run upload:e2e:browserstack +yarn run test:e2e:browserstack + +# Run it on Perfecto +yarn run upload:e2e:perfecto +yarn run test:e2e:perfecto ``` \ No newline at end of file diff --git a/android/app/my-release-key.keystore.enc b/android/app/my-release-key.keystore.enc new file mode 100644 index 0000000..f17e8e1 Binary files /dev/null and b/android/app/my-release-key.keystore.enc differ diff --git a/e2e/__tests__/appium-test-wd.js b/e2e/__tests__/appium-test-wd.js index fe58dec..33d205a 100644 --- a/e2e/__tests__/appium-test-wd.js +++ b/e2e/__tests__/appium-test-wd.js @@ -1,13 +1,14 @@ import path from 'path'; import * as wd from 'wd'; import * as capabilities from '../capabilities'; -import {DEVICE_TIMEOUT, JEST_TIMEOUT, TARGET_PLATFORM} from '../constants'; +import {DEVICE_TIMEOUT, DRIVER_INITIALIZATION_TIMEOUT, JEST_TIMEOUT, TARGET_PLATFORM} from '../constants'; + +jest.setTimeout(JEST_TIMEOUT); describe('Create Android session (wd)', () => { let driver; beforeAll(async () => { - jest.setTimeout(JEST_TIMEOUT); const {capabilities: deviceConfig, ...serverConfig} = capabilities[TARGET_PLATFORM]; @@ -23,7 +24,7 @@ describe('Create Android session (wd)', () => { // Start the session await driver.init(deviceConfig) .setImplicitWaitTimeout(DEVICE_TIMEOUT) - .sleep(5000); + .sleep(DRIVER_INITIALIZATION_TIMEOUT); console.info('[beforeAll] driver initialized %j', driver); }); diff --git a/e2e/__tests__/appium-test-wdio.js.old b/e2e/__tests__/appium-test-wdio.js similarity index 94% rename from e2e/__tests__/appium-test-wdio.js.old rename to e2e/__tests__/appium-test-wdio.js index 18cc361..abf1e9f 100644 --- a/e2e/__tests__/appium-test-wdio.js.old +++ b/e2e/__tests__/appium-test-wdio.js @@ -1,7 +1,7 @@ -import * as wdio from 'webdriverio'; -import * as capabilities from '../capabilities'; -import {JEST_TIMEOUT, TARGET_PLATFORM} from '../constants'; -import path from 'path'; +import path from 'path' +import * as wdio from 'webdriverio' +import * as capabilities from '../capabilities' +import {JEST_TIMEOUT, TARGET_PLATFORM} from '../constants' xdescribe('Create Android session (wdio)', () => { let client; diff --git a/e2e/capabilities.js b/e2e/capabilities.js index b539aac..301bebf 100644 --- a/e2e/capabilities.js +++ b/e2e/capabilities.js @@ -1,5 +1,9 @@ +import {version as appiumVersion} from 'appium/package.json' +import {name} from '../package.json' import { ANDROID_APPLICATION_PATH, + ANDROID_AVD_ARGS, + ANDROID_AVD_NAME, ANDROID_DEVICE_NAME, ANDROID_PLATFORM_VERSION, APPIUM_HOST, @@ -12,9 +16,7 @@ import { IOS_DEVICE_NAME, IOS_PLATFORM_VERSION, TARGET_PLATFORM -} from './constants'; -import {name} from '../package.json'; -import {version as appiumVersion} from 'appium/package.json'; +} from './constants' const common = { hostname: APPIUM_HOST, @@ -26,7 +28,8 @@ const common = { appiumVersion, waitforTimeout: DEVICE_TIMEOUT, commandTimeout: DEVICE_TIMEOUT, - newCommandTimeout: DEVICE_TIMEOUT + newCommandTimeout: DEVICE_TIMEOUT, + isHeadless: process.env.HEADLESS || process.env.CI || false } }; @@ -38,6 +41,8 @@ if (process.env.BROWSERSTACK) { common.capabilities['browserstack.debug'] = true; common.capabilities['browserstack.video'] = true; common.capabilities['browserstack.networkLogs'] = true; + common.capabilities.appiumVersion = '1.9.1' // FIXME-RT: Ugh. 🤞 this doesn't break 'cause we're actually on 1.12.1 + common.capabilities['browserstack.appium_version'] = common.capabilities.appiumVersion common.capabilities.build = `${name}:${TARGET_PLATFORM}`; } @@ -58,6 +63,12 @@ if (process.env.TESTOBJECT) { common.capabilities.privateDevicesOnly = process.env.TESTOBJECT_PRIVATE_DEVICES_ONLY ? JSON.parse(process.env.TESTOBJECT_PRIVATE_DEVICES_ONLY) : false; } +if (process.env.PERFECTO) { + // NOTE-RT: These seem to be a constant requirement, but my testing seems to indicate that it's not required for auth. And still the expected `user` value isn't consistent. + common.capabilities.user = common.user; // NOTE-RT: Per https://developers.perfectomobile.com/pages/viewpage.action?pageId=11174626, but their broken JS WDIO example wants a `@perfectomobile.com` appended to the end... https://github.com/PerfectoCode/Samples/tree/master/Appium/JavaScript#getting-started + common.capabilities.password = common.pwd; +} + export const android = { ...common, capabilities: { @@ -66,7 +77,19 @@ export const android = { automationName: 'UiAutomator2', deviceName: ANDROID_DEVICE_NAME, platformVersion: ANDROID_PLATFORM_VERSION, - app: ANDROID_APPLICATION_PATH + app: ANDROID_APPLICATION_PATH, + adbExecTimeout: 30, + deviceReadyTimeout: DEVICE_TIMEOUT / 1000, // NOTE-RT: This is actually just in seconds + androidDeviceReadyTimeout: DEVICE_TIMEOUT / 1000, // NOTE-RT: This is actually just in seconds + androidInstallTimeout: DEVICE_TIMEOUT, + appWaitDuration: 10, + avdLaunchTimeout: DEVICE_TIMEOUT, + avdReadyTimeout: DEVICE_TIMEOUT, + uiautomator2ServerInstallTimeout: DEVICE_TIMEOUT, + uiautomator2ServerLaunchTimeout: DEVICE_TIMEOUT, + disableWindowAnimation: process.env.HEADLESS || process.env.CI || false, + avd: ANDROID_AVD_NAME, + avdArgs: ANDROID_AVD_ARGS } }; @@ -94,11 +117,22 @@ if (process.env.SAUCE) { delete android.capabilities.waitforTimeout; delete android.capabilities.commandTimeout; delete android.capabilities.newCommandTimeout; + delete android.capabilities.adbExecTimeout; + delete android.capabilities.deviceReadyTimeout; + delete android.capabilities.androidDeviceReadyTimeout; + delete android.capabilities.androidInstallTimeout; + delete android.capabilities.appWaitDuration; + delete android.capabilities.avdLaunchTimeout; + delete android.capabilities.avdReadyTimeout; + delete android.capabilities.uiautomator2ServerInstallTimeout; + delete android.capabilities.uiautomator2ServerLaunchTimeout; + delete android.capabilities.disableWindowAnimation; android.capabilities.automationName = android.capabilities.automationName.toLowerCase(); // NOTE-RT: Sauce Labs wants this to be lowercase for some reason delete ios.capabilities.waitforTimeout; delete ios.capabilities.commandTimeout; delete ios.capabilities.newCommandTimeout; + delete ios.capabilities.adbExecTimeout; } if (process.env.TESTOBJECT) { @@ -107,4 +141,39 @@ if (process.env.TESTOBJECT) { delete ios.capabilities.deviceName; // FIXME-RT: Per the above delete ios.capabilities.platformVersion; // FIXME-RT: Per the above +} + +if (process.env.PERFECTO) { + delete android.capabilities.appiumVersion; + delete android.capabilities.waitforTimeout; + delete android.capabilities.commandTimeout; + delete android.capabilities.newCommandTimeout; + delete android.capabilities.adbExecTimeout; + delete android.capabilities.deviceReadyTimeout; + delete android.capabilities.androidDeviceReadyTimeout; + delete android.capabilities.androidInstallTimeout; + delete android.capabilities.appWaitDuration; + delete android.capabilities.avdLaunchTimeout; + delete android.capabilities.avdReadyTimeout; + delete android.capabilities.uiautomator2ServerInstallTimeout; + delete android.capabilities.uiautomator2ServerLaunchTimeout; + delete android.capabilities.disableWindowAnimation; + delete android.capabilities.deviceName; + delete android.capabilities.isHeadless; + android.capabilities.automationInfrastructure = 'UIAutomator2'; // NOTE-RT: https://developers.perfectomobile.com/display/TT/Select+a+Device+Based+on+Automation+Infrastructure differs from https://developers.perfectomobile.com/display/PD/Supported+Appium+Capabilities... + android.capabilities.automationName = android.capabilities.automationInfrastructure; // NOTE-RT: Per https://developers.perfectomobile.com/display/PD/Supported+Appium+Capabilities + android.capabilities.appPackage = 'com.apktest'; // NOTE-RT: Per https://developers.perfectomobile.com/display/PD/Supported+Appium+Capabilities#SupportedAppiumCapabilities-Android + android.capabilities.appActivity = '.MainActivity'; // NOTE-RT: Per https://developers.perfectomobile.com/display/PD/Supported+Appium+Capabilities#SupportedAppiumCapabilities-Android + // NOTE-RT: I shouldn't need these according to https://developers.perfectomobile.com/pages/viewpage.action?pageId=11174626 I can't get a matching capability + // android.capabilities.manufacturer = "Samsung"; + // android.capabilities.model = "Galaxy S10e"; + // android.capabilities.resolution = "1080x2280"; + // android.capabilities.deviceName = 'R58M21YXQBL'; + + delete ios.capabilities.appiumVersion; + delete ios.capabilities.waitforTimeout; + delete ios.capabilities.commandTimeout; + delete ios.capabilities.newCommandTimeout; + delete ios.capabilities.adbExecTimeout; + // ios.capabilities.deviceName = '17E62A82172A36293D316B522623430FD9D7EA0C'; } \ No newline at end of file diff --git a/e2e/constants.js b/e2e/constants.js index e755a0b..fa86b09 100644 --- a/e2e/constants.js +++ b/e2e/constants.js @@ -1,21 +1,26 @@ import path from 'path'; +import {name} from '../package.json'; -export const ANDROID_DEVICE_NAME = process.env.ANDROID_DEVICE_NAME || 'Nexus_5X_API_28'; -export const ANDROID_PLATFORM_VERSION = process.env.ANDROID_PLATFORM_VERSION || '9'; +export const ANDROID_AVD_NAME = process.env.ANDROID_AVD_NAME; +export const ANDROID_AVD_ARGS = process.env.ANDROID_AVD_ARGS; +export const ANDROID_DEVICE_NAME = process.env.ANDROID_DEVICE_NAME || ANDROID_AVD_NAME || name; +export const ANDROID_PLATFORM_VERSION = process.env.ANDROID_PLATFORM_VERSION; export const ANDROID_APPLICATION_PATH = process.env.ANDROID_APPLICATION_PATH || path.resolve(__dirname, '../android/app/build/outputs/apk/release/app-release.apk'); -export const DEVICE_TIMEOUT = process.env.DEVICE_TIMEOUT || 90 * 1000; +export const DEVICE_TIMEOUT = process.env.DEVICE_TIMEOUT || 1.5 * 60 * 1000; -export const IOS_DEVICE_NAME = process.env.IOS_DEVICE_NAME || 'iPhone SE'; -export const IOS_PLATFORM_VERSION = process.env.IOS_PLATFORM_VERSION || '12.1'; +export const DRIVER_INITIALIZATION_TIMEOUT = process.env.DRIVER_INITIALIZATION_TIMEOUT || 5 * 1000; + +export const IOS_DEVICE_NAME = process.env.IOS_DEVICE_NAME; +export const IOS_PLATFORM_VERSION = process.env.IOS_PLATFORM_VERSION; export const IOS_APPLICATION_PATH = process.env.IOS_APPLICATION_PATH; // FIXME-RT: Provide a real directory here export const APPIUM_HOST = process.env.APPIUM_HOST || 'localhost'; export const APPIUM_LOG_LEVEL = process.env.APPIUM_LOG_LEVEL || 'debug'; -export const APPIUM_PASSWORD = process.env.APPIUM_PASSWORD || undefined; +export const APPIUM_PASSWORD = process.env.APPIUM_PASSWORD; export const APPIUM_PORT = process.env.APPIUM_PORT && Number(process.env.APPIUM_PORT) || 4723; -export const APPIUM_USER = process.env.APPIUM_USER || undefined; +export const APPIUM_USER = process.env.APPIUM_USER; export const TARGET_PLATFORM = process.env.TARGET_PLATFORM || 'android'; -export const JEST_TIMEOUT = process.env.JEST_TIMEOUT || 180 * 1000; +export const JEST_TIMEOUT = process.env.JEST_TIMEOUT || 3 * 60 * 1000; diff --git a/e2e/jest.config.json b/e2e/jest.config.json index 1238c70..e5c211f 100644 --- a/e2e/jest.config.json +++ b/e2e/jest.config.json @@ -1,3 +1,4 @@ { + "testRunner": "jest-circus/runner", "verbose": true } diff --git a/jest.config.json b/jest.config.json index 3821fc1..7febdfe 100644 --- a/jest.config.json +++ b/jest.config.json @@ -5,5 +5,6 @@ "/node_modules/", "/e2e/" ], + "testRunner": "jest-circus/runner", "verbose": true } diff --git a/package.json b/package.json index df78b85..70e1467 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,8 @@ "version": "0.0.1", "private": true, "scripts": { + "postinstall": "npm run postinstall:download:android-wait-for-emulator", + "postinstall:download:android-wait-for-emulator": "if [ ! -f bin/android-wait-for-emulator ]; then mkdir -p bin; curl https://raw.githubusercontent.com/travis-ci/travis-cookbooks/precise-stable/ci_environment/android-sdk/files/default/android-wait-for-emulator > bin/android-wait-for-emulator; chmod +x bin/android-wait-for-emulator; fi;", "start": "node node_modules/react-native/local-cli/cli.js start", "start:android": "adb uninstall com.apktest && react-native run-android", "start:android:release": "react-native run-android --variant=release", @@ -11,21 +13,28 @@ "test:e2e:sauce": "SAUCE=true ANDROID_DEVICE_NAME='Google Pixel GoogleAPI Emulator' ANDROID_PLATFORM_VERSION=8.1 APPIUM_HOST=ondemand.eu-central-1.saucelabs.com APPIUM_PORT=80 APPIUM_USER=$SAUCE_USERNAME APPIUM_PASSWORD=$SAUCE_ACCESS_KEY ANDROID_APPLICATION_PATH=\"sauce-storage:$(node -p 'require(\"./package.json\").name').$APP_EXTENSION\" IOS_APPLICATION_PATH=\"sauce-storage:$(node -p 'require(\"./package.json\").name').$APP_EXTENSION\" jest --config e2e/jest.config.json --runInBand", "test:e2e:testobject": "TESTOBJECT=true ANDROID_DEVICE_NAME='LG Nexus 5X Free' ANDROID_PLATFORM_VERSION=8.1 APPIUM_HOST=eu1.appium.testobject.com APPIUM_PORT=80 APPIUM_USER=$SAUCE_USERNAME APPIUM_PASSWORD=$TESTOBJECT_ACCESS_KEY ANDROID_APPLICATION_PATH=\"sauce-storage:$(node -p 'require(\"./package.json\").name').$APP_EXTENSION\" IOS_APPLICATION_PATH=\"sauce-storage:$(node -p 'require(\"./package.json\").name').$APP_EXTENSION\" jest --config e2e/jest.config.json --runInBand", "test:e2e:browserstack": "BROWSERSTACK=true ANDROID_DEVICE_NAME='Google Pixel' ANDROID_PLATFORM_VERSION=7.1 IOS_DEVICE_NAME='iPhone 8 Plus' IOS_PLATFORM_VERSION=11 APPIUM_HOST=hub-cloud.browserstack.com APPIUM_PORT=80 APPIUM_USER=$BROWSERSTACK_USERNAME APPIUM_PASSWORD=$BROWSERSTACK_ACCESS_KEY ANDROID_APPLICATION_PATH=$BROWSERSTACK_USERNAME/$(node -p 'require(\"./package.json\").name').$APP_EXTENSION IOS_APPLICATION_PATH=$BROWSERSTACK_USERNAME/$(node -p 'require(\"./package.json\").name').$APP_EXTENSION jest --config e2e/jest.config.json --runInBand", + "test:e2e:perfecto": "PERFECTO=true ANDROID_PLATFORM_VERSION=9 IOS_PLATFORM_VERSION=12.1.4 APPIUM_HOST=mobilecloud.perfectomobile.com APPIUM_PORT=80 APPIUM_USER=$PERFECTO_USERNAME APPIUM_PASSWORD=$PERFECTO_PASSWORD ANDROID_APPLICATION_PATH=PRIVATE:$(node -p 'require(\"./package.json\").name').$APP_EXTENSION IOS_APPLICATION_PATH=PRIVATE:$(node -p 'require(\"./package.json\").name').$APP_EXTENSION jest --config e2e/jest.config.json --runInBand", "upload:e2e:sauce": "curl -v -u \"$SAUCE_USERNAME:$SAUCE_ACCESS_KEY\" -X POST https://eu-central-1.saucelabs.com/rest/v1/storage/$SAUCE_USERNAME/$(node -p 'require(\"./package.json\").name').$APP_EXTENSION?overwrite=true -H \"Content-Type: application/octet-stream\" --data-binary @$APP_PATH", "upload:e2e:testobject": "curl -v -u \"$SAUCE_USERNAME:$TESTOBJECT_ACCESS_KEY\" -X POST https://app.testobject.com:443/api/storage/upload -H \"Content-Type: application/octet-stream\" --data-binary @$APP_PATH", "upload:e2e:browserstack": "curl -v -u \"$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY\" -X POST https://api-cloud.browserstack.com/app-automate/upload -F \"file=@$APP_PATH\" -F \"data={\\\"custom_id\\\": \\\"$(node -p 'require(\"./package.json\").name').$APP_EXTENSION\\\"}\"", + "upload:e2e:perfecto": "curl -v -X POST \"https://mobilecloud.perfectomobile.com/services/repositories/media/PRIVATE:$(node -p 'require(\"./package.json\").name').$APP_EXTENSION?operation=upload&overwrite=true&user=$PERFECTO_USERNAME&password=$PERFECTO_PASSWORD&responseFormat=json\" -H \"Content-Type: application/octet-stream\" --data-binary @$APP_PATH --http1.1", "appium": "npm run appium:start", "appium:test": "npm run test:e2e", "clean:nodemodules": "rm -rf node_modules && rm -f package-lock.json && npm install", "build:android": "cd android && ./gradlew assembleRelease", "bs:android": "npm run build:android && adb uninstall com.apktest && npm run start:android:release", + "emulator:android:create": "echo no | avdmanager create avd -n $(node -p 'require(\"./package.json\").name') -k \"system-images;android-28;google_apis_playstore;x86\"", + "emulator:android:delete": "avdmanager delete avd -n $(node -p 'require(\"./package.json\").name')", + "emulator:android:start": "emulator -avd $(node -p 'require(\"./package.json\").name') -no-audio -no-window & echo $! > /tmp/$(node -p 'require(\"./package.json\").name').emulator.android.pid; echo \"Started Android emulator (`cat /tmp/$(node -p 'require(\"./package.json\").name').emulator.android.pid`) from /tmp/$(node -p 'require(\"./package.json\").name').emulator.android.pid\"; ./bin/android-wait-for-emulator", "appium:start": "appium & echo $! > /tmp/$(node -p 'require(\"./package.json\").name').appium.pid; echo \"Started server (`cat /tmp/$(node -p 'require(\"./package.json\").name').appium.pid`) from /tmp/$(node -p 'require(\"./package.json\").name').appium.pid\";", - "pree2e": "npm run appium:kill; npm run appium:start", + "pree2e": "npm run emulator:android:kill; npm run emulator:android:start; npm run appium:kill; npm run appium:start; adb wait-for-device get-serialno;", "e2e": "npm run appium:test", - "poste2e": "npm run appium:kill", - "appium:kill": "if [ -f /tmp/$(node -p 'require(\"./package.json\").name').appium.pid ]; then echo \"Killing appium (`cat /tmp/$(node -p 'require(\"./package.json\").name').appium.pid`) from /tmp/$(node -p 'require(\"./package.json\").name').appium.pid\"; kill -9 `cat /tmp/$(node -p 'require(\"./package.json\").name').appium.pid`; rm /tmp/$(node -p 'require(\"./package.json\").name').appium.pid; fi;" + "poste2e": "npm run appium:kill; npm run emulator:android:kill", + "appium:kill": "if [ -f /tmp/$(node -p 'require(\"./package.json\").name').appium.pid ]; then echo \"Killing appium (`cat /tmp/$(node -p 'require(\"./package.json\").name').appium.pid`) from /tmp/$(node -p 'require(\"./package.json\").name').appium.pid\"; kill -9 `cat /tmp/$(node -p 'require(\"./package.json\").name').appium.pid`; rm /tmp/$(node -p 'require(\"./package.json\").name').appium.pid; fi;", + "emulator:android:kill": "if [ -f /tmp/$(node -p 'require(\"./package.json\").name').emulator.android.pid ]; then echo \"Killing Android emulator (`cat /tmp/$(node -p 'require(\"./package.json\").name').emulator.android.pid`) from /tmp/$(node -p 'require(\"./package.json\").name').emulator.android.pid\"; kill -9 `cat /tmp/$(node -p 'require(\"./package.json\").name').emulator.android.pid`; rm /tmp/$(node -p 'require(\"./package.json\").name').emulator.android.pid; fi;" }, "dependencies": { + "jest-circus": "^24.7.1", "react": "16.8.3", "react-native": "0.59.4" }, diff --git a/yarn.lock b/yarn.lock index fbec858..c81d29f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4736,6 +4736,28 @@ jest-changed-files@^24.7.0: execa "^1.0.0" throat "^4.0.0" +jest-circus@^24.7.1: + version "24.7.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-24.7.1.tgz#f8dc4db5217eb010d71ad2f5b6e6f357590ccd01" + integrity sha512-zDNSS+7qQN0nSbR77qcOb+tOUWLcvZGzvXE1PjoV6xeHV5Vz7DPK9JkBIQF/n5Nz9yZbApDxq5NqGqmVCe0nnQ== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^24.7.1" + "@jest/test-result" "^24.7.1" + "@jest/types" "^24.7.0" + chalk "^2.0.1" + co "^4.6.0" + expect "^24.7.1" + is-generator-fn "^2.0.0" + jest-each "^24.7.1" + jest-matcher-utils "^24.7.0" + jest-message-util "^24.7.1" + jest-snapshot "^24.7.1" + jest-util "^24.7.1" + pretty-format "^24.7.0" + stack-utils "^1.0.1" + throat "^4.0.0" + jest-cli@^24.7.1: version "24.7.1" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.7.1.tgz#6093a539073b6f4953145abeeb9709cd621044f1"