From cefb600d214dacd3895c395bfd2f5e5f346961e7 Mon Sep 17 00:00:00 2001 From: Priyansh Garg Date: Thu, 13 Oct 2022 04:10:21 +0530 Subject: [PATCH] Add support for detecting browsers and installing latest Firefox browser. --- package-lock.json | 139 +++++++++++++++++++++ package.json | 1 + src/commands/android/constants.ts | 2 + src/commands/android/index.ts | 180 ++++++++++++++++++++++++++- src/commands/android/utils/common.ts | 80 ++++++++++-- 5 files changed, 392 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 568b2b3..4e25b73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "ansi-colors": "^4.1.3", + "axios": "^1.1.2", "cli-progress": "^3.11.2", "dotenv": "^16.0.3", "download": "^8.0.0", @@ -544,6 +545,21 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.2.tgz", + "integrity": "sha512-bznQyETwElsXl2RK7HLLwb5GPpOLlycxHCtrpDR/4RqqBzjARaOTo3jz4IgtntWUYee7Ne4S8UHd92VCuzPaWA==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -783,6 +799,17 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -1026,6 +1053,14 @@ "clone": "^1.0.2" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1482,6 +1517,38 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -2104,6 +2171,17 @@ "node": ">= 0.6" } }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -2434,6 +2512,11 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -3464,6 +3547,21 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.2.tgz", + "integrity": "sha512-bznQyETwElsXl2RK7HLLwb5GPpOLlycxHCtrpDR/4RqqBzjARaOTo3jz4IgtntWUYee7Ne4S8UHd92VCuzPaWA==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3635,6 +3733,14 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -3828,6 +3934,11 @@ "clone": "^1.0.2" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4179,6 +4290,21 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -4651,6 +4777,14 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -4885,6 +5019,11 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", diff --git a/package.json b/package.json index 7151712..d00a13a 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ }, "dependencies": { "ansi-colors": "^4.1.3", + "axios": "^1.1.2", "cli-progress": "^3.11.2", "dotenv": "^16.0.3", "download": "^8.0.0", diff --git a/src/commands/android/constants.ts b/src/commands/android/constants.ts index 4568691..6a8bc6b 100644 --- a/src/commands/android/constants.ts +++ b/src/commands/android/constants.ts @@ -5,6 +5,8 @@ import {SdkBinary} from './interfaces'; import {getAbiForOS} from './utils/common'; export const NIGHTWATCH_AVD = 'nightwatch-android-11'; +export const DEFAULT_FIREFOX_VERSION = '105.1.0'; +export const DEFAULT_CHROME_VERSION = '105.0.5195.136'; export const SETUP_CONFIG_QUES: inquirer.QuestionCollection = [ { diff --git a/src/commands/android/index.ts b/src/commands/android/index.ts index c849c20..a37011e 100644 --- a/src/commands/android/index.ts +++ b/src/commands/android/index.ts @@ -1,15 +1,19 @@ import colors from 'ansi-colors'; import * as dotenv from 'dotenv'; import fs from 'fs'; +import os from 'os'; import path from 'path'; import untildify from 'untildify'; import which from 'which'; import {prompt} from 'inquirer'; import {getPlatformName, symbols} from '../../utils'; -import {BINARY_TO_PACKAGE_NAME, NIGHTWATCH_AVD, SDK_BINARY_LOCATIONS, SETUP_CONFIG_QUES} from './constants'; +import { + BINARY_TO_PACKAGE_NAME, DEFAULT_CHROME_VERSION, DEFAULT_FIREFOX_VERSION, + NIGHTWATCH_AVD, SDK_BINARY_LOCATIONS, SETUP_CONFIG_QUES +} from './constants'; import {Options, OtherInfo, Platform, SdkBinary, SetupConfigs} from './interfaces'; -import {getAbiForOS, getBinaryNameForOS} from './utils/common'; +import {downloadFirefoxAndroid, getAbiForOS, getBinaryNameForOS, getFirefoxApkName, getLatestVersion, launchAVD} from './utils/common'; import {downloadAndSetupAndroidSdk, execBinarySync, getDefaultAndroidSdkRoot, installPackagesUsingSdkManager} from './utils/sdk'; @@ -53,6 +57,14 @@ export class AndroidSetup { result = false; } + if (setupConfigs.mode !== 'real') { + await this.verifyAndSetupBrowsers(setupConfigs.browsers); + } + + if (setupConfigs.mode !== 'emulator') { + console.log(`\n${colors.bold('Note:')} Please make sure you have required browsers installed on your real-device before running tests.`); + } + if (!sdkRootEnv) { this.sdkRootEnvSetInstructions(); } @@ -241,7 +253,7 @@ export class AndroidSetup { const nonWorkingBinaries: SdkBinary[] = []; for (const binaryName of binaries) { - const binaryPath = this.getBinaryLocation(binaryName); + const binaryPath = this.getBinaryLocation(binaryName, true); let cmd = '--version'; if (binaryName === 'emulator') { @@ -502,4 +514,166 @@ export class AndroidSetup { console.log('Doing this now might save you from future troubles.\n'); } + + async verifyAndSetupBrowsers(browsers: SetupConfigs['browsers']) { + if (!browsers || browsers === 'none') { + return; + } + + const verifyFirefox = ['firefox', 'both'].includes(browsers); + const verifyChrome = ['chrome', 'both'].includes(browsers); + + let firefoxLatestVersion = ''; + let chromeLatestVersion = ''; + + let installFirefox = false; + let installChrome = false; + + console.log(`\n${colors.cyan('Last bit:')} Verifying if browser(s) are installed...\n`); + + // console.log('Killing emulator...'); + // execBinarySync(this.getBinaryLocation('adb', true), 'adb', this.platform, 'emu kill'); + // need to wait after killing the emulators. + // or, fetch the emulators running and check if anyone of it is NIGHTWATCH_AVD, and if so, don't close. + + launchAVD(this.getBinaryLocation('emulator', true), this.platform); + + console.log('Waiting for emulator to boot up...'); + execBinarySync( + this.getBinaryLocation('adb', true), + 'adb', + this.platform, + 'wait-for-local-device' + ); + console.log('Boot up complete!\n'); + + console.log('Making sure adb has root permissions...'); + const adbRootStdout = execBinarySync( + this.getBinaryLocation('adb', true), + 'adb', + this.platform, + 'wait-for-local-device' + ); + if (adbRootStdout !== null) { + console.log(` ${colors.green(symbols().ok)} adb is running with root permissions!\n`); + } else { + console.log('Please try running the above command by yourself.\n'); + } + + if (verifyFirefox) { + firefoxLatestVersion = await getLatestVersion('firefox'); + + console.log('Verifying if Firefox is installed...'); + const stdout = execBinarySync( + this.getBinaryLocation('adb', true), + 'adb', + this.platform, + 'shell pm list packages org.mozilla.firefox' + ); + if (stdout) { + console.log(` ${colors.green(symbols().ok)} Firefox browser is installed in the AVD.\n`); + + console.log('Checking the version of installed Firefox browser...'); + const versionStdout = execBinarySync( + this.getBinaryLocation('adb', true), + 'adb', + this.platform, + 'shell dumpsys package org.mozilla.firefox' + ); + + if (versionStdout !== null) { + const versionMatch = versionStdout.match(/versionName=((\d+\.)+\d+)/); + if (!versionMatch) { + console.log(` ${colors.red(symbols().fail)} Failed to find the version of the Firefox browser installed.\n`); + } else if (versionMatch[1] !== firefoxLatestVersion && firefoxLatestVersion !== DEFAULT_FIREFOX_VERSION) { + console.log(`A new version of Firefox browser is available (${colors.cyan(versionMatch[1] + ' -> ' + firefoxLatestVersion)})\n`); + installFirefox = true; + } else { + console.log(` ${colors.green(symbols().ok)} Your Firefox browser is up-to-date.\n`); + } + } else { + console.log('Could not get the version of the installed Firefox browser.\n'); + } + } else { + console.log(` ${colors.red(symbols().fail)} Firefox browser not found in the AVD.\n`); + installFirefox = true; + } + } + + if (verifyChrome) { + chromeLatestVersion = DEFAULT_CHROME_VERSION; + + console.log('Verifying if Chrome is installed...'); + const stdout = execBinarySync( + this.getBinaryLocation('adb', true), + 'adb', + this.platform, + 'shell pm list packages com.android.chrome' + ); + if (stdout) { + console.log(` ${colors.green(symbols().ok)} Chrome browser is installed in the AVD.\n`); + + console.log('Checking the version of installed Chrome browser...'); + const versionStdout = execBinarySync( + this.getBinaryLocation('adb', true), + 'adb', + this.platform, + 'shell dumpsys package com.android.chrome' + ); + + if (versionStdout !== null) { + const versionMatch = versionStdout.match(/versionName=((\d+\.)+\d+)/); + if (!versionMatch) { + console.log(` ${colors.red(symbols().fail)} Failed to find the version of the Chrome browser installed.\n`); + } else if (versionMatch[1] !== chromeLatestVersion && chromeLatestVersion !== DEFAULT_FIREFOX_VERSION) { + console.log(`A new version of Chrome browser is available (${colors.cyan(versionMatch[1] + ' -> ' + chromeLatestVersion)})\n`); + installChrome = true; + } else { + console.log(` ${colors.green(symbols().ok)} Your Chrome browser is up-to-date.\n`); + } + } else { + console.log('Could not get the version of the installed Chrome browser.\n'); + } + } else { + console.log(` ${colors.red(symbols().fail)} Chrome browser not found in the AVD.\n`); + installChrome = true; + } + } + + if (this.options.setup) { + if (installFirefox) { + console.log('Downloading latest Firefox APK...'); + + const firefoxDownloaded = await downloadFirefoxAndroid(firefoxLatestVersion); + if (firefoxDownloaded) { + console.log('\n Installing the downloaded APK in the running AVD...'); + + const stdout = execBinarySync( + this.getBinaryLocation('adb', true), + 'adb', + this.platform, + `install -r ${path.join(os.tmpdir(), getFirefoxApkName(firefoxLatestVersion))}` + ); + + if (stdout !== null) { + console.log(`${colors.green(symbols().ok)} Firefox browser installed successfully!\n`); + } else { + console.log('Please try running the above command by yourself (make sure that the emulator is running).\n'); + } + } else { + console.log(`\n${colors.red('Failed!')} Please download the latest version of Firefox from the below link.`); + console.log('(Drag-and-drop the downloaded APK over the emulator screen to install.)'); + console.log(colors.cyan(' https://archive.mozilla.org/pub/fenix/releases'), '\n'); + } + } + + if (installChrome) { + // install chrome browser + } + } + + console.log('Killing emulator...'); + execBinarySync(this.getBinaryLocation('adb', true), 'adb', this.platform, 'emu kill'); + console.log('Emulator will close shortly. If not, please close it manually.'); + } } diff --git a/src/commands/android/utils/common.ts b/src/commands/android/utils/common.ts index 5cce0fe..65a1d85 100644 --- a/src/commands/android/utils/common.ts +++ b/src/commands/android/utils/common.ts @@ -1,7 +1,12 @@ +import axios, {AxiosResponse} from 'axios'; +import {exec} from 'child_process'; import cliProgress from 'cli-progress'; import download from 'download'; +import fs from 'fs'; +import os from 'os'; import path from 'path'; +import {DEFAULT_CHROME_VERSION, DEFAULT_FIREFOX_VERSION, NIGHTWATCH_AVD} from '../constants'; import {Platform} from '../interfaces'; export const getBinaryNameForOS = (platform: Platform, binaryName: string) => { @@ -39,13 +44,74 @@ export const downloadWithProgressBar = async (url: string, dest: string, extract format: ' [{bar}] {percentage}% | ETA: {eta}s' }, cliProgress.Presets.shades_classic); - const stream = download(url, dest, { - extract - }); - progressBar.start(100, 0); + try { + const stream = download(url, dest, { + extract + }); + progressBar.start(100, 0); + + await stream.on('downloadProgress', function(progress) { + progressBar.update(progress.percent*100); + }); + progressBar.stop(); + + return true; + } catch { + progressBar.stop(); + + return false; + } +}; + +export const getLatestVersion = async (browser: 'firefox' | 'chrome'): Promise => { + if (browser === 'firefox') { + try { + const {data}: AxiosResponse<{tag_name: string}> = await axios('https://api.github.com/repos/mozilla-mobile/fenix/releases/latest'); + + return data['tag_name'].slice(1); + } catch { + return DEFAULT_FIREFOX_VERSION; + } + } else { + return DEFAULT_CHROME_VERSION; + } +}; + +export const getFirefoxApkName = (version: string) => { + return `fenix-${version}.multi.android-${getAbiForOS()}.apk`; +}; + +export const downloadFirefoxAndroid = async (version: string) => { + if (!version) { + version = await getLatestVersion('firefox'); + } + + const tempdir = os.tmpdir(); + + const apkName = getFirefoxApkName(version); + if (fs.existsSync(path.join(tempdir, apkName))) { + return true; + } + + const apkDownloadUrl = `https://archive.mozilla.org/pub/fenix/releases/${version}/android/fenix-${version}-android-${getAbiForOS()}/${apkName}`; + + return await downloadWithProgressBar(apkDownloadUrl, tempdir); +}; + +export const launchAVD = (emuLocation: string, platform: Platform) => { + const emuFullName = path.basename(emuLocation); + const emuDirPath = path.dirname(emuLocation); + + console.log(`Launching emulator with ${NIGHTWATCH_AVD} AVD...\n`); + let cmd: string; + + if (platform === 'windows') { + cmd = `${emuFullName} @${NIGHTWATCH_AVD} -delay-adb`; + } else { + cmd = `./${emuFullName} @${NIGHTWATCH_AVD} -delay-adb`; + } - await stream.on('downloadProgress', function(progress) { - progressBar.update(progress.percent*100); + exec(cmd, { + cwd: emuDirPath }); - progressBar.stop(); };