diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 3348f07..ac65b2f 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -11,14 +11,6 @@ parameters: - name: testJobs type: object default: - - iosVersion: 12 - xcodeVersion: 10 - iosDeviceName: iPhone 6 - vmImage: macOS-10.14 - - iosVersion: 12.4 - xcodeVersion: 10.3 - iosDeviceName: iPhone X - vmImage: macOS-10.14 - iosVersion: 13.2 xcodeVersion: 11.2 iosDeviceName: iPhone 11 @@ -31,7 +23,10 @@ parameters: xcodeVersion: 12 iosDeviceName: iPhone 11 vmImage: macOS-10.15 - + - iosVersion: 14.4 + xcodeVersion: 12.4 + iosDeviceName: iPhone 12 + vmImage: macOS-10.15 stages: - stage: Unit_Test diff --git a/lib/simulator-xcode-9.js b/lib/simulator-xcode-9.js index b748882..b20688d 100644 --- a/lib/simulator-xcode-9.js +++ b/lib/simulator-xcode-9.js @@ -4,10 +4,11 @@ import path from 'path'; import { fs, timing } from 'appium-support'; import AsyncLock from 'async-lock'; import log from './logger'; -import { waitForCondition, retryInterval } from 'asyncbox'; +import { waitForCondition } from 'asyncbox'; import { toBiometricDomainComponent, getDeveloperRoot } from './utils.js'; import { NSUserDefaults, generateDefaultsCommandArgs } from './defaults-utils'; import B from 'bluebird'; +import { EventEmitter } from 'events'; const SIMULATOR_SHUTDOWN_TIMEOUT = 15 * 1000; const startupLock = new AsyncLock(); @@ -177,30 +178,38 @@ class SimulatorXcode9 extends SimulatorXcode8 { } /** - * Boots simulator if not already booted. + * Boots Simulator if not already booted. * Does nothing if it is already running. + * This API does NOT wait until Simulator is fully booted. * - * @throws {Error} If Simulator is still not running after being booted + * @throws {Error} If there was a failure while booting the Simulator. */ async boot () { - if (await this.isRunning()) { - log.info(`Simulator '${this.udid}' is already running`); - return; - } - - log.info(`Booting Simulator '${this.udid}'`); + const bootEventsEmitter = new EventEmitter(); + await this.simctl.startBootMonitor({ + onError: (err) => bootEventsEmitter.emit('failure', err), + onFinished: () => bootEventsEmitter.emit('finish'), + shouldPreboot: true, + }); try { - await this.simctl.bootDevice(); - } catch (e) { - log.warn(e.stderr || e.message); + await new B((resolve, reject) => { + // Historically this call was always asynchronous, + // e.g. it was not waiting until Simulator is fully booted. + // So we preserve that behavior, and if no errors are received for a while + // then we assume the Simulator booting is still in progress. + setTimeout(resolve, 3000); + bootEventsEmitter.once('failure', (err) => { + if (_.includes(err?.message, 'state: Booted')) { + resolve(); + } else { + reject(err); + } + }); + bootEventsEmitter.once('finish', resolve); + }); + } finally { + bootEventsEmitter.removeAllListeners(); } - - await retryInterval(5, 1000, async () => { - if (!await this.isRunning()) { - throw new Error(`Simulator '${this.udid}' is not running after being booted. ` + - `Check the Appium log for more details.`); - } - }); } /** diff --git a/package.json b/package.json index 484f806..7255f35 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "asyncbox": "^2.3.1", "bluebird": "^3.5.1", "lodash": "^4.2.1", - "node-simctl": "^6.4.0", + "node-simctl": "^6.6.0", "semver": "^7.0.0", "source-map-support": "^0.5.3", "teen_process": "^1.3.0",