From c1064b3eb057eea3889ff7758eafd48b3ebcf2cf Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sat, 23 Sep 2023 12:38:31 +0200 Subject: [PATCH] Fix tests --- lib/device-utils.js | 9 +++++++ lib/utils.js | 38 ++++++++++++++++++---------- test/unit/simulator-specs.js | 21 ++++++---------- test/unit/utils-specs.js | 48 +++++++++++++++++++++++++++++++++++- 4 files changed, 89 insertions(+), 27 deletions(-) create mode 100644 lib/device-utils.js diff --git a/lib/device-utils.js b/lib/device-utils.js new file mode 100644 index 0000000..8dbbf8a --- /dev/null +++ b/lib/device-utils.js @@ -0,0 +1,9 @@ +import Simctl from 'node-simctl'; + +/** + * @param {Record} [simctlOpts] + * @returns {Promise} + */ +export async function getDevices(simctlOpts) { + return await new Simctl(simctlOpts).getDevices(); +} diff --git a/lib/utils.js b/lib/utils.js index fd13ef3..dedc1de 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -3,9 +3,8 @@ import _ from 'lodash'; import { exec } from 'teen_process'; import { waitForCondition } from 'asyncbox'; import { getVersion } from 'appium-xcode'; -import Simctl from 'node-simctl'; import path from 'path'; - +import { getDevices } from './device-utils'; const DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS = 30000; const SAFARI_STARTUP_TIMEOUT_MS = 25 * 1000; @@ -34,6 +33,10 @@ const BIOMETRICS = { faceId: 'pearl', }; +/** + * @param {string} name + * @returns {string} + */ function toBiometricDomainComponent (name) { if (!BIOMETRICS[name]) { throw new Error(`'${name}' is not a valid biometric. Use one of: ${JSON.stringify(_.keys(BIOMETRICS))}`); @@ -42,18 +45,10 @@ function toBiometricDomainComponent (name) { } /** - * @param {Record|undefined} [simctlOpts] - * @returns {Promise} + * @param {string} appName + * @param {boolean} [forceKill=false] + * @returns {Promise} */ -export async function getDevices(simctlOpts) { - return await new Simctl(simctlOpts).getDevices(); -} - -// pgrep/pkill exit codes: -// 0 One or more processes were matched. -// 1 No processes were matched. -// 2 Invalid options were specified on the command line. -// 3 An internal error occurred. async function pkill (appName, forceKill = false) { let args = forceKill ? ['-9'] : []; args.push('-x', appName); @@ -61,6 +56,11 @@ async function pkill (appName, forceKill = false) { await exec('pkill', args); return 0; } catch (err) { + // pgrep/pkill exit codes: + // 0 One or more processes were matched. + // 1 No processes were matched. + // 2 Invalid options were specified on the command line. + // 3 An internal error occurred. if (!_.isUndefined(err.code)) { throw new Error(`Cannot forcefully terminate ${appName}. pkill error code: ${err.code}`); } @@ -69,6 +69,10 @@ async function pkill (appName, forceKill = false) { } } +/** + * @param {number} [timeout=DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS] + * @returns {Promise} + */ async function killAllSimulators (timeout = DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS) { log.debug('Killing all iOS Simulators'); const xcodeVersion = await getVersion(true); @@ -143,6 +147,11 @@ async function killAllSimulators (timeout = DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS) { } } +/** + * @param {string} udid + * @param {Record} [opts={}] + * @returns {Promise} + */ async function getSimulatorInfo (udid, opts = {}) { const { devicesSetPath @@ -162,6 +171,9 @@ async function simExists (udid) { return !!(await getSimulatorInfo(udid)); } +/** + * @returns {Promise} + */ async function getDeveloperRoot () { const {stdout} = await exec('xcode-select', ['-p']); return stdout.trim(); diff --git a/test/unit/simulator-specs.js b/test/unit/simulator-specs.js index 9f899bb..7835d4e 100644 --- a/test/unit/simulator-specs.js +++ b/test/unit/simulator-specs.js @@ -1,7 +1,8 @@ +// transpile:mocha + import { getSimulator } from '../../lib/simulator'; -import _ from 'lodash'; -import * as utilMethods from '../../lib/utils'; import * as teenProcess from 'teen_process'; +import * as deviceUtils from '../../lib/device-utils'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; import sinon from 'sinon'; @@ -23,22 +24,16 @@ const UDID = devices['8.1'][0].udid; describe('simulator', function () { let xcodeMock; - let getSimInfoStub; + let getDevicesStub; beforeEach(function () { xcodeMock = sinon.mock(xcode); - getSimInfoStub = sinon.stub(utilMethods, 'getSimulatorInfo').callsFake( - async (udid) => { - const result = _.toPairs(devices) - .map((pair) => pair[1]) - .reduce((a, b) => a.concat(b), []); - return await B.resolve(_.find(result, (dev) => dev.udid === udid)); - } - ); + getDevicesStub = sinon.stub(deviceUtils, 'getDevices'); + getDevicesStub.returns(B.resolve(devices)); }); afterEach(function () { xcodeMock.restore(); - getSimInfoStub.restore(); + getDevicesStub.restore(); }); describe('getSimulator', function () { @@ -91,8 +86,8 @@ describe('simulator', function () { sinon.stub(sim.simctl, 'getDevices').returns(B.resolve(devices)); return sim; }); - const stats = await B.all(sims.map((sim) => sim.stat())); + const stats = await B.all(sims.map((sim) => sim.stat())); stats[0].state.should.equal('Shutdown'); stats[0].name.should.equal('Resizable iPhone'); stats[1].state.should.equal('Shutdown'); diff --git a/test/unit/utils-specs.js b/test/unit/utils-specs.js index a8b23bb..25a9aa2 100644 --- a/test/unit/utils-specs.js +++ b/test/unit/utils-specs.js @@ -7,8 +7,10 @@ import B from 'bluebird'; import * as TeenProcess from 'teen_process'; import xcode from 'appium-xcode'; import { - toBiometricDomainComponent, killAllSimulators, + toBiometricDomainComponent, killAllSimulators, simExists, } from '../../lib/utils'; +import * as deviceUtils from '../../lib/device-utils'; +import { devices } from '../assets/deviceList'; import SimulatorXcode9 from '../../lib/simulator-xcode-9'; chai.should(); @@ -40,14 +42,18 @@ const XCODE_VERSION_6 = { describe('util', function () { let execStub; let xcodeMock; + let getDevicesStub; beforeEach(function () { execStub = sinon.stub(TeenProcess, 'exec'); xcodeMock = sinon.mock(xcode); + getDevicesStub = sinon.stub(deviceUtils, 'getDevices'); + getDevicesStub.returns(B.resolve(devices)); }); afterEach(function () { execStub.restore(); xcodeMock.restore(); + getDevicesStub.restore(); }); describe('killAllSimulators', function () { @@ -67,7 +73,47 @@ describe('util', function () { await killAllSimulators(); execStub.callCount.should.equal(2); }); + it('should call exec if pgrep does find running Simulator with Xcode6 and shutdown fails', async function () { + xcodeMock.expects('getVersion').once().withArgs(true).returns(B.resolve(XCODE_VERSION_6)); + execStub.withArgs('pgrep').returns('0'); + execStub.withArgs('xcrun').throws(); + execStub.withArgs('pkill').returns(); + + try { + await killAllSimulators(500); + } catch (e) {} + execStub.callCount.should.equal(3); + }); }); + + describe('simExists', function () { + it('returns true if device is found', async function () { + let results = await B.all([ + simExists('8F4A3349-3ABF-4597-953A-285C5C0FFD00'), + simExists('7DEA409E-159A-4730-B1C6-7C18279F72B8'), + simExists('F33783B2-9EE9-4A99-866E-E126ADBAD410'), + simExists('DFBC2970-9455-4FD9-BB62-9E4AE5AA6954'), + ]); + + for (let result of results) { + result.should.be.true; + } + }); + + it('returns false if device is not found', async function () { + let existence = []; + existence.push(simExists('A94E4CD7-D412-4198-BCD4-26799672975E')); + existence.push(simExists('asdf')); + existence.push(simExists(4)); + + let results = await B.all(existence); + + for (let result of results) { + result.should.be.false; + } + }); + }); + }); describe('Device preferences verification', function () {