1*fe5cfb17STomasz Sapeta/** 2*fe5cfb17STomasz Sapeta * Copyright (c) Meta Platforms, Inc. and affiliates. 3*fe5cfb17STomasz Sapeta * 4*fe5cfb17STomasz Sapeta * This source code is licensed under the MIT license found in the 5*fe5cfb17STomasz Sapeta * LICENSE file in the root directory of this source tree. 6*fe5cfb17STomasz Sapeta * 7*fe5cfb17STomasz Sapeta * @format 8*fe5cfb17STomasz Sapeta */ 9*fe5cfb17STomasz Sapeta 10*fe5cfb17STomasz Sapeta// Used in run-ci-e2e-test.js and executed in Circle CI. 11*fe5cfb17STomasz Sapeta// 12*fe5cfb17STomasz Sapeta// E2e test that verifies that init app can be installed, compiled, started and 13*fe5cfb17STomasz Sapeta// Hot Module reloading and Chrome debugging work. 14*fe5cfb17STomasz Sapeta// 15*fe5cfb17STomasz Sapeta// For other examples of appium refer to: 16*fe5cfb17STomasz Sapeta// https://github.com/appium/sample-code/tree/master/sample-code/examples/node and 17*fe5cfb17STomasz Sapeta// https://www.npmjs.com/package/wd-android 18*fe5cfb17STomasz Sapeta// 19*fe5cfb17STomasz Sapeta// To set up: 20*fe5cfb17STomasz Sapeta// - npm install --save-dev [email protected] [email protected] [email protected] [email protected] [email protected] 21*fe5cfb17STomasz Sapeta// - cp <this file> <to app installation path> 22*fe5cfb17STomasz Sapeta// - keytool -genkey -v -keystore android/app/debug.keystore -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "CN=Android Debug,O=Android,C=US" 23*fe5cfb17STomasz Sapeta// 24*fe5cfb17STomasz Sapeta// To run this test: 25*fe5cfb17STomasz Sapeta// - npm start 26*fe5cfb17STomasz Sapeta// - node node_modules/.bin/appium 27*fe5cfb17STomasz Sapeta// - (cd android && ./gradlew :app:copyDownloadableDepsToLibs) 28*fe5cfb17STomasz Sapeta// - react-native run-android 29*fe5cfb17STomasz Sapeta// - node ../node_modules/.bin/_mocha ../android-e2e-test.js 30*fe5cfb17STomasz Sapeta 31*fe5cfb17STomasz Sapeta/* eslint-env mocha */ 32*fe5cfb17STomasz Sapeta 33*fe5cfb17STomasz Sapeta'use strict'; 34*fe5cfb17STomasz Sapeta 35*fe5cfb17STomasz Sapetaconst wd = require('wd'); 36*fe5cfb17STomasz Sapetaconst path = require('path'); 37*fe5cfb17STomasz Sapetaconst fs = require('fs'); 38*fe5cfb17STomasz Sapetaconst pd = require('pretty-data2').pd; 39*fe5cfb17STomasz Sapeta 40*fe5cfb17STomasz Sapeta// value in ms to print out screen contents, set this value in CI to debug if tests are failing 41*fe5cfb17STomasz Sapetaconst appiumDebugInterval = process.env.APPIUM_DEBUG_INTERVAL; 42*fe5cfb17STomasz Sapeta 43*fe5cfb17STomasz Sapetadescribe('Android Test App', function () { 44*fe5cfb17STomasz Sapeta this.timeout(600000); 45*fe5cfb17STomasz Sapeta let driver; 46*fe5cfb17STomasz Sapeta let debugIntervalId; 47*fe5cfb17STomasz Sapeta 48*fe5cfb17STomasz Sapeta before(function () { 49*fe5cfb17STomasz Sapeta driver = wd.promiseChainRemote({ 50*fe5cfb17STomasz Sapeta host: 'localhost', 51*fe5cfb17STomasz Sapeta port: 4723, 52*fe5cfb17STomasz Sapeta }); 53*fe5cfb17STomasz Sapeta driver.on('status', function (info) { 54*fe5cfb17STomasz Sapeta console.log(info.cyan); 55*fe5cfb17STomasz Sapeta }); 56*fe5cfb17STomasz Sapeta driver.on('command', function (method, command, data) { 57*fe5cfb17STomasz Sapeta if (command === 'source()' && data) { 58*fe5cfb17STomasz Sapeta console.log( 59*fe5cfb17STomasz Sapeta ' > ' + method.yellow, 60*fe5cfb17STomasz Sapeta 'Screen contents'.grey, 61*fe5cfb17STomasz Sapeta '\n', 62*fe5cfb17STomasz Sapeta pd.xml(data).yellow, 63*fe5cfb17STomasz Sapeta ); 64*fe5cfb17STomasz Sapeta } else { 65*fe5cfb17STomasz Sapeta console.log(' > ' + method.yellow, command.grey, data || ''); 66*fe5cfb17STomasz Sapeta } 67*fe5cfb17STomasz Sapeta }); 68*fe5cfb17STomasz Sapeta driver.on('http', function (method, urlPath, data) { 69*fe5cfb17STomasz Sapeta console.log(' > ' + method.magenta, urlPath, (data || '').grey); 70*fe5cfb17STomasz Sapeta }); 71*fe5cfb17STomasz Sapeta 72*fe5cfb17STomasz Sapeta // every interval print what is on the screen 73*fe5cfb17STomasz Sapeta if (appiumDebugInterval) { 74*fe5cfb17STomasz Sapeta debugIntervalId = setInterval(() => { 75*fe5cfb17STomasz Sapeta // it driver.on('command') will log the screen contents 76*fe5cfb17STomasz Sapeta driver.source(); 77*fe5cfb17STomasz Sapeta }, appiumDebugInterval); 78*fe5cfb17STomasz Sapeta } 79*fe5cfb17STomasz Sapeta 80*fe5cfb17STomasz Sapeta const desired = { 81*fe5cfb17STomasz Sapeta platformName: 'Android', 82*fe5cfb17STomasz Sapeta deviceName: 'Android Emulator', 83*fe5cfb17STomasz Sapeta app: path.resolve('android/app/build/outputs/apk/debug/app-debug.apk'), 84*fe5cfb17STomasz Sapeta }; 85*fe5cfb17STomasz Sapeta 86*fe5cfb17STomasz Sapeta // React Native in dev mode often starts with Red Box "Can't fibd variable __fbBatchedBridge..." 87*fe5cfb17STomasz Sapeta // This is fixed by clicking Reload JS which will trigger a request to Metro 88*fe5cfb17STomasz Sapeta return driver 89*fe5cfb17STomasz Sapeta .init(desired) 90*fe5cfb17STomasz Sapeta .setImplicitWaitTimeout(5000) 91*fe5cfb17STomasz Sapeta .waitForElementByXPath('//android.widget.Button[@text="Reload JS"]') 92*fe5cfb17STomasz Sapeta .then( 93*fe5cfb17STomasz Sapeta elem => { 94*fe5cfb17STomasz Sapeta elem.click(); 95*fe5cfb17STomasz Sapeta driver.sleep(2000); 96*fe5cfb17STomasz Sapeta }, 97*fe5cfb17STomasz Sapeta // eslint-disable-next-line handle-callback-err 98*fe5cfb17STomasz Sapeta err => { 99*fe5cfb17STomasz Sapeta // ignoring if Reload JS button can't be located 100*fe5cfb17STomasz Sapeta }, 101*fe5cfb17STomasz Sapeta ); 102*fe5cfb17STomasz Sapeta }); 103*fe5cfb17STomasz Sapeta 104*fe5cfb17STomasz Sapeta after(function () { 105*fe5cfb17STomasz Sapeta if (debugIntervalId) { 106*fe5cfb17STomasz Sapeta clearInterval(debugIntervalId); 107*fe5cfb17STomasz Sapeta } 108*fe5cfb17STomasz Sapeta return driver.quit(); 109*fe5cfb17STomasz Sapeta }); 110*fe5cfb17STomasz Sapeta 111*fe5cfb17STomasz Sapeta it('should display new content after a refresh', function () { 112*fe5cfb17STomasz Sapeta const androidAppCode = fs.readFileSync('App.js', 'utf-8'); 113*fe5cfb17STomasz Sapeta let intervalToUpdate; 114*fe5cfb17STomasz Sapeta return ( 115*fe5cfb17STomasz Sapeta driver 116*fe5cfb17STomasz Sapeta .waitForElementByXPath( 117*fe5cfb17STomasz Sapeta '//android.widget.TextView[starts-with(@text, "Welcome to React")]', 118*fe5cfb17STomasz Sapeta ) 119*fe5cfb17STomasz Sapeta .then(() => { 120*fe5cfb17STomasz Sapeta fs.writeFileSync( 121*fe5cfb17STomasz Sapeta 'App.js', 122*fe5cfb17STomasz Sapeta androidAppCode.replace('Step One', 'Step 1'), 123*fe5cfb17STomasz Sapeta 'utf-8', 124*fe5cfb17STomasz Sapeta ); 125*fe5cfb17STomasz Sapeta }) 126*fe5cfb17STomasz Sapeta .sleep(1000) 127*fe5cfb17STomasz Sapeta // http://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MENU 128*fe5cfb17STomasz Sapeta .pressDeviceKey(46) 129*fe5cfb17STomasz Sapeta .pressDeviceKey(46) 130*fe5cfb17STomasz Sapeta .sleep(2000) 131*fe5cfb17STomasz Sapeta .waitForElementByXPath( 132*fe5cfb17STomasz Sapeta '//android.widget.TextView[starts-with(@text, "Step 1")]', 133*fe5cfb17STomasz Sapeta ) 134*fe5cfb17STomasz Sapeta .finally(() => { 135*fe5cfb17STomasz Sapeta clearInterval(intervalToUpdate); 136*fe5cfb17STomasz Sapeta fs.writeFileSync('App.js', androidAppCode, 'utf-8'); 137*fe5cfb17STomasz Sapeta driver.pressDeviceKey(46).pressDeviceKey(46).sleep(2000); 138*fe5cfb17STomasz Sapeta }) 139*fe5cfb17STomasz Sapeta ); 140*fe5cfb17STomasz Sapeta }); 141*fe5cfb17STomasz Sapeta 142*fe5cfb17STomasz Sapeta it('should have the menu available', function () { 143*fe5cfb17STomasz Sapeta return ( 144*fe5cfb17STomasz Sapeta driver 145*fe5cfb17STomasz Sapeta .waitForElementByXPath( 146*fe5cfb17STomasz Sapeta '//android.widget.TextView[starts-with(@text, "Welcome to React")]', 147*fe5cfb17STomasz Sapeta ) 148*fe5cfb17STomasz Sapeta // http://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MENU 149*fe5cfb17STomasz Sapeta .pressDeviceKey(82) 150*fe5cfb17STomasz Sapeta .waitForElementByXPath( 151*fe5cfb17STomasz Sapeta '//android.widget.TextView[starts-with(@text, "Toggle Inspector")]', 152*fe5cfb17STomasz Sapeta ) 153*fe5cfb17STomasz Sapeta ); 154*fe5cfb17STomasz Sapeta }); 155*fe5cfb17STomasz Sapeta}); 156