From 7fe6c289b5db574dd449aa46d365220f8c406a74 Mon Sep 17 00:00:00 2001 From: Isaac Murchie Date: Mon, 28 Jan 2019 10:38:54 -0800 Subject: [PATCH] By default get all devices in getDevices --- .travis.yml | 4 ++ lib/simctl.js | 32 ++++++++----- test/simctl-e2e-specs.js | 100 +++++++++++++++++++++++---------------- 3 files changed, 82 insertions(+), 54 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3291836..9e24998 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,10 @@ matrix: node_js: "8" - osx_image: xcode10 node_js: "10" + - osx_image: xcode10.1 + node_js: "8" + - osx_image: xcode10.1 + node_js: "10" script: - _FORCE_LOGS=1 npm run test && npm run e2e-test after_success: diff --git a/lib/simctl.js b/lib/simctl.js index 05294cc..39269af 100644 --- a/lib/simctl.js +++ b/lib/simctl.js @@ -3,9 +3,8 @@ import { retryInterval, waitForCondition } from 'asyncbox'; import { logger, fs, tempDir } from 'appium-support'; import _ from 'lodash'; -const log = logger.getLogger('simctl'); -const IOS_PLATFORM = 'iOS'; +const log = logger.getLogger('simctl'); /** * Execute the particular simctl command and return the output. @@ -425,14 +424,14 @@ async function eraseDevice (udid, timeout = 1000) { * Parse the list of existing Simulator devices to represent * it as convenient mapping. * - * @param {?string} platform [iOS] - The platform name, for example 'watchOS'. + * @param {?string} platform - The platform name, for example 'watchOS'. * @return {Object} The resulting mapping. Each key is platform version, * for example '10.3' and the corresponding value is an * array of the matching {@link DeviceInfo} instances. * @throws {Error} If the corresponding simctl subcommand command * returns non-zero return code. */ -async function getDevicesByParsing (platform = IOS_PLATFORM) { +async function getDevicesByParsing (platform) { // get the list of devices const {stdout} = await simExec('list', 0, ['devices']); @@ -445,7 +444,9 @@ async function getDevicesByParsing (platform = IOS_PLATFORM) { // ... // so, get the `-- iOS X.X --` line to find the sdk (X.X) // and the rest of the listing in order to later find the devices - const deviceSectionRe = new RegExp(`\\-\\-\\s+${_.escapeRegExp(platform)}\\s+(\\S+)\\s+\\-\\-(\\n\\s{4}.+)*`, 'mgi'); + const deviceSectionRe = _.isEmpty(platform) + ? new RegExp(`\\-\\-\\s+\\S+\\s+(\\S+)\\s+\\-\\-(\\n\\s{4}.+)*`, 'mgi') + : new RegExp(`\\-\\-\\s+${_.escapeRegExp(platform)}\\s+(\\S+)\\s+\\-\\-(\\n\\s{4}.+)*`, 'mgi'); const matches = []; let match; // make an entry for each sdk version @@ -461,7 +462,7 @@ async function getDevicesByParsing (platform = IOS_PLATFORM) { const devices = {}; for (match of matches) { const sdk = match[1]; - devices[sdk] = []; + devices[sdk] = devices[sdk] || []; // split the full match into lines and remove the first for (const line of match[0].split('\n').slice(1)) { // a line is something like @@ -493,7 +494,7 @@ async function getDevicesByParsing (platform = IOS_PLATFORM) { * @param {?string} forSdk - The sdk version, * for which the devices list should be parsed, * for example '10.3'. - * @param {?string} platform [iOS] - The platform name, for example 'watchOS'. + * @param {?string} platform - The platform name, for example 'watchOS'. * @return {Object|Array} If _forSdk_ is set then the list * of devices for the particular platform version. * Otherwise the same result as for {@link getDevicesByParsing} @@ -502,7 +503,7 @@ async function getDevicesByParsing (platform = IOS_PLATFORM) { * returns non-zero return code or if no matching * platform version is found in the system. */ -async function getDevices (forSdk = null, platform = IOS_PLATFORM) { +async function getDevices (forSdk = null, platform) { let devices = {}; try { const {stdout} = await simExec('list', 0, ['devices', '-j']); @@ -520,19 +521,23 @@ async function getDevices (forSdk = null, platform = IOS_PLATFORM) { * } * } */ - const versionMatchRe = new RegExp(`^${_.escapeRegExp(platform)}\\s+(\\S+)`, 'i'); + const versionMatchRe = _.isEmpty(platform) + ? new RegExp(`^\\S+\\s+(\\S+)`, 'i') + : new RegExp(`^${_.escapeRegExp(platform)}\\s+(\\S+)`, 'i'); for (const [sdkName, entries] of _.toPairs(JSON.parse(stdout).devices)) { const versionMatch = versionMatchRe.exec(sdkName); if (!versionMatch) { continue; } - devices[versionMatch[1]] = entries.map((el) => { + const sdk = versionMatch[1]; + devices[sdk] = devices[sdk] || []; + devices[sdk].push(...entries.map((el) => { delete el.availability; return { + sdk, ...el, - sdk: versionMatch[1] }; - }); + })); } } catch (err) { log.debug(`Unable to get JSON device list: ${err.stack}`); @@ -556,12 +561,13 @@ async function getDevices (forSdk = null, platform = IOS_PLATFORM) { throw new Error(errMsg); } + /** * Get the runtime for the particular platform version. * * @param {string} platformVersion - The platform version name, * for example '10.3'. - * @param {?string} platform [iOS] - The platform name, for example 'watchOS'. + * @param {?string} platform - The platform name, for example 'watchOS'. * @return {string} The corresponding runtime name for the given * platform version. */ diff --git a/test/simctl-e2e-specs.js b/test/simctl-e2e-specs.js index ae133d6..77eaa7a 100644 --- a/test/simctl-e2e-specs.js +++ b/test/simctl-e2e-specs.js @@ -21,16 +21,17 @@ describe('simctl', function () { this.timeout(MOCHA_TIMEOUT); let randName; - let randDeviceUdid = null; let validSdks = []; + let sdk; before(async function () { - let devices = await getDevices(); + const devices = await getDevices(); validSdks = _.keys(devices).sort((a, b) => a - b); if (!validSdks.length) { throw new Error('No valid SDKs'); } console.log(`Found valid SDKs: ${validSdks.join(', ')}`); // eslint-disable-line no-console + sdk = _.last(validSdks); // need to find a random name that does not already exist // give it 5 tries @@ -50,26 +51,67 @@ describe('simctl', function () { } }); - it('should create a device', async function () { - let udid = await createDevice(randName, DEVICE_NAME, _.last(validSdks)); - (typeof udid).should.equal('string'); - udid.length.should.equal(36); + it('should retrieve a device with compatible properties', async function () { + const devices = (await getDevices())[sdk]; + const firstDevice = devices[0]; + const expectedList = ['name', 'sdk', 'state', 'udid']; + firstDevice.should.have.any.keys(...expectedList); }); - it('should get devices', async function () { - let sdkDevices = await getDevices(_.last(validSdks)); - _.map(sdkDevices, 'name').should.include(randName); - randDeviceUdid = sdkDevices.filter((d) => d.name === randName)[0].udid; - }); + describe('createDevice', function () { + let udid; + after(async function () { + if (udid) { + await deleteDevice(udid, 16000); + } + }); + + it('should create a device', async function () { + udid = await createDevice(randName, DEVICE_NAME, sdk); + (typeof udid).should.equal('string'); + udid.length.should.equal(36); + }); - it('should erase devices', async function () { - await eraseDevice(randDeviceUdid, 16000); + it('should create a device and be able to see it in devices list right away', async function () { + const numSimsBefore = (await getDevices())[sdk].length; + udid = await createDevice('node-simctl test', DEVICE_NAME, sdk); + const numSimsAfter = (await getDevices())[sdk].length; + numSimsAfter.should.equal(numSimsBefore + 1); + }); }); - it('should delete devices', async function () { - await deleteDevice(randDeviceUdid); - let sdkDevices = await getDevices(_.last(validSdks)); - _.map(sdkDevices, 'name').should.not.include(randName); + describe('device manipulation', function () { + let udid; + const name = 'node-simctl test'; + beforeEach(async function () { + udid = await createDevice('node-simctl test', DEVICE_NAME, sdk); + }); + afterEach(async function () { + if (udid) { + await deleteDevice(udid, 16000); + } + }); + it('should get devices', async function () { + const sdkDevices = await getDevices(sdk); + _.map(sdkDevices, 'name').should.include(name); + }); + + it('should erase devices', async function () { + await eraseDevice(udid, 16000); + }); + + it('should delete devices', async function () { + await deleteDevice(udid); + const sdkDevices = await getDevices(sdk); + _.map(sdkDevices, 'name').should.not.include(udid); + + // so we do not delete again + udid = null; + }); + + it('should not fail to shutdown a shutdown simulator', async function () { + await shutdown(udid).should.eventually.not.be.rejected; + }); }); it('should return a nice error for invalid usage', async function () { @@ -83,30 +125,6 @@ describe('simctl', function () { err.message.should.include('Invalid device type: bar'); }); - it('should create a device and be able to see it in devices list right away', async function () { - let sdk = _.last(validSdks); - let numSimsBefore = (await getDevices())[sdk].length; - let udid = await createDevice('node-simctl test', DEVICE_NAME, sdk); - let numSimsAfter = (await getDevices())[sdk].length; - numSimsAfter.should.equal(numSimsBefore + 1); - await deleteDevice(udid); - }); - - it('should create a device with compatible properties', async function () { - let sdk = _.last(validSdks); - let devices = (await getDevices())[sdk]; - let firstDevice = devices[0]; - let expectedList = ['name', 'sdk', 'state', 'udid']; - Object.keys(firstDevice).sort().should.eql(expectedList); - }); - - it('should not fail to shutdown a shutdown simulator', async function () { - let sdk = _.last(validSdks); - let udid = await createDevice('node-simctl test', DEVICE_NAME, sdk); - await shutdown(udid).should.eventually.not.be.rejected; - await deleteDevice(udid); - }); - describe('on running Simulator', function () { if (process.env.TRAVIS) { this.retries(3);