From 7c0ce96892ca16a4abbb9731b08e170c0c4d5909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 9 Apr 2019 14:26:36 -0700 Subject: [PATCH 1/3] Install local react-native package in e2e --- scripts/run-ci-e2e-tests.js | 63 +++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index 88b38ba85b96..d8dae7f28430 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -43,12 +43,16 @@ let exitCode; // Make sure we installed local version of react-native function checkMarker() { if (!test('-e', path.basename(MARKER))) { - echo('Marker was not found, react native init command failed?'); + echo('Marker was not found, template copy failed?'); exitCode = 1; throw Error(exitCode); } } +function describe(message) { + echo(`\n\n>>>>> ${message}\n\n\n`); +} + try { // install CLI const CLI_PACKAGE = 'react-native-cli'; @@ -81,26 +85,59 @@ try { const PACKAGE = path.join(ROOT, 'react-native-*.tgz'); cd(TEMP); + + echo('Creating a basic React Native app from template'); + const E2E_APP_ROOT = path.join(TEMP, 'template'); + cp('-R', path.join(ROOT, 'template'), E2E_APP_ROOT); + + cd(E2E_APP_ROOT); + ls(E2E_APP_ROOT) + .filter(function(file) { + return file !== '__tests__' && file.match(/^_.*$/); + }) + .forEach(function(src) { + const dst = path.join(E2E_APP_ROOT, src.replace(/^_/, '.')); + mv(src, dst); + }); + + sed('-i', 'HelloWorld', 'test-template', 'package.json'); + + echo('Installing React Native packages'); + exec(`npm install ${PACKAGE}`); if ( tryExecNTimes( () => { exec('sleep 10s'); - return exec(`react-native init EndToEndTest --version ${PACKAGE}`).code; + return exec('npm install --save-dev flow-bin').code; }, numberOfRetries, - () => rm('-rf', 'EndToEndTest'), + () => rm('-rf', E2E_APP_ROOT), ) ) { - echo('Failed to execute react-native init'); + echo('Failed to install Flow'); echo('Most common reason is npm registry connectivity, try again'); exitCode = 1; throw Error(exitCode); } - cd('EndToEndTest'); + if ( + tryExecNTimes( + () => { + exec('sleep 10s'); + return exec('npm install').code; + }, + numberOfRetries, + () => rm('-rf', E2E_APP_ROOT), + ) + ) { + echo('Failed to execute npm install'); + echo('Most common reason is npm registry connectivity, try again'); + exitCode = 1; + throw Error(exitCode); + } if (argv.android) { - echo('Running an Android end-to-end test'); + describe('Executing Android end-to-end tests'); checkMarker(); echo('Installing end-to-end framework'); if ( @@ -154,7 +191,7 @@ try { SERVER_PID = packagerProcess.pid; // wait a bit to allow packager to startup exec('sleep 15s'); - echo('Executing android end-to-end test'); + describe('Test: Android end-to-end test'); if ( tryExecNTimes(() => { exec('sleep 10s'); @@ -171,7 +208,7 @@ try { if (argv.ios || argv.tvos) { checkMarker(); var iosTestType = argv.tvos ? 'tvOS' : 'iOS'; - echo('Running the ' + iosTestType + ' app'); + describe('Executing ' + iosTestType + ' end-to-end tests'); cd('ios'); // shelljs exec('', {async: true}) does not emit stdout events, so we rely on good old spawn const packagerEnv = Object.create(process.env); @@ -189,7 +226,7 @@ try { echo(`Starting packager server, ${SERVER_PID}`); echo('Running pod install'); exec('pod install'); - echo('Executing ' + iosTestType + ' end-to-end test'); + describe('Test: ' + iosTestType + ' end-to-end test'); if ( tryExecNTimes(() => { exec('sleep 10s'); @@ -240,6 +277,7 @@ try { if (argv.js) { checkMarker(); // Check the packager produces a bundle (doesn't throw an error) + describe('Test: Verify packager can generate an Android bundle'); if ( exec( 'react-native bundle --max-workers 1 --platform android --dev true --entry-file index.js --bundle-output android-bundle.js', @@ -249,6 +287,7 @@ try { exitCode = 1; throw Error(exitCode); } + describe('Test: Verify packager can generate an iOS bundle'); if ( exec( 'react-native --max-workers 1 bundle --platform ios --dev true --entry-file index.js --bundle-output ios-bundle.js', @@ -258,6 +297,12 @@ try { exitCode = 1; throw Error(exitCode); } + describe('Test: Flow check'); + if (exec('./node_modules/.bin/flow check').code) { + echo('Flow check failed.'); + exitCode = 1; + throw Error(exitCode); + } } exitCode = 0; } finally { From 0ffb3644e8aeff2ba310be6e3499d13f135a2aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 9 Apr 2019 16:59:58 -0700 Subject: [PATCH 2/3] Use CLI to create e2e app, before manually installing RN package --- scripts/run-ci-e2e-tests.js | 59 +++++++++++++------------------------ 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index d8dae7f28430..487b9bb48dda 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -31,24 +31,11 @@ const ROOT = path.normalize(path.join(__dirname, '..')); const tryExecNTimes = require('./try-n-times'); const TEMP = exec('mktemp -d /tmp/react-native-XXXXXXXX').stdout.trim(); -// To make sure we actually installed the local version -// of react-native, we will create a temp file inside the template -// and check that it exists after `react-native init -const MARKER = exec(`mktemp ${ROOT}/template/XXXXXXXX`).stdout.trim(); const numberOfRetries = argv.retries || 1; let SERVER_PID; let APPIUM_PID; let exitCode; -// Make sure we installed local version of react-native -function checkMarker() { - if (!test('-e', path.basename(MARKER))) { - echo('Marker was not found, template copy failed?'); - exitCode = 1; - throw Error(exitCode); - } -} - function describe(message) { echo(`\n\n>>>>> ${message}\n\n\n`); } @@ -86,23 +73,24 @@ try { const PACKAGE = path.join(ROOT, 'react-native-*.tgz'); cd(TEMP); - echo('Creating a basic React Native app from template'); - const E2E_APP_ROOT = path.join(TEMP, 'template'); - cp('-R', path.join(ROOT, 'template'), E2E_APP_ROOT); - - cd(E2E_APP_ROOT); - ls(E2E_APP_ROOT) - .filter(function(file) { - return file !== '__tests__' && file.match(/^_.*$/); - }) - .forEach(function(src) { - const dst = path.join(E2E_APP_ROOT, src.replace(/^_/, '.')); - mv(src, dst); - }); - - sed('-i', 'HelloWorld', 'test-template', 'package.json'); - - echo('Installing React Native packages'); + echo('Creating EndToEndTest React Native app'); + if ( + tryExecNTimes( + () => { + exec('sleep 10s'); + return exec('react-native init EndToEndTest').code; + }, + numberOfRetries, + () => rm('-rf', E2E_APP_ROOT), + ) + ) { + echo('Failed to execute react-native init'); + echo('Most common reason is npm registry connectivity, try again'); + exitCode = 1; + throw Error(exitCode); + } + cd('EndToEndTest'); + echo('Installing React Native package'); exec(`npm install ${PACKAGE}`); if ( tryExecNTimes( @@ -119,7 +107,7 @@ try { exitCode = 1; throw Error(exitCode); } - + echo('Installing node_modules'); if ( tryExecNTimes( () => { @@ -138,7 +126,6 @@ try { if (argv.android) { describe('Executing Android end-to-end tests'); - checkMarker(); echo('Installing end-to-end framework'); if ( tryExecNTimes( @@ -206,7 +193,6 @@ try { } if (argv.ios || argv.tvos) { - checkMarker(); var iosTestType = argv.tvos ? 'tvOS' : 'iOS'; describe('Executing ' + iosTestType + ' end-to-end tests'); cd('ios'); @@ -230,7 +216,7 @@ try { if ( tryExecNTimes(() => { exec('sleep 10s'); - let destination = 'platform=iOS Simulator,name=iPhone 5s,OS=12.1'; + let destination = 'platform=iOS Simulator,name=iPhone 6s,OS=12.1'; let sdk = 'iphonesimulator'; let scheme = 'EndToEndTest'; @@ -275,7 +261,7 @@ try { } if (argv.js) { - checkMarker(); + describe('Executing JavaScript end-to-end tests'); // Check the packager produces a bundle (doesn't throw an error) describe('Test: Verify packager can generate an Android bundle'); if ( @@ -306,9 +292,6 @@ try { } exitCode = 0; } finally { - cd(ROOT); - rm(MARKER); - if (SERVER_PID) { echo(`Killing packager ${SERVER_PID}`); exec(`kill -9 ${SERVER_PID}`); From d7e79845c69844349c4a27fac52ed636237f999b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 9 Apr 2019 17:48:38 -0700 Subject: [PATCH 3/3] Switch back to using CLI for test app scaffolding. Use npm tag to ensure local package isinstalled. --- scripts/run-ci-e2e-tests.js | 95 ++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index 487b9bb48dda..8baca7f30d3c 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -77,11 +77,14 @@ try { if ( tryExecNTimes( () => { - exec('sleep 10s'); - return exec('react-native init EndToEndTest').code; + return exec(`react-native init EndToEndTest --version ${PACKAGE} --npm`) + .code; }, numberOfRetries, - () => rm('-rf', E2E_APP_ROOT), + () => { + rm('-rf', 'EndToEndTest'); + exec('sleep 10s'); + }, ) ) { echo('Failed to execute react-native init'); @@ -95,11 +98,10 @@ try { if ( tryExecNTimes( () => { - exec('sleep 10s'); return exec('npm install --save-dev flow-bin').code; }, numberOfRetries, - () => rm('-rf', E2E_APP_ROOT), + () => exec('sleep 10s'), ) ) { echo('Failed to install Flow'); @@ -111,11 +113,10 @@ try { if ( tryExecNTimes( () => { - exec('sleep 10s'); return exec('npm install').code; }, numberOfRetries, - () => rm('-rf', E2E_APP_ROOT), + () => exec('sleep 10s'), ) ) { echo('Failed to execute npm install'); @@ -180,10 +181,13 @@ try { exec('sleep 15s'); describe('Test: Android end-to-end test'); if ( - tryExecNTimes(() => { - exec('sleep 10s'); - return exec('node node_modules/.bin/_mocha android-e2e-test.js').code; - }, numberOfRetries) + tryExecNTimes( + () => { + return exec('node node_modules/.bin/_mocha android-e2e-test.js').code; + }, + numberOfRetries, + () => exec('sleep 10s'), + ) ) { echo('Failed to run Android end-to-end tests'); echo('Most likely the code is broken'); @@ -214,43 +218,46 @@ try { exec('pod install'); describe('Test: ' + iosTestType + ' end-to-end test'); if ( - tryExecNTimes(() => { - exec('sleep 10s'); - let destination = 'platform=iOS Simulator,name=iPhone 6s,OS=12.1'; - let sdk = 'iphonesimulator'; - let scheme = 'EndToEndTest'; + tryExecNTimes( + () => { + let destination = 'platform=iOS Simulator,name=iPhone 6s,OS=12.1'; + let sdk = 'iphonesimulator'; + let scheme = 'EndToEndTest'; - if (argv.tvos) { - destination = 'platform=tvOS Simulator,name=Apple TV,OS=11.4'; - sdk = 'appletvsimulator'; - scheme = 'EndToEndTest-tvOS'; - } + if (argv.tvos) { + destination = 'platform=tvOS Simulator,name=Apple TV,OS=11.4'; + sdk = 'appletvsimulator'; + scheme = 'EndToEndTest-tvOS'; + } - return exec( - [ - 'xcodebuild', - '-workspace', - '"EndToEndTest.xcworkspace"', - '-destination', - `"${destination}"`, - '-scheme', - `"${scheme}"`, - '-sdk', - sdk, - '-UseModernBuildSystem=NO', - 'test', - ].join(' ') + - ' | ' + + return exec( [ - 'xcpretty', - '--report', - 'junit', - '--output', - `"~/react-native/reports/junit/${iosTestType}-e2e/results.xml"`, + 'xcodebuild', + '-workspace', + '"EndToEndTest.xcworkspace"', + '-destination', + `"${destination}"`, + '-scheme', + `"${scheme}"`, + '-sdk', + sdk, + '-UseModernBuildSystem=NO', + 'test', ].join(' ') + - ' && exit ${PIPESTATUS[0]}', - ).code; - }, numberOfRetries) + ' | ' + + [ + 'xcpretty', + '--report', + 'junit', + '--output', + `"~/react-native/reports/junit/${iosTestType}-e2e/results.xml"`, + ].join(' ') + + ' && exit ${PIPESTATUS[0]}', + ).code; + }, + numberOfRetries, + () => exec('sleep 10s'), + ) ) { echo('Failed to run ' + iosTestType + ' end-to-end tests'); echo('Most likely the code is broken');