From ae9c471a1a42878a3161212264bc7e5a6ca4d8bb Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 6 Mar 2018 17:26:34 +0200 Subject: [PATCH 01/73] switch to e2e tests to jest --- detox/test/.watchmanconfig | 1 - .../test/e2e/{a-sanity.js => a-sanity.test.js} | 0 .../e2e/{b-matchers.js => b-matchers.test.js} | 0 .../e2e/{c-actions.js => c-actions.test.js} | 0 detox/test/e2e/config.json | 6 ++++++ .../{d-assertions.js => d-assertions.test.js} | 0 .../e2e/{e-waitfor.js => e-waitfor.test.js} | 0 .../test/e2e/{f-device.js => f-device.test.js} | 0 ...-stress-tests.js => g-stress-tests.test.js} | 0 ...{h-stress-root.js => h-stress-root.test.js} | 2 +- detox/test/e2e/helpers/init.js | 7 +++++++ ...s-timeouts.js => i-stress-timeouts.test.js} | 0 detox/test/e2e/init.js | 18 ------------------ ...lbacks.js => j-async-and-callbacks.test.js} | 0 ...cations.js => k-user-notifications.test.js} | 0 .../{l-animations.js => l-animations.test.js} | 0 ...{l-permissions.js => l-permissions.test.js} | 0 .../e2e/{m-network.js => m-network.test.js} | 4 ++-- detox/test/e2e/mocha.opts | 3 --- .../{n-deep-links.js => n-deep-links.test.js} | 0 .../e2e/{o-location.js => o-location.test.js} | 0 detox/test/package.json | 4 +++- 22 files changed, 19 insertions(+), 26 deletions(-) delete mode 100644 detox/test/.watchmanconfig rename detox/test/e2e/{a-sanity.js => a-sanity.test.js} (100%) rename detox/test/e2e/{b-matchers.js => b-matchers.test.js} (100%) rename detox/test/e2e/{c-actions.js => c-actions.test.js} (100%) create mode 100644 detox/test/e2e/config.json rename detox/test/e2e/{d-assertions.js => d-assertions.test.js} (100%) rename detox/test/e2e/{e-waitfor.js => e-waitfor.test.js} (100%) rename detox/test/e2e/{f-device.js => f-device.test.js} (100%) rename detox/test/e2e/{g-stress-tests.js => g-stress-tests.test.js} (100%) rename detox/test/e2e/{h-stress-root.js => h-stress-root.test.js} (96%) create mode 100644 detox/test/e2e/helpers/init.js rename detox/test/e2e/{i-stress-timeouts.js => i-stress-timeouts.test.js} (100%) delete mode 100644 detox/test/e2e/init.js rename detox/test/e2e/{j-async-and-callbacks.js => j-async-and-callbacks.test.js} (100%) rename detox/test/e2e/{k-user-notifications.js => k-user-notifications.test.js} (100%) rename detox/test/e2e/{l-animations.js => l-animations.test.js} (100%) rename detox/test/e2e/{l-permissions.js => l-permissions.test.js} (100%) rename detox/test/e2e/{m-network.js => m-network.test.js} (97%) delete mode 100644 detox/test/e2e/mocha.opts rename detox/test/e2e/{n-deep-links.js => n-deep-links.test.js} (100%) rename detox/test/e2e/{o-location.js => o-location.test.js} (100%) diff --git a/detox/test/.watchmanconfig b/detox/test/.watchmanconfig deleted file mode 100644 index 9e26dfeeb6..0000000000 --- a/detox/test/.watchmanconfig +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/detox/test/e2e/a-sanity.js b/detox/test/e2e/a-sanity.test.js similarity index 100% rename from detox/test/e2e/a-sanity.js rename to detox/test/e2e/a-sanity.test.js diff --git a/detox/test/e2e/b-matchers.js b/detox/test/e2e/b-matchers.test.js similarity index 100% rename from detox/test/e2e/b-matchers.js rename to detox/test/e2e/b-matchers.test.js diff --git a/detox/test/e2e/c-actions.js b/detox/test/e2e/c-actions.test.js similarity index 100% rename from detox/test/e2e/c-actions.js rename to detox/test/e2e/c-actions.test.js diff --git a/detox/test/e2e/config.json b/detox/test/e2e/config.json new file mode 100644 index 0000000000..b0135d74be --- /dev/null +++ b/detox/test/e2e/config.json @@ -0,0 +1,6 @@ +{ + "setupTestFrameworkScriptFile" : "./helpers/init.js", + "bail": true, + "verbose": true, + "forceExit": true +} \ No newline at end of file diff --git a/detox/test/e2e/d-assertions.js b/detox/test/e2e/d-assertions.test.js similarity index 100% rename from detox/test/e2e/d-assertions.js rename to detox/test/e2e/d-assertions.test.js diff --git a/detox/test/e2e/e-waitfor.js b/detox/test/e2e/e-waitfor.test.js similarity index 100% rename from detox/test/e2e/e-waitfor.js rename to detox/test/e2e/e-waitfor.test.js diff --git a/detox/test/e2e/f-device.js b/detox/test/e2e/f-device.test.js similarity index 100% rename from detox/test/e2e/f-device.js rename to detox/test/e2e/f-device.test.js diff --git a/detox/test/e2e/g-stress-tests.js b/detox/test/e2e/g-stress-tests.test.js similarity index 100% rename from detox/test/e2e/g-stress-tests.js rename to detox/test/e2e/g-stress-tests.test.js diff --git a/detox/test/e2e/h-stress-root.js b/detox/test/e2e/h-stress-root.test.js similarity index 96% rename from detox/test/e2e/h-stress-root.js rename to detox/test/e2e/h-stress-root.test.js index ada1cae9ea..e1b2ebb712 100644 --- a/detox/test/e2e/h-stress-root.js +++ b/detox/test/e2e/h-stress-root.test.js @@ -7,7 +7,7 @@ describe('StressRoot', () => { await element(by.text('Switch Root')).tap(); }); - after(async () => { + afterAll(async () => { await device.relaunchApp(); }); diff --git a/detox/test/e2e/helpers/init.js b/detox/test/e2e/helpers/init.js new file mode 100644 index 0000000000..b00a8c4ba1 --- /dev/null +++ b/detox/test/e2e/helpers/init.js @@ -0,0 +1,7 @@ +const detox = require('detox'); +const config = require('../../package.json').detox; +jest.setTimeout(480000); + +beforeAll(async () => { + await detox.init(config); +}); \ No newline at end of file diff --git a/detox/test/e2e/i-stress-timeouts.js b/detox/test/e2e/i-stress-timeouts.test.js similarity index 100% rename from detox/test/e2e/i-stress-timeouts.js rename to detox/test/e2e/i-stress-timeouts.test.js diff --git a/detox/test/e2e/init.js b/detox/test/e2e/init.js deleted file mode 100644 index b122f47fb4..0000000000 --- a/detox/test/e2e/init.js +++ /dev/null @@ -1,18 +0,0 @@ -const detox = require('detox'); -const config = require('../package.json').detox; - -before(async () => { - await detox.init(config); -}); - -after(async () => { - await detox.cleanup(); -}); - -beforeEach(async function() { - await detox.beforeEach(this.currentTest.parent.title, this.currentTest.title); -}); - -afterEach(async function() { - await detox.afterEach(this.currentTest.parent.title, this.currentTest.title); -}); \ No newline at end of file diff --git a/detox/test/e2e/j-async-and-callbacks.js b/detox/test/e2e/j-async-and-callbacks.test.js similarity index 100% rename from detox/test/e2e/j-async-and-callbacks.js rename to detox/test/e2e/j-async-and-callbacks.test.js diff --git a/detox/test/e2e/k-user-notifications.js b/detox/test/e2e/k-user-notifications.test.js similarity index 100% rename from detox/test/e2e/k-user-notifications.js rename to detox/test/e2e/k-user-notifications.test.js diff --git a/detox/test/e2e/l-animations.js b/detox/test/e2e/l-animations.test.js similarity index 100% rename from detox/test/e2e/l-animations.js rename to detox/test/e2e/l-animations.test.js diff --git a/detox/test/e2e/l-permissions.js b/detox/test/e2e/l-permissions.test.js similarity index 100% rename from detox/test/e2e/l-permissions.js rename to detox/test/e2e/l-permissions.test.js diff --git a/detox/test/e2e/m-network.js b/detox/test/e2e/m-network.test.js similarity index 97% rename from detox/test/e2e/m-network.js rename to detox/test/e2e/m-network.test.js index 1d6e102ee5..556b7b8ab5 100644 --- a/detox/test/e2e/m-network.js +++ b/detox/test/e2e/m-network.test.js @@ -3,11 +3,11 @@ const MockServer = require('../mock-server/mock-server'); describe('Network Synchronization', () => { let mockServer = new MockServer(); - before(async () => { + beforeAll(async () => { mockServer.init(); }); - after( () => { + afterAll( () => { mockServer.close(); }); diff --git a/detox/test/e2e/mocha.opts b/detox/test/e2e/mocha.opts deleted file mode 100644 index bfb952dc38..0000000000 --- a/detox/test/e2e/mocha.opts +++ /dev/null @@ -1,3 +0,0 @@ ---recursive ---timeout 480000 ---bail \ No newline at end of file diff --git a/detox/test/e2e/n-deep-links.js b/detox/test/e2e/n-deep-links.test.js similarity index 100% rename from detox/test/e2e/n-deep-links.js rename to detox/test/e2e/n-deep-links.test.js diff --git a/detox/test/e2e/o-location.js b/detox/test/e2e/o-location.test.js similarity index 100% rename from detox/test/e2e/o-location.js rename to detox/test/e2e/o-location.test.js diff --git a/detox/test/package.json b/detox/test/package.json index 6c9b0f73b3..0993d94a2e 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -18,11 +18,13 @@ "devDependencies": { "detox": "^7.0.0", "express": "^4.15.3", + "jest": "^22.3.0", "lodash": "^4.14.1", "mocha": "^4.0.0" }, "detox": { "specs": "e2e", + "test-runner": "jest", "__session": { "server": "ws://localhost:8099", "sessionId": "test" @@ -63,4 +65,4 @@ } } } -} \ No newline at end of file +} From 57ef87323123a0f22176c167a8c6c3cf27a83aa7 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 6 Mar 2018 20:23:44 +0200 Subject: [PATCH 02/73] downgrade test project to RN51 --- detox/test/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detox/test/package.json b/detox/test/package.json index 0993d94a2e..713ff276e3 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -12,8 +12,8 @@ "build:android": "detox build --configuration android.emu.release" }, "dependencies": { - "react": "16.2.0", - "react-native": "0.53.3" + "react": "16.0.0", + "react-native": "0.51.0" }, "devDependencies": { "detox": "^7.0.0", From c54109eb6e8a023291512ea12b7e38a8adc2b784 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 20 Feb 2018 13:01:12 +0200 Subject: [PATCH 03/73] wait for device based on bootstatus --- detox/ios/EarlGrey | 2 +- detox/src/devices/AppleSimUtils.js | 25 ++++++------------ detox/src/devices/AppleSimUtils.test.js | 34 +++---------------------- 3 files changed, 13 insertions(+), 48 deletions(-) diff --git a/detox/ios/EarlGrey b/detox/ios/EarlGrey index fa109ac51e..f51a5cfc7c 160000 --- a/detox/ios/EarlGrey +++ b/detox/ios/EarlGrey @@ -1 +1 @@ -Subproject commit fa109ac51e82d334e8daeb8f2dda7c491b29cee7 +Subproject commit f51a5cfc7cdf81fd3e21102a7439be756c3963dc diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 0d05da7bec..170a8947bd 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -44,25 +44,15 @@ class AppleSimUtils { return device; } - async waitForDeviceState(udid, state) { - let device; - await retry({ retries: 10, interval: 1000 }, async () => { - device = await this.findDeviceByUDID(udid); - if (!_.isEqual(device.state, state)) { - throw new Error(`device is in state '${device.state}'`); - } - }); - return device; + async boot(udid) { + if (!await this.isBooted(udid)) { + await this._bootDeviceByXcodeVersion(udid); + } } - async boot(udid) { + async isBooted(udid) { const device = await this.findDeviceByUDID(udid); - if (_.isEqual(device.state, 'Booted') || _.isEqual(device.state, 'Booting')) { - return false; - } - await this.waitForDeviceState(udid, 'Shutdown'); - await this._bootDeviceByXcodeVersion(udid); - await this.waitForDeviceState(udid, 'Booted'); + return (_.isEqual(device.state, 'Booted') || _.isEqual(device.state, 'Booting')); } async install(udid, absPath) { @@ -200,6 +190,7 @@ class AppleSimUtils { } else { await this._bootDeviceMagically(udid); } + await this._execSimctl({ cmd: `bootstatus ${udid}`, retries: 1 }); } async _bootDeviceMagically(udid) { @@ -245,4 +236,4 @@ class LogsInfo { } } -module.exports = AppleSimUtils; +module.exports = AppleSimUtils; \ No newline at end of file diff --git a/detox/src/devices/AppleSimUtils.test.js b/detox/src/devices/AppleSimUtils.test.js index 6af5efcbea..d52a01edbc 100644 --- a/detox/src/devices/AppleSimUtils.test.js +++ b/detox/src/devices/AppleSimUtils.test.js @@ -146,30 +146,6 @@ describe('AppleSimUtils', () => { }); }); - describe('waitForDeviceState', () => { - it('findsDeviceByUdid', async () => { - uut.findDeviceByUDID = jest.fn(() => Promise.resolve({ udid: 'the udid', state: 'the state' })); - retry.mockImplementation((opts, fn) => Promise.resolve(fn())); - const result = await uut.waitForDeviceState(`the udid`, `the state`); - expect(uut.findDeviceByUDID).toHaveBeenCalledTimes(1); - expect(result).toEqual({ udid: 'the udid', state: 'the state' }); - }); - - it('waits for state to be equal', async () => { - uut.findDeviceByUDID = jest.fn(() => Promise.resolve({ udid: 'the udid', state: 'different state' })); - retry.mockImplementation((opts, fn) => Promise.resolve(fn())); - try { - await uut.waitForDeviceState(`the udid`, `the state`); - fail(`should throw`); - } catch (e) { - expect(e).toEqual(new Error(`device is in state 'different state'`)); - } - expect(uut.findDeviceByUDID).toHaveBeenCalledTimes(1); - expect(retry).toHaveBeenCalledTimes(1); - expect(retry).toHaveBeenCalledWith({ retries: 10, interval: 1000 }, expect.any(Function)); - }); - }); - describe('getXcodeVersion', () => { it('returns xcode major version', async () => { exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({ stdout: 'Xcode 123.456\nBuild version 123abc123\n' })); @@ -206,16 +182,14 @@ describe('AppleSimUtils', () => { }); describe('boot', () => { + it('waits for device by udid to be Shutdown, boots magically, then waits for state to be Booted', async () => { uut.findDeviceByUDID = jest.fn(() => Promise.resolve({ state: 'unknown' })); - uut.waitForDeviceState = jest.fn(() => Promise.resolve(true)); uut.getXcodeVersion = jest.fn(() => Promise.resolve(1)); expect(exec.execWithRetriesAndLogs).not.toHaveBeenCalled(); - await uut.boot('some udid'); + await uut.boot('some-udid'); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith(expect.stringMatching('xcode-select -p'), undefined, expect.anything(), 1); - expect(uut.waitForDeviceState).toHaveBeenCalledTimes(2); - expect(uut.waitForDeviceState.mock.calls[0]).toEqual([`some udid`, `Shutdown`]); - expect(uut.waitForDeviceState.mock.calls[1]).toEqual([`some udid`, `Booted`]); + expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith(expect.stringMatching('bootstatus some-udid'), undefined, expect.anything(), 1); }); it('skips if device state was already Booted', async () => { @@ -223,6 +197,7 @@ describe('AppleSimUtils', () => { uut.getXcodeVersion = jest.fn(() => Promise.resolve(1)); await uut.boot('udid'); expect(uut.findDeviceByUDID).toHaveBeenCalledTimes(1); + expect(uut.findDeviceByUDID).toHaveBeenCalledWith('udid'); expect(exec.execWithRetriesAndLogs).not.toHaveBeenCalled(); }); @@ -239,7 +214,6 @@ describe('AppleSimUtils', () => { uut.getXcodeVersion = jest.fn(() => Promise.resolve(9)); await uut.boot('udid'); expect(uut.getXcodeVersion).toHaveBeenCalledTimes(1); - expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(1); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith(expect.stringMatching('xcrun simctl boot udid'), undefined, expect.anything(), 10); }); From f5cd1b941193b303f8fbf0a12061fb793ed9431b Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 20 Feb 2018 15:19:07 +0200 Subject: [PATCH 04/73] introduce findDevicesUDID and use in findDeviceUDID --- detox/src/devices/AppleSimUtils.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 170a8947bd..95c5fa214e 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -20,22 +20,27 @@ class AppleSimUtils { } async findDeviceUDID(query) { + const udids = await this.findDevicesUDID(query); + return udids ? udids[0] : undefined; + } + + async findDevicesUDID(query) { const statusLogs = { trying: `Searching for device matching ${query}...` }; let correctQuery = this._correctQueryWithOS(query); const response = await this._execAppleSimUtils({ args: `--list "${correctQuery}" --maxResults=1` }, statusLogs, 1); const parsed = this._parseResponseFromAppleSimUtils(response); - const udid = _.get(parsed, [0, 'udid']); - if (!udid) { + const udids = _.map(parsed, 'udid'); + if (!udids || !udids.length || !udids[0]) { throw new Error(`Can't find a simulator to match with "${query}", run 'xcrun simctl list' to list your supported devices. It is advised to only state a device type, and not to state iOS version, e.g. "iPhone 7"`); } - return udid; + return udids; } async findDeviceByUDID(udid) { - const response = await this._execAppleSimUtils({ args: `--list` }, undefined, 1); + const response = await this._execAppleSimUtils({args: `--list --byId "${udid}"`}, undefined, 1); const parsed = this._parseResponseFromAppleSimUtils(response); const device = _.find(parsed, (device) => _.isEqual(device.udid, udid)); if (!device) { From 3c2664958f8f0dfbcb3a898dab84413cd17ee6f1 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 6 Mar 2018 20:46:23 +0200 Subject: [PATCH 05/73] remove redundant check --- detox/src/devices/AppleSimUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 95c5fa214e..20755e021f 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -21,7 +21,7 @@ class AppleSimUtils { async findDeviceUDID(query) { const udids = await this.findDevicesUDID(query); - return udids ? udids[0] : undefined; + return udids[0]; } async findDevicesUDID(query) { From bdf4eb8c47834b138c62e64edc4410428126b262 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 20 Feb 2018 15:30:16 +0200 Subject: [PATCH 06/73] support multiple workers. for now set to 1 --- detox/local-cli/detox-test.js | 22 ++++++------- detox/src/devices/AppleSimUtils.js | 2 +- detox/src/devices/AppleSimUtils.test.js | 43 +++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index fac9b7cb0f..760e7a776e 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -72,21 +72,21 @@ function runMocha() { cp.execSync(command, {stdio: 'inherit'}); } -function runJest() { +function runJest(maxWorkers = 1) { const configFile = runnerConfig ? `--config=${runnerConfig}` : ''; const platform = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(program.platform)}).)*$'` : ''; - const command = `node_modules/.bin/jest ${testFolder} ${configFile} --runInBand ${platform}`; - console.log(command); + const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxWorkers} ${platform} --verbose`; + const env = Object.assign({}, process.env, { + configuration: program.configuration, + loglevel: program.loglevel, + cleanup: program.cleanup, + reuse: program.reuse, + debugSynchronization: program.debugSynchronization, + artifactsLocation: program.artifactsLocation + }); cp.execSync(command, { stdio: 'inherit', - env: Object.assign({}, process.env, { - configuration: program.configuration, - loglevel: program.loglevel, - cleanup: program.cleanup, - reuse: program.reuse, - debugSynchronization: program.debugSynchronization, - artifactsLocation: program.artifactsLocation - }) + env }); } diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 20755e021f..5774aa8db8 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -29,7 +29,7 @@ class AppleSimUtils { trying: `Searching for device matching ${query}...` }; let correctQuery = this._correctQueryWithOS(query); - const response = await this._execAppleSimUtils({ args: `--list "${correctQuery}" --maxResults=1` }, statusLogs, 1); + const response = await this._execAppleSimUtils({ args: `--list "${correctQuery}"` }, statusLogs, 1); const parsed = this._parseResponseFromAppleSimUtils(response); const udids = _.map(parsed, 'udid'); if (!udids || !udids.length || !udids[0]) { diff --git a/detox/src/devices/AppleSimUtils.test.js b/detox/src/devices/AppleSimUtils.test.js index d52a01edbc..76b60adc02 100644 --- a/detox/src/devices/AppleSimUtils.test.js +++ b/detox/src/devices/AppleSimUtils.test.js @@ -29,6 +29,45 @@ describe('AppleSimUtils', () => { expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(1); }); + describe('findDevicesUDID', () => { + + it('return multiple devices', async () => { + exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({ + stdout: JSON.stringify([ + { + "state": "Shutdown", + "availability": "(available)", + "name": "iPhone 6", + "udid": "the uuid1", + "os": { + "version": "10.3.1", + "availability": "(available)", + "name": "iOS 10.3", + "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-10-3", + "buildversion": "14E8301" + } + }, + { + "state": "Shutdown", + "availability": "(available)", + "name": "iPhone 6", + "udid": "the uuid2", + "os": { + "version": "10.3.1", + "availability": "(available)", + "name": "iOS 10.3", + "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-10-3", + "buildversion": "14E8301" + } + } + ]) + })); + const result = await uut.findDevicesUDID('iPhone 7'); + expect(result).toEqual(['the uuid1', 'the uuid2']); + }); + }); + + describe('findDeviceUDID', () => { it('correct params', async () => { expect(exec.execWithRetriesAndLogs).not.toHaveBeenCalled(); @@ -37,7 +76,7 @@ describe('AppleSimUtils', () => { } catch (e) { } expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(1); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith('applesimutils', { - args: `--list "iPhone 6" --maxResults=1` + args: `--list "iPhone 6"` }, expect.anything(), 1, undefined); }); @@ -46,7 +85,7 @@ describe('AppleSimUtils', () => { await uut.findDeviceUDID('iPhone 6 , iOS 10.3'); } catch (e) { } expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith('applesimutils', { - args: `--list "iPhone 6, OS=iOS 10.3" --maxResults=1` + args: `--list "iPhone 6, OS=iOS 10.3"` }, expect.anything(), 1, undefined); }); From fb9634923fb94d2cd7356081670f951e02b16116 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 6 Mar 2018 21:10:21 +0200 Subject: [PATCH 07/73] device registry # Conflicts: # detox/src/devices/AppleSimUtils.js # detox/test/package.json --- detox/package.json | 1 + detox/src/devices/DeviceRegistry.js | 67 ++++++++++++++++++++++ detox/src/devices/DeviceRegistry.test.js | 73 ++++++++++++++++++++++++ detox/src/devices/SimulatorDriver.js | 8 ++- detox/test/e2e/helpers/init.js | 24 +++++++- 5 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 detox/src/devices/DeviceRegistry.js create mode 100644 detox/src/devices/DeviceRegistry.test.js diff --git a/detox/package.json b/detox/package.json index 19acae1465..4cf47f3990 100644 --- a/detox/package.json +++ b/detox/package.json @@ -51,6 +51,7 @@ "ini": "^1.3.4", "lodash": "^4.14.1", "npmlog": "^4.0.2", + "proper-lockfile": "^3.0.2", "shell-utils": "^1.0.9", "tail": "^1.2.3", "telnet-client": "0.15.3", diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js new file mode 100644 index 0000000000..1abe74a658 --- /dev/null +++ b/detox/src/devices/DeviceRegistry.js @@ -0,0 +1,67 @@ +const fs = require('fs'); +const plockfile = require('proper-lockfile'); +const _ = require('lodash'); +const retry = require('../utils/retry'); +const LOCK_FILE = './device.registry.state.lock'; + +class DeviceRegistry { + + constructor({getDeviceIdsByType, maxTestRunners = 1, createDevice}) { + this.getDeviceIdsByType = getDeviceIdsByType; + this.maxTestRunners = maxTestRunners; + this.createDevice = createDevice; + createEmptyLockFileIfNeeded(); + } + + async getDevice(deviceType) { + await retry(() => plockfile.lockSync(LOCK_FILE)); + const deviceIds = await this.getDeviceIdsByType(deviceType); + await this._createDeviceIfNecessary({deviceIds}); + + const unlockedDeviceId = getFirstUnlocked(deviceIds); + if (unlockedDeviceId) { + const lockedDevices = getLockedDevices(); + lockedDevices.push(unlockedDeviceId); + writeLockedDevices(lockedDevices); + plockfile.unlockSync(LOCK_FILE); + return unlockedDeviceId; + } + plockfile.unlockSync(LOCK_FILE); + } + + async _createDeviceIfNecessary ({deviceIds}) { + const numberOfDevicesNeededToCreate = Math.max(this.maxTestRunners - deviceIds.length, 0); + _.times(numberOfDevicesNeededToCreate, async () => await this.createDevice()); + } + + static clear() { + writeLockedDevices([]); + } + +} + +const createEmptyLockFileIfNeeded = () => { + if (!fs.existsSync(LOCK_FILE)) { + writeLockedDevices([]); + } +}; + +const writeLockedDevices = lockedDevices => fs.writeFileSync(LOCK_FILE, JSON.stringify(lockedDevices)); + +const getLockedDevices = () => { + createEmptyLockFileIfNeeded(); + const lockFileContent = fs.readFileSync(LOCK_FILE, 'utf-8'); + return JSON.parse(lockFileContent); +}; + +const getFirstUnlocked = deviceIds => { + for (let i=0; i < deviceIds.length; i++) { + let deviceId = deviceIds[i]; + if (!getLockedDevices().includes(deviceId)) { + return deviceId; + } + } +}; + +DeviceRegistry.clear(); +module.exports = DeviceRegistry; \ No newline at end of file diff --git a/detox/src/devices/DeviceRegistry.test.js b/detox/src/devices/DeviceRegistry.test.js new file mode 100644 index 0000000000..2cba09bb1f --- /dev/null +++ b/detox/src/devices/DeviceRegistry.test.js @@ -0,0 +1,73 @@ +const DeviceRegistry = require('./DeviceRegistry'); + +describe('device registry', () => { + + let registry; + const createDevice = jest.fn(); + + function initRegistry({maxTestRunners, numberOfDevicesPerType = 1} = {}) { + const devicesIds = Array.from(Array(numberOfDevicesPerType).keys()); + const getDeviceIdsByType = type => devicesIds.map(deviceId => `id-${deviceId}-of-type-${type}`); + return new DeviceRegistry({getDeviceIdsByType, maxTestRunners, createDevice}); + } + + describe('device creation', () => { + + it('should create devices if they are not available', async () => { + const maxTestRunners = 4; + const numberOfDevicesPerType = 1; + + registry = initRegistry({maxTestRunners, numberOfDevicesPerType}); + await registry.getDevice('iPhoneX'); + + expect(createDevice).toHaveBeenCalledTimes(maxTestRunners - numberOfDevicesPerType); + }); + + it('should not create devices if they are available', async () => { + const maxTestRunners = 1; + const numberOfDevicesPerType = 1; + registry = initRegistry({numberOfDevicesPerType, maxTestRunners}); + await registry.getDevice('iPhoneX'); + + expect(createDevice).not.toHaveBeenCalled(); + }); + + }); + + it('should return a device id for a given type', async () => { + registry = initRegistry(); + DeviceRegistry.clear(); + + const ret = await registry.getDevice('iPhoneX'); + + expect(ret).toEqual('id-0-of-type-iPhoneX'); + }); + + it('should return a device id for a given type when the registry contains multiple ids', async () => { + registry = initRegistry({numberOfDevicesPerType: 2}); + DeviceRegistry.clear(); + const ret = await registry.getDevice('iPhoneX'); + + expect(ret).toEqual('id-0-of-type-iPhoneX'); + }); + + it('should not return a device id for a given type if the device is locked', async () => { + registry = initRegistry(); + await registry.getDevice('iPhoneX'); + const ret = await registry.getDevice('iPhoneX'); + + expect(ret).toEqual(undefined); + }); + + it('should not return a device id for a given type if the device is locked in a different registry', async () => { + registry = initRegistry(); + const registry2 = initRegistry(); + await registry2.getDevice('iPhoneX'); + + const ret = await registry.getDevice('iPhoneX'); + + expect(ret).toEqual(undefined); + }); + + +}); \ No newline at end of file diff --git a/detox/src/devices/SimulatorDriver.js b/detox/src/devices/SimulatorDriver.js index 26e180fb85..21822cc97d 100644 --- a/detox/src/devices/SimulatorDriver.js +++ b/detox/src/devices/SimulatorDriver.js @@ -6,12 +6,14 @@ const IosDriver = require('./IosDriver'); const AppleSimUtils = require('./AppleSimUtils'); const configuration = require('../configuration'); const environment = require('../utils/environment'); +const DeviceRegistry = require('./DeviceRegistry'); class SimulatorDriver extends IosDriver { constructor(client) { super(client); this._applesimutils = new AppleSimUtils(); + this.deviceRegistry = new DeviceRegistry({getDeviceIdsByType: async type => await this._applesimutils.findDevicesUDID(type)}); } async prepare() { @@ -23,8 +25,12 @@ class SimulatorDriver extends IosDriver { } } + async cleanup(deviceId, bundleId) { + return super.cleanup(deviceId, bundleId); + } + async acquireFreeDevice(name) { - const deviceId = await this._applesimutils.findDeviceUDID(name); + const deviceId = await this.deviceRegistry.getDevice(name); await this.boot(deviceId); return deviceId; } diff --git a/detox/test/e2e/helpers/init.js b/detox/test/e2e/helpers/init.js index b00a8c4ba1..7fd65afc8c 100644 --- a/detox/test/e2e/helpers/init.js +++ b/detox/test/e2e/helpers/init.js @@ -2,6 +2,28 @@ const detox = require('detox'); const config = require('../../package.json').detox; jest.setTimeout(480000); + beforeAll(async () => { await detox.init(config); -}); \ No newline at end of file +}); + +afterAll(async () => { + await detox.cleanup(); +}) +// +// let testID; +// +// beforeEach(async () => { +// // DeviceManager.lock +// // await detox.beforeEach(this.currentTest.parent.title, this.currentTest.title); +// +// testID = Math.floor(Math.random() * 100); +// detox.lock(testID); +// +// console.log('DDDDDDD BEFORE EZCG GLOBAL') +// }); +// +// afterEach(async () => { +// detox.release(testID); +// console.log('DDDDDDD AFTER EZCG GLOBAL') +// }); From bf31acbb0f0707c05ead70a21149df47da66e009 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 6 Mar 2018 21:12:37 +0200 Subject: [PATCH 08/73] device registry # Conflicts: # detox/src/devices/AppleSimUtils.js # detox/test/package.json --- detox/local-cli/detox-test.js | 10 ++-- detox/src/devices/AppleSimUtils.js | 12 +++++ detox/src/devices/AppleSimUtils.test.js | 68 ++++++++++++++++++++++++ detox/src/devices/DeviceRegistry.js | 7 +-- detox/src/devices/DeviceRegistry.test.js | 31 ++++++++--- detox/src/devices/SimulatorDriver.js | 12 ++++- detox/test/e2e/config.json | 1 + detox/test/e2e/helpers/init.js | 32 +++++------ detox/test/package.json | 1 + 9 files changed, 141 insertions(+), 33 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 760e7a776e..5f0ac2bf2c 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -24,6 +24,8 @@ program .option('-p, --platform [ios/android]', 'Run platform specific tests. Runs tests with invert grep on \':platform:\', ' + 'e.g test with substring \':ios:\' in its name will not run when passing \'--platform android\'') + .option('-w, --max-test-workers [value]', + `Number of test workers (default is 1)`) .parse(process.argv); const config = require(path.join(process.cwd(), 'package.json')).detox; @@ -72,17 +74,19 @@ function runMocha() { cp.execSync(command, {stdio: 'inherit'}); } -function runJest(maxWorkers = 1) { +function runJest() { const configFile = runnerConfig ? `--config=${runnerConfig}` : ''; const platform = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(program.platform)}).)*$'` : ''; - const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxWorkers} ${platform} --verbose`; + const maxTestWorkers = getConfigFor('maxTestWorkers', 1); + const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxTestWorkers} ${platform} --verbose --bail`; const env = Object.assign({}, process.env, { configuration: program.configuration, loglevel: program.loglevel, cleanup: program.cleanup, reuse: program.reuse, debugSynchronization: program.debugSynchronization, - artifactsLocation: program.artifactsLocation + artifactsLocationartifactsLocation: program.artifactsLocation, + maxTestWorkers, }); cp.execSync(command, { stdio: 'inherit', diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 5774aa8db8..47505db7d6 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -60,6 +60,18 @@ class AppleSimUtils { return (_.isEqual(device.state, 'Booted') || _.isEqual(device.state, 'Booting')); } + async create(type) { + const result = await this._execSimctl({ cmd: `list runtimes -j` }); + const stdout = _.get(result, 'stdout'); + const runtimes = JSON.parse(stdout); + const newestRuntime = _.maxBy(runtimes.runtimes, r => Number(r.version)); + if (newestRuntime) { + console.log('Creating simulator', `create "${type}" "${type}" "${newestRuntime.identifier}"`) + await this._execSimctl({cmd: `create "${type}" "${type}" "${newestRuntime.identifier}"`}); + return true; + } + } + async install(udid, absPath) { const statusLogs = { trying: `Installing ${absPath}...`, diff --git a/detox/src/devices/AppleSimUtils.test.js b/detox/src/devices/AppleSimUtils.test.js index 76b60adc02..1410e7bab6 100644 --- a/detox/src/devices/AppleSimUtils.test.js +++ b/detox/src/devices/AppleSimUtils.test.js @@ -258,6 +258,74 @@ describe('AppleSimUtils', () => { }); }); + describe('create', () => { + it('calls xcrun', async () => { + exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: "{}"})); + + const created = await uut.create('name'); + expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(1); + expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith( + `/usr/bin/xcrun simctl list runtimes -j`, + undefined, + expect.anything(), + 1); + expect(created).toEqual(undefined); + }); + + it('creates using the newest runtime version', async () => { + const runtimes = { + "runtimes" : [ + { + "buildversion" : "13C75", + "availability" : "(available)", + "name" : "iOS 9.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-2", + "version" : "9.2" + }, + { + "buildversion" : "13E233", + "availability" : "(available)", + "name" : "iOS 9.3", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-3", + "version" : "9.3" + }, + { + "buildversion" : "15C107", + "availability" : "(available)", + "name" : "iOS 11.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-11-2", + "version" : "11.2" + }, + { + "buildversion" : "15K104", + "availability" : "(available)", + "name" : "tvOS 11.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.tvOS-11-2", + "version" : "11.2" + }, + { + "buildversion" : "15S100", + "availability" : "(available)", + "name" : "watchOS 4.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.watchOS-4-2", + "version" : "4.2" + } + ] + }; + exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: JSON.stringify(runtimes)})); + + const created = await uut.create('iPhone 8 Plus'); + + expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith( + `/usr/bin/xcrun simctl create "iPhone 8 Plus" "iPhone 8 Plus" "com.apple.CoreSimulator.SimRuntime.iOS-11-2"`, + undefined, + expect.anything(), + 1); + expect(created).toEqual(true); + }); + }); + + describe('install', () => { it('calls xcrun', async () => { await uut.install('udid', 'somePath'); diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 1abe74a658..99c6356cf7 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -16,7 +16,7 @@ class DeviceRegistry { async getDevice(deviceType) { await retry(() => plockfile.lockSync(LOCK_FILE)); const deviceIds = await this.getDeviceIdsByType(deviceType); - await this._createDeviceIfNecessary({deviceIds}); + await this._createDeviceIfNecessary({deviceIds, deviceType}); const unlockedDeviceId = getFirstUnlocked(deviceIds); if (unlockedDeviceId) { @@ -27,11 +27,12 @@ class DeviceRegistry { return unlockedDeviceId; } plockfile.unlockSync(LOCK_FILE); + throw new Error(`Unable to find unlocked device ${deviceType}`); } - async _createDeviceIfNecessary ({deviceIds}) { + async _createDeviceIfNecessary ({deviceIds, deviceType}) { const numberOfDevicesNeededToCreate = Math.max(this.maxTestRunners - deviceIds.length, 0); - _.times(numberOfDevicesNeededToCreate, async () => await this.createDevice()); + _.times(numberOfDevicesNeededToCreate, async () => await this.createDevice(deviceType)); } static clear() { diff --git a/detox/src/devices/DeviceRegistry.test.js b/detox/src/devices/DeviceRegistry.test.js index 2cba09bb1f..320ff8fabd 100644 --- a/detox/src/devices/DeviceRegistry.test.js +++ b/detox/src/devices/DeviceRegistry.test.js @@ -21,13 +21,18 @@ describe('device registry', () => { await registry.getDevice('iPhoneX'); expect(createDevice).toHaveBeenCalledTimes(maxTestRunners - numberOfDevicesPerType); + expect(createDevice).toHaveBeenCalledWith('iPhoneX'); }); - it('should not create devices if they are available', async () => { + it('should not create devices if there is no need', async () => { const maxTestRunners = 1; const numberOfDevicesPerType = 1; registry = initRegistry({numberOfDevicesPerType, maxTestRunners}); - await registry.getDevice('iPhoneX'); + try { + await registry.getDevice('iPhoneX'); + } + catch (e) { + } expect(createDevice).not.toHaveBeenCalled(); }); @@ -53,8 +58,8 @@ describe('device registry', () => { it('should not return a device id for a given type if the device is locked', async () => { registry = initRegistry(); - await registry.getDevice('iPhoneX'); - const ret = await registry.getDevice('iPhoneX'); + await tryGetDevice('iPhoneX'); + const ret = await tryGetDevice('iPhoneX'); expect(ret).toEqual(undefined); }); @@ -62,12 +67,26 @@ describe('device registry', () => { it('should not return a device id for a given type if the device is locked in a different registry', async () => { registry = initRegistry(); const registry2 = initRegistry(); - await registry2.getDevice('iPhoneX'); + try { + await registry2.getDevice('iPhoneX'); + } + catch (e) { + // ignore + } - const ret = await registry.getDevice('iPhoneX'); + const ret = await tryGetDevice('iPhoneX'); expect(ret).toEqual(undefined); }); + const tryGetDevice = async name => { + try { + await registry.getDevice(name); + } + catch (e) { + // ignore + } + } + }); \ No newline at end of file diff --git a/detox/src/devices/SimulatorDriver.js b/detox/src/devices/SimulatorDriver.js index 21822cc97d..fbcd333694 100644 --- a/detox/src/devices/SimulatorDriver.js +++ b/detox/src/devices/SimulatorDriver.js @@ -13,7 +13,11 @@ class SimulatorDriver extends IosDriver { constructor(client) { super(client); this._applesimutils = new AppleSimUtils(); - this.deviceRegistry = new DeviceRegistry({getDeviceIdsByType: async type => await this._applesimutils.findDevicesUDID(type)}); + this.deviceRegistry = new DeviceRegistry({ + maxTestRunners: global.process.env.maxTestRunners, + getDeviceIdsByType: async type => await this._applesimutils.findDevicesUDID(type), + createDevice: type => this._applesimutils.create(type), + }); } async prepare() { @@ -31,7 +35,11 @@ class SimulatorDriver extends IosDriver { async acquireFreeDevice(name) { const deviceId = await this.deviceRegistry.getDevice(name); - await this.boot(deviceId); + if (deviceId) { + await this.boot(deviceId); + } else { + console.error('Unable to acquire free device ', name); + } return deviceId; } diff --git a/detox/test/e2e/config.json b/detox/test/e2e/config.json index b0135d74be..1c870c47c1 100644 --- a/detox/test/e2e/config.json +++ b/detox/test/e2e/config.json @@ -1,5 +1,6 @@ { "setupTestFrameworkScriptFile" : "./helpers/init.js", + "testEnvironment": "node", "bail": true, "verbose": true, "forceExit": true diff --git a/detox/test/e2e/helpers/init.js b/detox/test/e2e/helpers/init.js index 7fd65afc8c..e672255871 100644 --- a/detox/test/e2e/helpers/init.js +++ b/detox/test/e2e/helpers/init.js @@ -2,28 +2,22 @@ const detox = require('detox'); const config = require('../../package.json').detox; jest.setTimeout(480000); - beforeAll(async () => { await detox.init(config); }); afterAll(async () => { await detox.cleanup(); -}) -// -// let testID; -// -// beforeEach(async () => { -// // DeviceManager.lock -// // await detox.beforeEach(this.currentTest.parent.title, this.currentTest.title); -// -// testID = Math.floor(Math.random() * 100); -// detox.lock(testID); -// -// console.log('DDDDDDD BEFORE EZCG GLOBAL') -// }); -// -// afterEach(async () => { -// detox.release(testID); -// console.log('DDDDDDD AFTER EZCG GLOBAL') -// }); +}); + +beforeEach(async function() { + await detox.beforeEach(jasmine.testPath); +}); + +afterEach(async function() { + await detox.afterEach(jasmine.testPath); +}); + +process.on('unhandledRejection', (reason, p) => { + console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); +}); \ No newline at end of file diff --git a/detox/test/package.json b/detox/test/package.json index 713ff276e3..8f3fd2a7b5 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -7,6 +7,7 @@ "packager": "react-native start", "detox-server": "detox run-server", "e2e:ios": "detox test --configuration ios.sim.release --debug-synchronization 10000 --platform ios", + "e2e:ios-multi": "detox test --configuration ios.sim.release --debug-synchronization 10000 --platform ios --loglevel info --max-test-workers 3", "e2e:android": "detox test --configuration android.emu.release --loglevel verbose --platform android", "build:ios": "detox build --configuration ios.sim.release", "build:android": "detox build --configuration android.emu.release" From 5c5d92350c3c6e01740149e368479117cc06857c Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 6 Mar 2018 21:20:09 +0200 Subject: [PATCH 09/73] fix device registry race condition --- detox/local-cli/detox-test.js | 13 +++++++++++-- detox/src/devices/DeviceRegistry.js | 9 ++++++++- detox/src/devices/DeviceRegistry.test.js | 24 ++++++++++++++++++++++-- detox/src/devices/SimulatorDriver.js | 3 ++- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 5f0ac2bf2c..5e7c82ccdb 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -28,6 +28,8 @@ program `Number of test workers (default is 1)`) .parse(process.argv); +clearDeviceRegistryLockFile(); + const config = require(path.join(process.cwd(), 'package.json')).detox; const testFolder = getConfigFor('specs', 'e2e'); @@ -78,7 +80,7 @@ function runJest() { const configFile = runnerConfig ? `--config=${runnerConfig}` : ''; const platform = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(program.platform)}).)*$'` : ''; const maxTestWorkers = getConfigFor('maxTestWorkers', 1); - const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxTestWorkers} ${platform} --verbose --bail`; + const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxTestWorkers} ${platform}`; const env = Object.assign({}, process.env, { configuration: program.configuration, loglevel: program.loglevel, @@ -119,4 +121,11 @@ function getPlatformSpecificString(platform) { } return platformRevertString; -} \ No newline at end of file +} + +function clearDeviceRegistryLockFile() { + const fs = require('fs'); + const LOCK_FILE = './device.registry.state.lock'; + fs.writeFileSync(LOCK_FILE, '[]'); +} + diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 99c6356cf7..344172961a 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -30,6 +30,14 @@ class DeviceRegistry { throw new Error(`Unable to find unlocked device ${deviceType}`); } + static async freeDevice(deviceId) { + await retry(() => plockfile.lockSync(LOCK_FILE)); + const lockedDevices = getLockedDevices(); + _.remove(lockedDevices, lockedDeviceId => lockedDeviceId === deviceId); + writeLockedDevices(lockedDevices); + plockfile.unlockSync(LOCK_FILE); + } + async _createDeviceIfNecessary ({deviceIds, deviceType}) { const numberOfDevicesNeededToCreate = Math.max(this.maxTestRunners - deviceIds.length, 0); _.times(numberOfDevicesNeededToCreate, async () => await this.createDevice(deviceType)); @@ -64,5 +72,4 @@ const getFirstUnlocked = deviceIds => { } }; -DeviceRegistry.clear(); module.exports = DeviceRegistry; \ No newline at end of file diff --git a/detox/src/devices/DeviceRegistry.test.js b/detox/src/devices/DeviceRegistry.test.js index 320ff8fabd..0baad04a0c 100644 --- a/detox/src/devices/DeviceRegistry.test.js +++ b/detox/src/devices/DeviceRegistry.test.js @@ -5,13 +5,15 @@ describe('device registry', () => { let registry; const createDevice = jest.fn(); - function initRegistry({maxTestRunners, numberOfDevicesPerType = 1} = {}) { + function initRegistry({maxTestRunners = 1, numberOfDevicesPerType = 1} = {}) { const devicesIds = Array.from(Array(numberOfDevicesPerType).keys()); const getDeviceIdsByType = type => devicesIds.map(deviceId => `id-${deviceId}-of-type-${type}`); return new DeviceRegistry({getDeviceIdsByType, maxTestRunners, createDevice}); } - describe('device creation', () => { + describe('create device', () => { + + beforeEach(DeviceRegistry.clear); it('should create devices if they are not available', async () => { const maxTestRunners = 4; @@ -39,6 +41,24 @@ describe('device registry', () => { }); + + describe('free device', () => { + + beforeEach(DeviceRegistry.clear); + + it('should free device', async () => { + registry = initRegistry({}); + await registry.getDevice('iPhoneX'); + + expect(await tryGetDevice('iPhoneX')).toEqual(undefined); + + await DeviceRegistry.freeDevice('id-0-of-type-iPhoneX'); + + expect(await registry.getDevice('iPhoneX')).toEqual('id-0-of-type-iPhoneX'); + }); + + }); + it('should return a device id for a given type', async () => { registry = initRegistry(); DeviceRegistry.clear(); diff --git a/detox/src/devices/SimulatorDriver.js b/detox/src/devices/SimulatorDriver.js index fbcd333694..8283eb1e95 100644 --- a/detox/src/devices/SimulatorDriver.js +++ b/detox/src/devices/SimulatorDriver.js @@ -14,7 +14,7 @@ class SimulatorDriver extends IosDriver { super(client); this._applesimutils = new AppleSimUtils(); this.deviceRegistry = new DeviceRegistry({ - maxTestRunners: global.process.env.maxTestRunners, + maxTestRunners: global.process.env.maxTestWorkers, getDeviceIdsByType: async type => await this._applesimutils.findDevicesUDID(type), createDevice: type => this._applesimutils.create(type), }); @@ -30,6 +30,7 @@ class SimulatorDriver extends IosDriver { } async cleanup(deviceId, bundleId) { + await DeviceRegistry.freeDevice(deviceId); return super.cleanup(deviceId, bundleId); } From f18c34c55930e345d298f1f2f5f7326fe563e832 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 6 Mar 2018 21:23:22 +0200 Subject: [PATCH 10/73] move maxTestWorkers param to detox config --- detox/local-cli/detox-test.js | 5 ++++- detox/test/package.json | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 5e7c82ccdb..f12989632d 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -3,6 +3,8 @@ const program = require('commander'); const path = require('path'); const cp = require('child_process'); +const _ = require('lodash'); + program .option('-o, --runner-config [config]', `Test runner config file, defaults to e2e/mocha.opts for mocha and e2e/config.json' for jest`) @@ -77,9 +79,10 @@ function runMocha() { } function runJest() { + const currentConfiguration = config.configurations && config.configurations[program.configuration]; + const maxTestWorkers = _.get(currentConfiguration, 'maxTestWorkers', 1); const configFile = runnerConfig ? `--config=${runnerConfig}` : ''; const platform = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(program.platform)}).)*$'` : ''; - const maxTestWorkers = getConfigFor('maxTestWorkers', 1); const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxTestWorkers} ${platform}`; const env = Object.assign({}, process.env, { configuration: program.configuration, diff --git a/detox/test/package.json b/detox/test/package.json index 8f3fd2a7b5..454fce5bb4 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -7,7 +7,7 @@ "packager": "react-native start", "detox-server": "detox run-server", "e2e:ios": "detox test --configuration ios.sim.release --debug-synchronization 10000 --platform ios", - "e2e:ios-multi": "detox test --configuration ios.sim.release --debug-synchronization 10000 --platform ios --loglevel info --max-test-workers 3", + "e2e:ios-multi": "detox test --configuration ios.sim.release-multi --debug-synchronization 10000 --platform ios --loglevel info --max-test-workers 3", "e2e:android": "detox test --configuration android.emu.release --loglevel verbose --platform android", "build:ios": "detox build --configuration ios.sim.release", "build:android": "detox build --configuration android.emu.release" @@ -43,6 +43,13 @@ "type": "ios.simulator", "name": "iPhone 8 Plus" }, + "ios.sim.release-multi": { + "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/example.app", + "build": "set -o pipefail && export CODE_SIGNING_REQUIRED=NO && export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -project ios/example.xcodeproj -scheme example_ci -configuration Release -sdk iphonesimulator -derivedDataPath ios/build | xcpretty", + "type": "ios.simulator", + "name": "iPhone 8 Plus", + "maxTestWorkers": 3 + }, "ios.none": { "binaryPath": "ios", "type": "ios.none", From 5004898c8b37493f91c62c8f2c016f70249d4110 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Sun, 4 Mar 2018 10:26:28 +0200 Subject: [PATCH 11/73] clean up --- detox/local-cli/detox-test.js | 3 --- detox/test/package.json | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index f12989632d..71c5f59b2f 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -26,8 +26,6 @@ program .option('-p, --platform [ios/android]', 'Run platform specific tests. Runs tests with invert grep on \':platform:\', ' + 'e.g test with substring \':ios:\' in its name will not run when passing \'--platform android\'') - .option('-w, --max-test-workers [value]', - `Number of test workers (default is 1)`) .parse(process.argv); clearDeviceRegistryLockFile(); @@ -74,7 +72,6 @@ function runMocha() { const debugSynchronization = program.debugSynchronization ? `--debug-synchronization ${program.debugSynchronization}` : ''; const command = `node_modules/.bin/mocha ${testFolder} ${configFile} ${configuration} ${loglevel} ${cleanup} ${reuse} ${debugSynchronization} ${platform} ${artifactsLocation}`; - console.log(command); cp.execSync(command, {stdio: 'inherit'}); } diff --git a/detox/test/package.json b/detox/test/package.json index 454fce5bb4..8e93188f2c 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -7,7 +7,7 @@ "packager": "react-native start", "detox-server": "detox run-server", "e2e:ios": "detox test --configuration ios.sim.release --debug-synchronization 10000 --platform ios", - "e2e:ios-multi": "detox test --configuration ios.sim.release-multi --debug-synchronization 10000 --platform ios --loglevel info --max-test-workers 3", + "e2e:ios-multi": "detox test --configuration ios.sim.release-multi --debug-synchronization 10000 --platform ios --loglevel info", "e2e:android": "detox test --configuration android.emu.release --loglevel verbose --platform android", "build:ios": "detox build --configuration ios.sim.release", "build:android": "detox build --configuration android.emu.release" From 74849ae57220356bb59e867eb2552c7bc8984688 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 6 Mar 2018 22:41:08 +0200 Subject: [PATCH 12/73] -forceExit --- detox/test/e2e/config.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/detox/test/e2e/config.json b/detox/test/e2e/config.json index 1c870c47c1..1f51a1ce7b 100644 --- a/detox/test/e2e/config.json +++ b/detox/test/e2e/config.json @@ -2,6 +2,5 @@ "setupTestFrameworkScriptFile" : "./helpers/init.js", "testEnvironment": "node", "bail": true, - "verbose": true, - "forceExit": true + "verbose": true } \ No newline at end of file From 4251edc72b46da8fda6e773915ba9e84e91b0d5e Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Wed, 7 Mar 2018 12:02:37 +0200 Subject: [PATCH 13/73] error when no runtime is available --- detox/src/devices/AppleSimUtils.js | 4 +- detox/src/devices/AppleSimUtils.test.js | 99 ++++++++++++++----------- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 47505db7d6..76de55d1c1 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -66,9 +66,11 @@ class AppleSimUtils { const runtimes = JSON.parse(stdout); const newestRuntime = _.maxBy(runtimes.runtimes, r => Number(r.version)); if (newestRuntime) { - console.log('Creating simulator', `create "${type}" "${type}" "${newestRuntime.identifier}"`) + console.log('Creating simulator', `create "${type}" "${type}" "${newestRuntime.identifier}"`); await this._execSimctl({cmd: `create "${type}" "${type}" "${newestRuntime.identifier}"`}); return true; + } else { + throw new Error(`Unable to create device. No runtime found for ${type}`); } } diff --git a/detox/src/devices/AppleSimUtils.test.js b/detox/src/devices/AppleSimUtils.test.js index 1410e7bab6..14e6cc96b4 100644 --- a/detox/src/devices/AppleSimUtils.test.js +++ b/detox/src/devices/AppleSimUtils.test.js @@ -259,59 +259,72 @@ describe('AppleSimUtils', () => { }); describe('create', () => { - it('calls xcrun', async () => { - exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: "{}"})); + + const runtimes = { + "runtimes" : [ + { + "buildversion" : "13C75", + "availability" : "(available)", + "name" : "iOS 9.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-2", + "version" : "9.2" + }, + { + "buildversion" : "13E233", + "availability" : "(available)", + "name" : "iOS 9.3", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-3", + "version" : "9.3" + }, + { + "buildversion" : "15C107", + "availability" : "(available)", + "name" : "iOS 11.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-11-2", + "version" : "11.2" + }, + { + "buildversion" : "15K104", + "availability" : "(available)", + "name" : "tvOS 11.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.tvOS-11-2", + "version" : "11.2" + }, + { + "buildversion" : "15S100", + "availability" : "(available)", + "name" : "watchOS 4.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.watchOS-4-2", + "version" : "4.2" + } + ] + }; + + it('calls xcrun to get a list of runtimes', async () => { + exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: JSON.stringify(runtimes)})); const created = await uut.create('name'); - expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(1); + expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(2); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith( `/usr/bin/xcrun simctl list runtimes -j`, undefined, expect.anything(), 1); - expect(created).toEqual(undefined); }); + it('errors when there is no runtime available', async () => { + exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: "{}"})); + try { + await uut.create('name1'); + fail(`should throw`); + } + catch (e) { + expect(`${e}`).toEqual('Error: Unable to create device. No runtime found for name1'); + } + }); + + it('creates using the newest runtime version', async () => { - const runtimes = { - "runtimes" : [ - { - "buildversion" : "13C75", - "availability" : "(available)", - "name" : "iOS 9.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-2", - "version" : "9.2" - }, - { - "buildversion" : "13E233", - "availability" : "(available)", - "name" : "iOS 9.3", - "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-3", - "version" : "9.3" - }, - { - "buildversion" : "15C107", - "availability" : "(available)", - "name" : "iOS 11.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-11-2", - "version" : "11.2" - }, - { - "buildversion" : "15K104", - "availability" : "(available)", - "name" : "tvOS 11.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.tvOS-11-2", - "version" : "11.2" - }, - { - "buildversion" : "15S100", - "availability" : "(available)", - "name" : "watchOS 4.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.watchOS-4-2", - "version" : "4.2" - } - ] - }; exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: JSON.stringify(runtimes)})); const created = await uut.create('iPhone 8 Plus'); From 3bc6518879ae1c8adb409aef407f429f4199b748 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Wed, 7 Mar 2018 12:03:29 +0200 Subject: [PATCH 14/73] use dot notation --- detox/local-cli/detox-test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 71c5f59b2f..f2f5cfee99 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -3,7 +3,6 @@ const program = require('commander'); const path = require('path'); const cp = require('child_process'); -const _ = require('lodash'); program .option('-o, --runner-config [config]', @@ -77,7 +76,7 @@ function runMocha() { function runJest() { const currentConfiguration = config.configurations && config.configurations[program.configuration]; - const maxTestWorkers = _.get(currentConfiguration, 'maxTestWorkers', 1); + const maxTestWorkers = currentConfiguration.maxTestWorkers || 1; const configFile = runnerConfig ? `--config=${runnerConfig}` : ''; const platform = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(program.platform)}).)*$'` : ''; const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxTestWorkers} ${platform}`; From f839c3dfdd0297c4c5a386486b7d3f4859d81233 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Wed, 7 Mar 2018 12:15:52 +0200 Subject: [PATCH 15/73] move lock file to ~/Library/Detox --- detox/src/devices/DeviceRegistry.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 344172961a..ebfc6fa830 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -1,8 +1,9 @@ +const os = require('os'); const fs = require('fs'); const plockfile = require('proper-lockfile'); const _ = require('lodash'); const retry = require('../utils/retry'); -const LOCK_FILE = './device.registry.state.lock'; +const LOCK_FILE = `${os.homedir()}/Library/Detox/device.registry.state.lock`; class DeviceRegistry { From fa268cd1656155b49df55719104c00efd4af3b09 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Wed, 7 Mar 2018 12:35:17 +0200 Subject: [PATCH 16/73] adjust lock file retry options --- detox/src/devices/DeviceRegistry.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index ebfc6fa830..99a2030491 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -4,6 +4,7 @@ const plockfile = require('proper-lockfile'); const _ = require('lodash'); const retry = require('../utils/retry'); const LOCK_FILE = `${os.homedir()}/Library/Detox/device.registry.state.lock`; +const LOCK_RETRY_OPTIONS = {retries: Number.MAX_SAFE_INTEGER, interval: 5}; class DeviceRegistry { @@ -15,7 +16,7 @@ class DeviceRegistry { } async getDevice(deviceType) { - await retry(() => plockfile.lockSync(LOCK_FILE)); + await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(LOCK_FILE)); const deviceIds = await this.getDeviceIdsByType(deviceType); await this._createDeviceIfNecessary({deviceIds, deviceType}); @@ -32,7 +33,7 @@ class DeviceRegistry { } static async freeDevice(deviceId) { - await retry(() => plockfile.lockSync(LOCK_FILE)); + await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(LOCK_FILE)); const lockedDevices = getLockedDevices(); _.remove(lockedDevices, lockedDeviceId => lockedDeviceId === deviceId); writeLockedDevices(lockedDevices); From d5e7dabf18d8304f060f5ad31daef48121e84bfa Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Wed, 7 Mar 2018 12:39:20 +0200 Subject: [PATCH 17/73] use functions instead of consts when declaring functions --- detox/src/devices/DeviceRegistry.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 99a2030491..965bd919b7 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -51,27 +51,29 @@ class DeviceRegistry { } -const createEmptyLockFileIfNeeded = () => { +function createEmptyLockFileIfNeeded() { if (!fs.existsSync(LOCK_FILE)) { writeLockedDevices([]); } -}; +} -const writeLockedDevices = lockedDevices => fs.writeFileSync(LOCK_FILE, JSON.stringify(lockedDevices)); +function writeLockedDevices(lockedDevices) { + fs.writeFileSync(LOCK_FILE, JSON.stringify(lockedDevices)); +} -const getLockedDevices = () => { +function getLockedDevices() { createEmptyLockFileIfNeeded(); const lockFileContent = fs.readFileSync(LOCK_FILE, 'utf-8'); return JSON.parse(lockFileContent); -}; +} -const getFirstUnlocked = deviceIds => { +function getFirstUnlocked(deviceIds) { for (let i=0; i < deviceIds.length; i++) { let deviceId = deviceIds[i]; if (!getLockedDevices().includes(deviceId)) { return deviceId; } } -}; +} module.exports = DeviceRegistry; \ No newline at end of file From 06b917ec652cfff81c5551b1bfa5657a090b1233 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Wed, 7 Mar 2018 12:47:00 +0200 Subject: [PATCH 18/73] use const for detox library root path --- detox/src/devices/DeviceRegistry.js | 4 ++-- detox/src/utils/environment.js | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 965bd919b7..68d6b906a4 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -1,9 +1,9 @@ -const os = require('os'); const fs = require('fs'); const plockfile = require('proper-lockfile'); const _ = require('lodash'); const retry = require('../utils/retry'); -const LOCK_FILE = `${os.homedir()}/Library/Detox/device.registry.state.lock`; +const {DETOX_LIBRARY_ROOT_PATH} = require('../utils/environment'); +const LOCK_FILE = `${DETOX_LIBRARY_ROOT_PATH}/device.registry.state.lock`; const LOCK_RETRY_OPTIONS = {retries: Number.MAX_SAFE_INTEGER, interval: 5}; class DeviceRegistry { diff --git a/detox/src/utils/environment.js b/detox/src/utils/environment.js index 823a67627e..9bad8f9dd9 100644 --- a/detox/src/utils/environment.js +++ b/detox/src/utils/environment.js @@ -1,6 +1,7 @@ const os = require('os'); const path = require('path'); const exec = require('child-process-promise').exec; +const DETOX_LIBRARY_ROOT_PATH = `${os.homedir()}/Library/Detox`; function getAndroidSDKPath() { let sdkPath = process.env.ANDROID_SDK_ROOT || process.env.ANDROID_HOME; @@ -18,11 +19,12 @@ function getDetoxVersion() { async function getFrameworkPath() { const detoxVersion = this.getDetoxVersion(); const sha1 = (await exec(`(echo "${detoxVersion}" && xcodebuild -version) | shasum | awk '{print $1}'`)).stdout.trim(); - return `${os.homedir()}/Library/Detox/ios/${sha1}/Detox.framework`; + return `${DETOX_LIBRARY_ROOT_PATH}/ios/${sha1}/Detox.framework`; } module.exports = { getDetoxVersion, getFrameworkPath, - getAndroidSDKPath + getAndroidSDKPath, + DETOX_LIBRARY_ROOT_PATH }; From d3dcdfbc92b5d7283a09a711e6f93226232993cc Mon Sep 17 00:00:00 2001 From: Rotem M Date: Wed, 7 Mar 2018 14:59:34 +0200 Subject: [PATCH 19/73] Reset EarlGrey submodule --- detox/ios/EarlGrey | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/ios/EarlGrey b/detox/ios/EarlGrey index f51a5cfc7c..fa109ac51e 160000 --- a/detox/ios/EarlGrey +++ b/detox/ios/EarlGrey @@ -1 +1 @@ -Subproject commit f51a5cfc7cdf81fd3e21102a7439be756c3963dc +Subproject commit fa109ac51e82d334e8daeb8f2dda7c491b29cee7 From caa6fc872dc317cf3727c0437da9835c42d9fe4b Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Wed, 7 Mar 2018 17:08:24 +0200 Subject: [PATCH 20/73] dummy commit --- detox/local-cli/detox-test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index f2f5cfee99..84d3354986 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -127,4 +127,3 @@ function clearDeviceRegistryLockFile() { const LOCK_FILE = './device.registry.state.lock'; fs.writeFileSync(LOCK_FILE, '[]'); } - From a26e200a04ffa62a8a3f5c8c2a7a3b63e88c4477 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Wed, 7 Mar 2018 19:45:47 +0200 Subject: [PATCH 21/73] verbose postinstall --- detox/scripts/postinstall.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/scripts/postinstall.sh b/detox/scripts/postinstall.sh index e21c7007ea..928ea208ce 100755 --- a/detox/scripts/postinstall.sh +++ b/detox/scripts/postinstall.sh @@ -1,4 +1,4 @@ -#!/bin/bash -e +#!/bin/bash -ex if [ "$__DETOX_DEV" = true ]; then echo "Running postinstall for detox dev mode, exiting" From 70cb9d56cf6336f3b73c3d5f17f200019f11de3d Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Thu, 8 Mar 2018 11:21:20 +0200 Subject: [PATCH 22/73] simplified root path to fix Android build --- detox/src/utils/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/utils/environment.js b/detox/src/utils/environment.js index 9bad8f9dd9..a86210e2a4 100644 --- a/detox/src/utils/environment.js +++ b/detox/src/utils/environment.js @@ -1,7 +1,7 @@ const os = require('os'); const path = require('path'); const exec = require('child-process-promise').exec; -const DETOX_LIBRARY_ROOT_PATH = `${os.homedir()}/Library/Detox`; +const DETOX_LIBRARY_ROOT_PATH = os.homedir(); function getAndroidSDKPath() { let sdkPath = process.env.ANDROID_SDK_ROOT || process.env.ANDROID_HOME; From 4c72215f0e1b4f04656c04a2785f33d1c5236a65 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Thu, 8 Mar 2018 11:45:04 +0200 Subject: [PATCH 23/73] Revert "simplified root path to fix Android build" This reverts commit 70cb9d56cf6336f3b73c3d5f17f200019f11de3d. --- detox/src/utils/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/utils/environment.js b/detox/src/utils/environment.js index a86210e2a4..9bad8f9dd9 100644 --- a/detox/src/utils/environment.js +++ b/detox/src/utils/environment.js @@ -1,7 +1,7 @@ const os = require('os'); const path = require('path'); const exec = require('child-process-promise').exec; -const DETOX_LIBRARY_ROOT_PATH = os.homedir(); +const DETOX_LIBRARY_ROOT_PATH = `${os.homedir()}/Library/Detox`; function getAndroidSDKPath() { let sdkPath = process.env.ANDROID_SDK_ROOT || process.env.ANDROID_HOME; From 406740ee961b0df055110dacc285eba54712f7b8 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Thu, 8 Mar 2018 11:54:07 +0200 Subject: [PATCH 24/73] simplified root path to fix Android build --- detox/src/devices/DeviceRegistry.js | 19 +++++++++---------- detox/src/utils/environment.js | 4 +++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 68d6b906a4..9cfa3d8b39 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -2,8 +2,7 @@ const fs = require('fs'); const plockfile = require('proper-lockfile'); const _ = require('lodash'); const retry = require('../utils/retry'); -const {DETOX_LIBRARY_ROOT_PATH} = require('../utils/environment'); -const LOCK_FILE = `${DETOX_LIBRARY_ROOT_PATH}/device.registry.state.lock`; +const {DEVICE_LOCK_FILE_PATH} = require('../utils/environment'); const LOCK_RETRY_OPTIONS = {retries: Number.MAX_SAFE_INTEGER, interval: 5}; class DeviceRegistry { @@ -16,7 +15,7 @@ class DeviceRegistry { } async getDevice(deviceType) { - await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(LOCK_FILE)); + await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(DEVICE_LOCK_FILE_PATH)); const deviceIds = await this.getDeviceIdsByType(deviceType); await this._createDeviceIfNecessary({deviceIds, deviceType}); @@ -25,19 +24,19 @@ class DeviceRegistry { const lockedDevices = getLockedDevices(); lockedDevices.push(unlockedDeviceId); writeLockedDevices(lockedDevices); - plockfile.unlockSync(LOCK_FILE); + plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); return unlockedDeviceId; } - plockfile.unlockSync(LOCK_FILE); + plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); throw new Error(`Unable to find unlocked device ${deviceType}`); } static async freeDevice(deviceId) { - await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(LOCK_FILE)); + await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(DEVICE_LOCK_FILE_PATH)); const lockedDevices = getLockedDevices(); _.remove(lockedDevices, lockedDeviceId => lockedDeviceId === deviceId); writeLockedDevices(lockedDevices); - plockfile.unlockSync(LOCK_FILE); + plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); } async _createDeviceIfNecessary ({deviceIds, deviceType}) { @@ -52,18 +51,18 @@ class DeviceRegistry { } function createEmptyLockFileIfNeeded() { - if (!fs.existsSync(LOCK_FILE)) { + if (!fs.existsSync(DEVICE_LOCK_FILE_PATH)) { writeLockedDevices([]); } } function writeLockedDevices(lockedDevices) { - fs.writeFileSync(LOCK_FILE, JSON.stringify(lockedDevices)); + fs.writeFileSync(DEVICE_LOCK_FILE_PATH, JSON.stringify(lockedDevices)); } function getLockedDevices() { createEmptyLockFileIfNeeded(); - const lockFileContent = fs.readFileSync(LOCK_FILE, 'utf-8'); + const lockFileContent = fs.readFileSync(DEVICE_LOCK_FILE_PATH, 'utf-8'); return JSON.parse(lockFileContent); } diff --git a/detox/src/utils/environment.js b/detox/src/utils/environment.js index 9bad8f9dd9..a93f891ed3 100644 --- a/detox/src/utils/environment.js +++ b/detox/src/utils/environment.js @@ -2,6 +2,8 @@ const os = require('os'); const path = require('path'); const exec = require('child-process-promise').exec; const DETOX_LIBRARY_ROOT_PATH = `${os.homedir()}/Library/Detox`; +const DETOX_ROOT_PATH = os.homedir(); +const DEVICE_LOCK_FILE_PATH = path.join(DETOX_ROOT_PATH, 'device.registry.state.lock'); function getAndroidSDKPath() { let sdkPath = process.env.ANDROID_SDK_ROOT || process.env.ANDROID_HOME; @@ -26,5 +28,5 @@ module.exports = { getDetoxVersion, getFrameworkPath, getAndroidSDKPath, - DETOX_LIBRARY_ROOT_PATH + DEVICE_LOCK_FILE_PATH }; From 04b624395951e30e5ef463b63bb17be5949ff9d6 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Sat, 10 Mar 2018 20:00:52 +0200 Subject: [PATCH 25/73] dummy commit --- detox/src/devices/DeviceRegistry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 9cfa3d8b39..2634f3da24 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -75,4 +75,4 @@ function getFirstUnlocked(deviceIds) { } } -module.exports = DeviceRegistry; \ No newline at end of file +module.exports = DeviceRegistry; From ddbdd06386ba1dc61e7b2964ef332a9749829257 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Sat, 10 Mar 2018 22:11:01 +0200 Subject: [PATCH 26/73] run e2e w/ parallelization in ci --- scripts/ci.ios.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index f39dce8c00..bc422fe4e2 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -6,6 +6,6 @@ run_f "$(dirname "$0")/unit.ios.sh" pushd detox/test run_f "npm run build:ios" -run_f "npm run e2e:ios" +run_f "npm run e2e:ios-multi" popd #npm run release \ No newline at end of file From 712e6de47e67d47cebb1b04d4c35d4d3d99032cf Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Sat, 10 Mar 2018 23:23:25 +0200 Subject: [PATCH 27/73] dummy commit --- detox/src/devices/DeviceRegistry.js | 1 + 1 file changed, 1 insertion(+) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 2634f3da24..7a47c15980 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -76,3 +76,4 @@ function getFirstUnlocked(deviceIds) { } module.exports = DeviceRegistry; + From 9b0c50a3832f874e1a34dc5c41763eb36c887ba3 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Sun, 11 Mar 2018 11:19:39 +0200 Subject: [PATCH 28/73] temp - added troubleshooting logs --- detox/src/devices/AppleSimUtils.js | 1 + detox/src/utils/exec.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 76de55d1c1..5dea115652 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -61,6 +61,7 @@ class AppleSimUtils { } async create(type) { + await this._execSimctl({ cmd: `list devices -j` }); const result = await this._execSimctl({ cmd: `list runtimes -j` }); const stdout = _.get(result, 'stdout'); const runtimes = JSON.parse(stdout); diff --git a/detox/src/utils/exec.js b/detox/src/utils/exec.js index 741fd34394..dfedb6eccf 100644 --- a/detox/src/utils/exec.js +++ b/detox/src/utils/exec.js @@ -17,7 +17,7 @@ async function execWithRetriesAndLogs(bin, options, statusLogs, retries = 10, in cmd = bin; } - log.verbose(`${_operationCounter}: ${cmd}`); + log.info(`${_operationCounter}: ${cmd}`); let result; await retry({retries, interval}, async () => { @@ -31,11 +31,11 @@ async function execWithRetriesAndLogs(bin, options, statusLogs, retries = 10, in } if (result.stdout) { - log.verbose(`${_operationCounter}: stdout:`, result.stdout); + log.info(`${_operationCounter}: stdout:`, result.stdout); } if (result.stderr) { - log.verbose(`${_operationCounter}: stderr:`, result.stderr); + log.info(`${_operationCounter}: stderr:`, result.stderr); } if (statusLogs && statusLogs.successful) { From bc79553c2cea78fc42384ebc7b1c19de5e13519b Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Sun, 11 Mar 2018 14:40:41 +0200 Subject: [PATCH 29/73] Revert "temp - added troubleshooting logs" This reverts commit 9b0c50a3832f874e1a34dc5c41763eb36c887ba3. --- detox/src/devices/AppleSimUtils.js | 1 - detox/src/utils/exec.js | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 5dea115652..76de55d1c1 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -61,7 +61,6 @@ class AppleSimUtils { } async create(type) { - await this._execSimctl({ cmd: `list devices -j` }); const result = await this._execSimctl({ cmd: `list runtimes -j` }); const stdout = _.get(result, 'stdout'); const runtimes = JSON.parse(stdout); diff --git a/detox/src/utils/exec.js b/detox/src/utils/exec.js index dfedb6eccf..741fd34394 100644 --- a/detox/src/utils/exec.js +++ b/detox/src/utils/exec.js @@ -17,7 +17,7 @@ async function execWithRetriesAndLogs(bin, options, statusLogs, retries = 10, in cmd = bin; } - log.info(`${_operationCounter}: ${cmd}`); + log.verbose(`${_operationCounter}: ${cmd}`); let result; await retry({retries, interval}, async () => { @@ -31,11 +31,11 @@ async function execWithRetriesAndLogs(bin, options, statusLogs, retries = 10, in } if (result.stdout) { - log.info(`${_operationCounter}: stdout:`, result.stdout); + log.verbose(`${_operationCounter}: stdout:`, result.stdout); } if (result.stderr) { - log.info(`${_operationCounter}: stderr:`, result.stderr); + log.verbose(`${_operationCounter}: stderr:`, result.stderr); } if (statusLogs && statusLogs.successful) { From 7de97acb2b8013cc8f56c585c7e5ae074f7c60f7 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Mon, 12 Mar 2018 17:43:44 +0200 Subject: [PATCH 30/73] merge --- detox/test/e2e/n-network.test.js | 4 ++-- .../e2e/{o-deep-links.test.test.js => o-deep-links.test.js} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename detox/test/e2e/{o-deep-links.test.test.js => o-deep-links.test.js} (100%) diff --git a/detox/test/e2e/n-network.test.js b/detox/test/e2e/n-network.test.js index 1d6e102ee5..556b7b8ab5 100644 --- a/detox/test/e2e/n-network.test.js +++ b/detox/test/e2e/n-network.test.js @@ -3,11 +3,11 @@ const MockServer = require('../mock-server/mock-server'); describe('Network Synchronization', () => { let mockServer = new MockServer(); - before(async () => { + beforeAll(async () => { mockServer.init(); }); - after( () => { + afterAll( () => { mockServer.close(); }); diff --git a/detox/test/e2e/o-deep-links.test.test.js b/detox/test/e2e/o-deep-links.test.js similarity index 100% rename from detox/test/e2e/o-deep-links.test.test.js rename to detox/test/e2e/o-deep-links.test.js From 00c40d3387df69faffaef7b07b31b0123d9ef8ca Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Mon, 12 Mar 2018 17:46:08 +0200 Subject: [PATCH 31/73] make sure single works --- scripts/ci.ios.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index bc422fe4e2..f39dce8c00 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -6,6 +6,6 @@ run_f "$(dirname "$0")/unit.ios.sh" pushd detox/test run_f "npm run build:ios" -run_f "npm run e2e:ios-multi" +run_f "npm run e2e:ios" popd #npm run release \ No newline at end of file From 3630f5a7711cbfb05cd64d83e30259e9a0c0d7b9 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Tue, 13 Mar 2018 21:34:38 +0200 Subject: [PATCH 32/73] fix clear lock file path --- detox/local-cli/detox-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 84d3354986..78d0d91c18 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -124,6 +124,7 @@ function getPlatformSpecificString(platform) { function clearDeviceRegistryLockFile() { const fs = require('fs'); - const LOCK_FILE = './device.registry.state.lock'; + const os = require('os'); + const LOCK_FILE = path.join(os.homedir(),'device.registry.state.lock'); fs.writeFileSync(LOCK_FILE, '[]'); } From 646168ca34b70e5143e3f26815e34632c8a21535 Mon Sep 17 00:00:00 2001 From: Doron Pearl Date: Thu, 15 Mar 2018 16:09:04 +0200 Subject: [PATCH 33/73] improve closed socket error message --- detox/src/client/AsyncWebSocket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/client/AsyncWebSocket.js b/detox/src/client/AsyncWebSocket.js index e944c35e12..8c76a622cd 100644 --- a/detox/src/client/AsyncWebSocket.js +++ b/detox/src/client/AsyncWebSocket.js @@ -51,7 +51,7 @@ class AsyncWebSocket { async send(message, messageId) { if (!this.ws) { - throw new Error(`Can't send a message on a closed websocket, init the by calling 'open()'`); + throw new Error(`Can't send a message on a closed websocket, init the by calling 'open()'. Message: ${message}`); } return new Promise(async(resolve, reject) => { From f40373fadc6a5e91eb695f6480a56c8b660404e7 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Wed, 2 May 2018 14:34:53 +0300 Subject: [PATCH 34/73] WIP --- detox/local-cli/detox-test.js | 4 +- detox/scripts/postinstall.sh | 2 +- detox/src/devices/AppleSimUtils.js | 27 +- detox/src/devices/AppleSimUtils.test.js | 1064 ++++++++++++++++- detox/src/devices/DeviceRegistry.js | 2 - ...ling.test.js => 19.crash-handling.test.js} | 0 6 files changed, 1039 insertions(+), 60 deletions(-) rename detox/test/e2e/{29.crash-handling.test.js => 19.crash-handling.test.js} (100%) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 251371c5fe..12d12b3f7d 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -42,7 +42,6 @@ program clearDeviceRegistryLockFile(); -const config = require(path.join(process.cwd(), 'package.json')).detox; if (program.configuration) { if (!config.configurations[program.configuration]) { @@ -124,8 +123,7 @@ function runJest() { reuse: program.reuse, debugSynchronization: program.debugSynchronization, artifactsLocation: program.artifactsLocation, - headless: program.headless, - maxTestWorkers, + headless: program.headless }); cp.execSync(command, { diff --git a/detox/scripts/postinstall.sh b/detox/scripts/postinstall.sh index 4be60276de..f05bfc8668 100755 --- a/detox/scripts/postinstall.sh +++ b/detox/scripts/postinstall.sh @@ -1,4 +1,4 @@ -#!/bin/bash -ex +#!/bin/bash -e if [ `uname` == "Darwin" ]; then source "$(dirname ${0})/build_framework.ios.sh" diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index a5ca64f773..e0a6815a1a 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -60,17 +60,30 @@ class AppleSimUtils { return (_.isEqual(device.state, 'Booted') || _.isEqual(device.state, 'Booting')); } - async create(type) { - const result = await this._execSimctl({ cmd: `list runtimes -j` }); + async create(name) { + + const IPHONES = { + "iPhone 8": "iPhone2017-A", + "iPhone 8 Plus": "iPhone2017-B", + "iPhone X": "iPhone2017-C" + }; + + if (IPHONES[name]) { + name = IPHONES[name]; + } + + const result = await this._execSimctl({ cmd: `list -j` }); const stdout = _.get(result, 'stdout'); - const runtimes = JSON.parse(stdout); - const newestRuntime = _.maxBy(runtimes.runtimes, r => Number(r.version)); + const output = JSON.parse(stdout); + const deviceType = _.filter(output.devicetypes, { 'name': name})[0]; + const newestRuntime = _.maxBy(output.runtimes, r => Number(r.version)); + if (newestRuntime) { - console.log('Creating simulator', `create "${type}" "${type}" "${newestRuntime.identifier}"`); - await this._execSimctl({cmd: `create "${type}" "${type}" "${newestRuntime.identifier}"`}); + //console.log(`create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`); + await this._execSimctl({cmd: `create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`}); return true; } else { - throw new Error(`Unable to create device. No runtime found for ${type}`); + throw new Error(`Unable to create device. No runtime found for ${name}`); } } diff --git a/detox/src/devices/AppleSimUtils.test.js b/detox/src/devices/AppleSimUtils.test.js index 7825569c1e..597ce20f0c 100644 --- a/detox/src/devices/AppleSimUtils.test.js +++ b/detox/src/devices/AppleSimUtils.test.js @@ -1,3 +1,5 @@ +const _ = require('lodash'); + describe('AppleSimUtils', () => { let AppleSimUtils; let uut; @@ -260,53 +262,1021 @@ describe('AppleSimUtils', () => { describe('create', () => { - const runtimes = { - "runtimes" : [ - { - "buildversion" : "13C75", - "availability" : "(available)", - "name" : "iOS 9.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-2", - "version" : "9.2" - }, - { - "buildversion" : "13E233", - "availability" : "(available)", - "name" : "iOS 9.3", - "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-3", - "version" : "9.3" - }, - { - "buildversion" : "15C107", - "availability" : "(available)", - "name" : "iOS 11.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-11-2", - "version" : "11.2" - }, - { - "buildversion" : "15K104", - "availability" : "(available)", - "name" : "tvOS 11.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.tvOS-11-2", - "version" : "11.2" + const simctlList = { + "devicetypes" : [ + { + "name" : "iPhone 4s", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-4s" + }, + { + "name" : "iPhone 5", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-5" + }, + { + "name" : "iPhone 5s", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-5s" + }, + { + "name" : "iPhone 6", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6" + }, + { + "name" : "iPhone 6 Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus" + }, + { + "name" : "iPhone 6s", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6s" + }, + { + "name" : "iPhone 6s Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus" + }, + { + "name" : "iPhone 7", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-7" + }, + { + "name" : "iPhone 7 Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus" + }, + { + "name" : "iPhone SE", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-SE" + }, + { + "name" : "iPhone2017-A", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8" + }, + { + "name" : "iPhone2017-B", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus" + }, + { + "name" : "iPhone2017-C", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-X" + }, + { + "name" : "iPad 2", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-2" + }, + { + "name" : "iPad Retina", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Retina" + }, + { + "name" : "iPad Air", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Air" + }, + { + "name" : "iPad Air 2", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2" + }, + { + "name" : "iPad (5th generation)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad--5th-generation-" + }, + { + "name" : "iPad Pro (9.7-inch)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-" + }, + { + "name" : "iPad Pro (12.9-inch)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro" + }, + { + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---2nd-generation-" + }, + { + "name" : "iPad Pro (10.5-inch)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--10-5-inch-" + }, + { + "name" : "Apple TV", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p" + }, + { + "name" : "Apple TV 4K", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-4K" + }, + { + "name" : "Apple TV 4K (at 1080p)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-1080p" + }, + { + "name" : "Apple Watch - 38mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm" + }, + { + "name" : "Apple Watch - 42mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm" + }, + { + "name" : "Apple Watch Series 2 - 38mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-38mm" + }, + { + "name" : "Apple Watch Series 2 - 42mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-42mm" + }, + { + "name" : "Watch2017 - 38mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-3-38mm" + }, + { + "name" : "Watch2017 - 42mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-3-42mm" + } + ], + "runtimes" : [ + { + "buildversion" : "13C75", + "availability" : "(available)", + "name" : "iOS 9.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-2", + "version" : "9.2" + }, + { + "buildversion" : "15A372", + "availability" : "(available)", + "name" : "iOS 11.0", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-11-0", + "version" : "11.0" + }, + { + "buildversion" : "15J380", + "availability" : "(available)", + "name" : "tvOS 11.0", + "identifier" : "com.apple.CoreSimulator.SimRuntime.tvOS-11-0", + "version" : "11.0" + }, + { + "buildversion" : "15R372", + "availability" : "(available)", + "name" : "watchOS 4.0", + "identifier" : "com.apple.CoreSimulator.SimRuntime.watchOS-4-0", + "version" : "4.0" + } + ], + "devices" : { + "com.apple.CoreSimulator.SimRuntime.iOS-10-3" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "D4D2213B-1A98-4EBD-8E03-F52B4E739B45" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "F069D970-41D1-44C6-A1B1-8C0E3A10D5A0" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "15DD6668-072D-444E-BD56-C143665F6CD6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "908DC74E-FA0B-48FE-AD88-6FBBCB017250" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "6609FFB6-08C8-4195-ADBE-D1EDC4004ECF" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "08E4145F-5AE4-4BD2-8937-169F7793E6E2" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "1187FB7A-61B9-4892-B812-4E97C950C1A9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7 Plus", + "udid" : "D12A1E7C-3E50-4168-8731-AE8DFB702C6C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone SE", + "udid" : "ABDC82BE-A1AA-4AC3-AC63-20C3200CA868" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "36E04E65-EDC4-4199-9B8D-F5F20D907BE9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "9B5CEB84-A78B-471D-BCDF-A5406A2C78B9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad (5th generation)", + "udid" : "EE27F2B8-4ECA-48D5-9AAA-5B6B71E4B47A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (9.7 inch)", + "udid" : "DF67BCEB-1E98-4862-8E29-4262E45C36DD" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9 inch)", + "udid" : "464C614E-0B52-459E-81F8-5D48E6726A01" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "udid" : "4243CB58-55C7-4668-8F75-868B6FC1E411" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (10.5-inch)", + "udid" : "FA595536-1EFD-412E-8FC8-4E9945CF59A1" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-9-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "86C23AE7-E9E0-4358-91EB-DEA118CF5B4C" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-3-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "65216D2D-8329-4720-B7B7-56DE1DA223DE" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "B288646D-8B92-4799-A5F8-55ACF7EAB4FC" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "C41A6B35-7FBD-4A25-BC59-A11DD490E543" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "1089EFA6-E851-42DD-B88F-945193DBC47C" + } + ], + "iOS 9.2" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6s Plus", + "udid" : "9E22FA5C-1225-4BB0-9883-03AA139BA731" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-10-0" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "9EC2F2E1-3FCC-4635-BC69-7558AB64E2B8" + } + ], + "tvOS 11.0" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV 1080p", + "udid" : "4F521FFA-99FF-4815-B1FE-0B19AC2A740D" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV 4K", + "udid" : "C0A6390F-C364-4922-AE22-C983A46409A3" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV 4K (at 1080p)", + "udid" : "8C1B1F1E-5FED-449F-A918-6C0E808EAA3D" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-9-3" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 4s", + "udid" : "A0C05A53-04A7-4D19-BEC9-5BF961483DD9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "6AEBE78B-E6B3-443B-8B8F-D91F8E766A23" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "F2132AC3-CECF-4EAF-9763-58CE584A1C94" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "A26635FD-0DCA-4679-9934-19AA7DEC59DB" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "03743681-7CA5-47C2-B4F8-CF8D03272FB6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "291E8BFF-2576-43A1-9B14-AF07937BED6A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "FA4ACAFA-8CA1-4EF0-B594-6A856C006B51" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad 2", + "udid" : "FEF98A7E-0630-4C4C-83C1-1FB7F2129D83" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Retina", + "udid" : "FBCD1D2D-B9AC-4201-B850-BB6363CA2D7C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "85D3A5F6-E982-4751-8C2F-3FB68A6ED2E4" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "CAE43B00-1766-4804-8D4B-99A48B8D7858" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro", + "udid" : "880C4E47-C6DC-45F8-BDF6-8B167561C274" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-10-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "95A9A35D-9C9D-4360-A266-1AB1D5D0A8CA" + } + ], + "watchOS 4.0" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch - 38mm", + "udid" : "98631D9A-A2B3-4752-8A3E-92E990BAE106" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch - 42mm", + "udid" : "79E7E680-0D9F-40A2-9EE4-2F7EB351A094" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "6812D5A9-2931-467F-A349-7F46953B0F32" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "70FB6CDE-A5CB-4995-9CCB-9288E93C7308" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 3 - 38mm", + "udid" : "F080A29E-2615-46D3-B32E-D0C27EAC7D58" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 3 - 42mm", + "udid" : "2F5B3F90-3279-4542-A08E-0A10578DBDE7" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-2-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "631E3AFD-DDB4-406A-A668-556D4FEDF07C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "6E2F9E53-7659-476A-9C14-5E48C428BC36" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-10-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "40EDC654-D61C-4B8D-B277-95D67D543DD3" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-3-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "240C26E6-FE33-41A3-8EF0-7858DA2F53B6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "C5366104-3578-4E59-9212-F2B3138D7A9E" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "06636736-4EE6-4CBF-9D5F-436CF2260448" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "DA3753BB-0B7D-4745-9530-9F2A08356A75" + } + ], + "iOS 11.0" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 5s", + "udid" : "0A66E373-5A8D-4C43-9E67-DF88CAE6263C" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6", + "udid" : "739D456A-A219-411E-8F11-409B5B9C76E7" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6 Plus", + "udid" : "2F84EC3D-ED0E-4D8A-9902-1F3FC1A9851A" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6s", + "udid" : "08973AB7-9BDB-4BC0-9DF1-CA8D01B59E03" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6s Plus", + "udid" : "912DA237-CB50-4DC9-AF8E-3371C55CC39D" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 7", + "udid" : "551A4179-C45E-44BF-82CD-235D410ECAC3" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 7 (Detox)", + "udid" : "E3F13477-6650-45D7-A1F2-A46AC8CA7221" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 7 (Detox2)", + "udid" : "EF229C34-34B8-47E8-92A1-0722BB056338" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 7 (Detox3)", + "udid" : "722DC993-CF3E-4F02-99DC-C942E24D45E9" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 7 Plus", + "udid" : "07F56D62-25E9-4119-95CE-69E87350D1D4" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 7 Plus (Detox)", + "udid" : "4A23F40C-34B8-42CD-A81D-AB10ABB60C58" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone SE", + "udid" : "095EBCAC-5BF3-4B1E-83BD-483B9AEA25AE" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 8", + "udid" : "A84142C2-3E25-49C2-AFA3-EF7046AB55D6" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 8 Plus", + "udid" : "E8170B7C-98DC-4EA2-AA76-DF41CC546634" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 8 Plus-temp", + "udid" : "79AA5C43-6C65-43BF-9FDB-48AC834853B2" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone X", + "udid" : "D53474CF-7DD1-4673-8517-E75DAD6C34D6" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Air", + "udid" : "9FB9BBB8-A04E-4FEA-83A4-769243D3047A" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Air 2", + "udid" : "9DEBD82B-4F4D-4FBF-8612-44440C2F1130" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad (5th generation)", + "udid" : "EEC5C875-1E7F-430D-BE85-AB77C713C7CC" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Pro (9.7-inch)", + "udid" : "054F9054-251E-4748-98A9-247F95CFE324" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Pro (12.9-inch)", + "udid" : "49AD50FC-8201-43F3-8AFB-03A80B9910D4" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "udid" : "BA18412F-5BB4-40B6-8C0C-D49E88343632" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Pro (10.5-inch)", + "udid" : "A8E67E06-D791-46E8-835D-9EA26900166A" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-9-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "3727084D-1D11-4D5F-B1C9-AE12D9EA25D0" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-10-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "601A6052-401B-4D5F-9969-D1B252BFB63A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "AC2800F6-6B9F-4952-BDAD-28A0F43B621C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "5FE03940-89F3-4DED-B924-9DD0630C5D3B" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "4E51342E-1F41-45ED-A6EA-6313FDED9E27" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "D39174C7-0DCB-4881-BD1C-18A7C82B1DC4" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "BE906158-376A-4733-A6ED-65E2B79B2351" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "A3C93900-6D17-4830-8FBE-E102E4BBCBB9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7 Plus", + "udid" : "AE64887B-7B6F-439E-8039-99D43FD1FD8C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone SE", + "udid" : "109BD1B5-21D0-491C-998D-98EC6F2E6AD3" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Retina", + "udid" : "555728C2-B1FF-410B-B096-83EC1F491BE2" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "21A8B777-4B51-4A7B-9788-1A0E39727614" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air - 2", + "udid" : "0A607DDB-9785-430E-8561-2E0B4B367E0E" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "95F63516-E360-49CF-B576-FB93EEFE0A1F" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (9.7 inch)", + "udid" : "B3E96CEE-622A-4B36-8D19-5FB3165155CB" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9 inch)", + "udid" : "FACC38D5-1F64-4081-9078-378C4B51C582" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-10-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "69E9738A-271D-409E-AAF8-F843C2C9CB3B" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "6CA27F3D-0F40-4BDF-81F7-D5799181F1F7" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "CB66B6DD-393A-436A-A52D-9D22A332CC65" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "F2A4AE49-FC71-43F2-B9C4-2BF0398549A7" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "2828C5F5-540F-470C-A17D-82A3E401E855" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "6249369E-BBE7-4A27-B1AC-B079209C74EC" + }, + { + "state" : "Creating", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "9C9ABE4D-70C7-49DC-A396-3CB1D0E82846" + }, + { + "state" : "Creating", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7 Plus", + "udid" : "8C2A47A6-A415-4A5F-8372-4FF4CA232BD8" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone SE", + "udid" : "39CDBD89-A8CB-42E9-B4EB-E28E2958E4C9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Retina", + "udid" : "9C029A8A-7096-4CA1-94DD-EA8F720C5FD9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "D1CE0B39-B724-438B-935D-97C915817B19" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "193D0394-2580-44DC-8A04-F5823FB039CC" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (9.7 inch)", + "udid" : "518D94EB-75B2-453D-A141-7A1E1F49F382" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9 inch)", + "udid" : "058A009B-4348-4281-8B9C-B5C0CE06EFF8" + } + ] }, - { - "buildversion" : "15S100", - "availability" : "(available)", - "name" : "watchOS 4.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.watchOS-4-2", - "version" : "4.2" + "pairs" : { + "997DB5F5-8B56-4DE6-A753-B56E8719FA18" : { + "watch" : { + "name" : "Apple Watch - 42mm", + "udid" : "B288646D-8B92-4799-A5F8-55ACF7EAB4FC", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s Plus", + "udid" : "08E4145F-5AE4-4BD2-8937-169F7793E6E2", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "D5FF253C-4716-4335-81E5-5205D108DD90" : { + "watch" : { + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "70FB6CDE-A5CB-4995-9CCB-9288E93C7308", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7 Plus", + "udid" : "07F56D62-25E9-4119-95CE-69E87350D1D4", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + }, + "43CCD05A-9B61-42BF-8609-83CEFF47C683" : { + "watch" : { + "name" : "Apple Watch Series 3 - 38mm", + "udid" : "F080A29E-2615-46D3-B32E-D0C27EAC7D58", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 8", + "udid" : "A84142C2-3E25-49C2-AFA3-EF7046AB55D6", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + }, + "5B8FD9F2-1A06-403A-9B70-588D3ECA304E" : { + "watch" : { + "name" : "Apple Watch - 38mm", + "udid" : "631E3AFD-DDB4-406A-A668-556D4FEDF07C", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s", + "udid" : "291E8BFF-2576-43A1-9B14-AF07937BED6A", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "77ADF31D-FFBC-4415-B5F7-CB1C17B822F2" : { + "watch" : { + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "6812D5A9-2931-467F-A349-7F46953B0F32", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7", + "udid" : "551A4179-C45E-44BF-82CD-235D410ECAC3", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + }, + "83D9FFEA-D9E0-4A24-A65C-3B3DE9ECBD34" : { + "watch" : { + "name" : "Apple Watch - 38mm", + "udid" : "65216D2D-8329-4720-B7B7-56DE1DA223DE", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s", + "udid" : "6609FFB6-08C8-4195-ADBE-D1EDC4004ECF", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "B6D42DDC-5779-401D-BA30-6BECB6CCAF95" : { + "watch" : { + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "1089EFA6-E851-42DD-B88F-945193DBC47C", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7 Plus", + "udid" : "D12A1E7C-3E50-4168-8731-AE8DFB702C6C", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "BDB6FE82-D93B-4979-9559-C570C176FBF0" : { + "watch" : { + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "DA3753BB-0B7D-4745-9530-9F2A08356A75", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7 Plus", + "udid" : "AE64887B-7B6F-439E-8039-99D43FD1FD8C", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "395AFC29-C727-404F-ACBA-6D81A7D499EC" : { + "watch" : { + "name" : "Apple Watch Series 3 - 42mm", + "udid" : "2F5B3F90-3279-4542-A08E-0A10578DBDE7", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 8 Plus", + "udid" : "E8170B7C-98DC-4EA2-AA76-DF41CC546634", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + }, + "AF4B7649-054B-40A6-A5BC-F2A0915863A3" : { + "watch" : { + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "06636736-4EE6-4CBF-9D5F-436CF2260448", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7", + "udid" : "A3C93900-6D17-4830-8FBE-E102E4BBCBB9", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "21CC02B2-F853-40BE-96D1-B9607EBFDE31" : { + "watch" : { + "name" : "Apple Watch - 42mm", + "udid" : "6E2F9E53-7659-476A-9C14-5E48C428BC36", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s Plus", + "udid" : "FA4ACAFA-8CA1-4EF0-B594-6A856C006B51", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "A5DC73DC-7CFB-4B28-8EC4-F403BDDA3E73" : { + "watch" : { + "name" : "Apple Watch - 38mm", + "udid" : "98631D9A-A2B3-4752-8A3E-92E990BAE106", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s", + "udid" : "08973AB7-9BDB-4BC0-9DF1-CA8D01B59E03", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + }, + "796D06AE-3671-4D9B-A241-B694DE1623F4" : { + "watch" : { + "name" : "Apple Watch - 42mm", + "udid" : "79E7E680-0D9F-40A2-9EE4-2F7EB351A094", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s Plus", + "udid" : "912DA237-CB50-4DC9-AF8E-3371C55CC39D", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + }, + "0CFC50E9-BABF-47C0-8668-BAA97E8CCB83" : { + "watch" : { + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "C41A6B35-7FBD-4A25-BC59-A11DD490E543", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7", + "udid" : "1187FB7A-61B9-4892-B812-4E97C950C1A9", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + } } - ] - }; + } + ; - it('calls xcrun to get a list of runtimes', async () => { - exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: JSON.stringify(runtimes)})); + it('calls xcrun to get a list of runtimes/devicetypes/devices', async () => { + exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: JSON.stringify(simctlList)})); - const created = await uut.create('name'); + const created = await uut.create('iPhone 8 Plus'); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(2); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith( - `/usr/bin/xcrun simctl list runtimes -j`, + `/usr/bin/xcrun simctl list -j`, undefined, expect.anything(), 1); @@ -315,22 +1285,22 @@ describe('AppleSimUtils', () => { it('errors when there is no runtime available', async () => { exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: "{}"})); try { - await uut.create('name1'); + await uut.create('iPhone 7 Plus'); fail(`should throw`); } catch (e) { - expect(`${e}`).toEqual('Error: Unable to create device. No runtime found for name1'); + expect(`${e}`).toEqual('Error: Unable to create device. No runtime found for iPhone 7 Plus'); } }); - it('creates using the newest runtime version', async () => { - exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: JSON.stringify(runtimes)})); + xit('creates using the newest runtime version', async () => { + exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: JSON.stringify(simctlList)})); - const created = await uut.create('iPhone 8 Plus'); + const created = await uut.create('iPhone 7 Plus'); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith( - `/usr/bin/xcrun simctl create "iPhone 8 Plus" "iPhone 8 Plus" "com.apple.CoreSimulator.SimRuntime.iOS-11-2"`, + `/usr/bin/xcrun simctl create "iPhone 7 Plus" "iPhone 7 Plus" "com.apple.CoreSimulator.SimRuntime.iOS-11-3`, undefined, expect.anything(), 1); diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 7a47c15980..72eee8908f 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -47,7 +47,6 @@ class DeviceRegistry { static clear() { writeLockedDevices([]); } - } function createEmptyLockFileIfNeeded() { @@ -76,4 +75,3 @@ function getFirstUnlocked(deviceIds) { } module.exports = DeviceRegistry; - diff --git a/detox/test/e2e/29.crash-handling.test.js b/detox/test/e2e/19.crash-handling.test.js similarity index 100% rename from detox/test/e2e/29.crash-handling.test.js rename to detox/test/e2e/19.crash-handling.test.js From 5dd5d276e3888e188268e6f64eecda593da556a8 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Mon, 7 May 2018 15:58:27 +0300 Subject: [PATCH 35/73] WIP --- detox/local-cli/detox-test.js | 4 +- detox/src/devices/AppleSimUtils.js | 35 ++++++++------- detox/src/devices/DeviceRegistry.js | 53 +++++++++++------------ detox/src/devices/DeviceRegistry.test.js | 18 ++++---- detox/src/devices/SimulatorDriver.js | 3 +- detox/src/index.js | 3 ++ detox/src/utils/environment.js | 3 +- detox/test/e2e/08.stress-root.test.js | 3 -- detox/test/e2e/09.stress-timeouts.test.js | 3 -- detox/test/e2e/14.network.test.js | 4 +- detox/test/package.json | 2 +- 11 files changed, 64 insertions(+), 67 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 12d12b3f7d..ba800c4c5c 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -111,11 +111,11 @@ function runMocha() { function runJest() { const currentConfiguration = config.configurations && config.configurations[program.configuration]; - const maxTestWorkers = currentConfiguration.maxTestWorkers || 1; + const maxWorkers = currentConfiguration.maxWorkers || 1; const configFile = runnerConfig ? `--config=${runnerConfig}` : ''; const platform = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(program.platform)}).)*$'` : ''; - const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxTestWorkers} ${platform}`; + const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxWorkers} ${platform}`; const env = Object.assign({}, process.env, { configuration: program.configuration, loglevel: program.loglevel, diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index e0a6815a1a..25330ef108 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -1,3 +1,4 @@ +const process = require('process'); const _ = require('lodash'); const exec = require('../utils/exec'); const retry = require('../utils/retry'); @@ -29,7 +30,7 @@ class AppleSimUtils { trying: `Searching for device matching ${query}...` }; let correctQuery = this._correctQueryWithOS(query); - const response = await this._execAppleSimUtils({ args: `--list "${correctQuery}"` }, statusLogs, 1); + const response = await this._execAppleSimUtils({ args: `--list --byType "${correctQuery}"` }, statusLogs, 1); const parsed = this._parseResponseFromAppleSimUtils(response); const udids = _.map(parsed, 'udid'); if (!udids || !udids.length || !udids[0]) { @@ -61,17 +62,6 @@ class AppleSimUtils { } async create(name) { - - const IPHONES = { - "iPhone 8": "iPhone2017-A", - "iPhone 8 Plus": "iPhone2017-B", - "iPhone X": "iPhone2017-C" - }; - - if (IPHONES[name]) { - name = IPHONES[name]; - } - const result = await this._execSimctl({ cmd: `list -j` }); const stdout = _.get(result, 'stdout'); const output = JSON.parse(stdout); @@ -79,9 +69,10 @@ class AppleSimUtils { const newestRuntime = _.maxBy(output.runtimes, r => Number(r.version)); if (newestRuntime) { - //console.log(`create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`); - await this._execSimctl({cmd: `create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`}); - return true; + console.log(process.pid, `create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`); + const result = await this._execSimctl({cmd: `create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`}); + const udid = _.get(result, 'stdout').trim(); + return udid; } else { throw new Error(`Unable to create device. No runtime found for ${name}`); } @@ -194,6 +185,20 @@ class AppleSimUtils { return correctQuery; } + //convertXcode9(name) { + // const IPHONES = { + // "iPhone 8": "iPhone2017-A", + // "iPhone 8 Plus": "iPhone2017-B", + // "iPhone X": "iPhone2017-C" + // }; + // + // if (IPHONES[name]) { + // return IPHONES[name]; + // } else { + // return name; + // } + //} + _parseResponseFromAppleSimUtils(response) { let out = _.get(response, 'stdout'); if (_.isEmpty(out)) { diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 72eee8908f..675af23aed 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -3,49 +3,46 @@ const plockfile = require('proper-lockfile'); const _ = require('lodash'); const retry = require('../utils/retry'); const {DEVICE_LOCK_FILE_PATH} = require('../utils/environment'); -const LOCK_RETRY_OPTIONS = {retries: Number.MAX_SAFE_INTEGER, interval: 5}; +const LOCK_RETRY_OPTIONS = {retries: 100, interval: 5}; class DeviceRegistry { - constructor({getDeviceIdsByType, maxTestRunners = 1, createDevice}) { + constructor({getDeviceIdsByType, createDevice}) { this.getDeviceIdsByType = getDeviceIdsByType; - this.maxTestRunners = maxTestRunners; this.createDevice = createDevice; createEmptyLockFileIfNeeded(); } - async getDevice(deviceType) { - await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(DEVICE_LOCK_FILE_PATH)); - const deviceIds = await this.getDeviceIdsByType(deviceType); - await this._createDeviceIfNecessary({deviceIds, deviceType}); + async lock() { + await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(DEVICE_LOCK_FILE_PATH)); + } - const unlockedDeviceId = getFirstUnlocked(deviceIds); - if (unlockedDeviceId) { - const lockedDevices = getLockedDevices(); - lockedDevices.push(unlockedDeviceId); - writeLockedDevices(lockedDevices); - plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); - return unlockedDeviceId; - } - plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); - throw new Error(`Unable to find unlocked device ${deviceType}`); + async unlock() { + await plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); } - static async freeDevice(deviceId) { - await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(DEVICE_LOCK_FILE_PATH)); + async freeDevice(deviceId) { + await this.lock(); const lockedDevices = getLockedDevices(); _.remove(lockedDevices, lockedDeviceId => lockedDeviceId === deviceId); writeLockedDevices(lockedDevices); - plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); + await this.unlock(); } - async _createDeviceIfNecessary ({deviceIds, deviceType}) { - const numberOfDevicesNeededToCreate = Math.max(this.maxTestRunners - deviceIds.length, 0); - _.times(numberOfDevicesNeededToCreate, async () => await this.createDevice(deviceType)); - } + async getDevice(deviceType) { + await this.lock(); + const deviceIds = await this.getDeviceIdsByType(deviceType); - static clear() { - writeLockedDevices([]); + let deviceId = getFirstUnlocked(deviceIds); + if (!deviceId) { + deviceId = await this.createDevice(deviceType); + } + + const lockedDevices = getLockedDevices(); + lockedDevices.push(deviceId); + writeLockedDevices(lockedDevices); + await this.unlock(); + return deviceId; } } @@ -66,9 +63,11 @@ function getLockedDevices() { } function getFirstUnlocked(deviceIds) { - for (let i=0; i < deviceIds.length; i++) { + console.log(`getFirstUnlocked ${deviceIds}`); + for (let i = 0; i < deviceIds.length; i++) { let deviceId = deviceIds[i]; if (!getLockedDevices().includes(deviceId)) { + console.log(`getFirstUnlocked return ${deviceId}`); return deviceId; } } diff --git a/detox/src/devices/DeviceRegistry.test.js b/detox/src/devices/DeviceRegistry.test.js index 0baad04a0c..e3b000b595 100644 --- a/detox/src/devices/DeviceRegistry.test.js +++ b/detox/src/devices/DeviceRegistry.test.js @@ -5,10 +5,10 @@ describe('device registry', () => { let registry; const createDevice = jest.fn(); - function initRegistry({maxTestRunners = 1, numberOfDevicesPerType = 1} = {}) { + function initRegistry({numberOfDevicesPerType = 1} = {}) { const devicesIds = Array.from(Array(numberOfDevicesPerType).keys()); const getDeviceIdsByType = type => devicesIds.map(deviceId => `id-${deviceId}-of-type-${type}`); - return new DeviceRegistry({getDeviceIdsByType, maxTestRunners, createDevice}); + return new DeviceRegistry({getDeviceIdsByType, createDevice}); } describe('create device', () => { @@ -16,22 +16,20 @@ describe('device registry', () => { beforeEach(DeviceRegistry.clear); it('should create devices if they are not available', async () => { - const maxTestRunners = 4; const numberOfDevicesPerType = 1; - registry = initRegistry({maxTestRunners, numberOfDevicesPerType}); - await registry.getDevice('iPhoneX'); + registry = initRegistry({numberOfDevicesPerType}); + await registry.getDevice('iPhone X'); - expect(createDevice).toHaveBeenCalledTimes(maxTestRunners - numberOfDevicesPerType); - expect(createDevice).toHaveBeenCalledWith('iPhoneX'); + expect(createDevice).toHaveBeenCalledTimes(numberOfDevicesPerType); + expect(createDevice).toHaveBeenCalledWith('iPhone X'); }); it('should not create devices if there is no need', async () => { - const maxTestRunners = 1; const numberOfDevicesPerType = 1; - registry = initRegistry({numberOfDevicesPerType, maxTestRunners}); + registry = initRegistry({numberOfDevicesPerType}); try { - await registry.getDevice('iPhoneX'); + await registry.getDevice('iPhone X'); } catch (e) { } diff --git a/detox/src/devices/SimulatorDriver.js b/detox/src/devices/SimulatorDriver.js index 1a452f1a3f..a0e4130375 100644 --- a/detox/src/devices/SimulatorDriver.js +++ b/detox/src/devices/SimulatorDriver.js @@ -14,7 +14,6 @@ class SimulatorDriver extends IosDriver { super(client); this._applesimutils = new AppleSimUtils(); this.deviceRegistry = new DeviceRegistry({ - maxTestRunners: global.process.env.maxTestWorkers, getDeviceIdsByType: async type => await this._applesimutils.findDevicesUDID(type), createDevice: type => this._applesimutils.create(type), }); @@ -30,7 +29,7 @@ class SimulatorDriver extends IosDriver { } async cleanup(deviceId, bundleId) { - await DeviceRegistry.freeDevice(deviceId); + await this.deviceRegistry.freeDevice(deviceId); return super.cleanup(deviceId, bundleId); } diff --git a/detox/src/index.js b/detox/src/index.js index 814659bb45..4859b73e02 100644 --- a/detox/src/index.js +++ b/detox/src/index.js @@ -78,3 +78,6 @@ module.exports = Object.assign({ afterEach, DetoxConstants }, exportWrapper); + + +process.on('unhandledRejection', up => { throw up }) \ No newline at end of file diff --git a/detox/src/utils/environment.js b/detox/src/utils/environment.js index a93f891ed3..1d851c6665 100644 --- a/detox/src/utils/environment.js +++ b/detox/src/utils/environment.js @@ -2,8 +2,7 @@ const os = require('os'); const path = require('path'); const exec = require('child-process-promise').exec; const DETOX_LIBRARY_ROOT_PATH = `${os.homedir()}/Library/Detox`; -const DETOX_ROOT_PATH = os.homedir(); -const DEVICE_LOCK_FILE_PATH = path.join(DETOX_ROOT_PATH, 'device.registry.state.lock'); +const DEVICE_LOCK_FILE_PATH = path.join(DETOX_LIBRARY_ROOT_PATH, 'device.registry.state.lock'); function getAndroidSDKPath() { let sdkPath = process.env.ANDROID_SDK_ROOT || process.env.ANDROID_HOME; diff --git a/detox/test/e2e/08.stress-root.test.js b/detox/test/e2e/08.stress-root.test.js index e1b2ebb712..8e5113922c 100644 --- a/detox/test/e2e/08.stress-root.test.js +++ b/detox/test/e2e/08.stress-root.test.js @@ -1,9 +1,6 @@ describe('StressRoot', () => { beforeEach(async () => { await device.relaunchApp(); - }); - - beforeEach(async () => { await element(by.text('Switch Root')).tap(); }); diff --git a/detox/test/e2e/09.stress-timeouts.test.js b/detox/test/e2e/09.stress-timeouts.test.js index b7c8b54ffe..1bdff2ef8b 100644 --- a/detox/test/e2e/09.stress-timeouts.test.js +++ b/detox/test/e2e/09.stress-timeouts.test.js @@ -1,9 +1,6 @@ describe('StressTimeouts', () => { beforeEach(async () => { await device.reloadReactNative(); - }); - - beforeEach(async () => { await element(by.text('Timeouts')).tap(); }); diff --git a/detox/test/e2e/14.network.test.js b/detox/test/e2e/14.network.test.js index 556b7b8ab5..3b336c43a9 100644 --- a/detox/test/e2e/14.network.test.js +++ b/detox/test/e2e/14.network.test.js @@ -3,11 +3,11 @@ const MockServer = require('../mock-server/mock-server'); describe('Network Synchronization', () => { let mockServer = new MockServer(); - beforeAll(async () => { + beforeAll(() => { mockServer.init(); }); - afterAll( () => { + afterAll(() => { mockServer.close(); }); diff --git a/detox/test/package.json b/detox/test/package.json index b83679d036..7d3d0a1412 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -49,7 +49,7 @@ "build": "set -o pipefail && export CODE_SIGNING_REQUIRED=NO && export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -project ios/example.xcodeproj -scheme example_ci -configuration Release -sdk iphonesimulator -derivedDataPath ios/build | xcpretty", "type": "ios.simulator", "name": "iPhone 8 Plus", - "maxTestWorkers": 3 + "maxWorkers": 3 }, "ios.none": { "binaryPath": "ios", From 56f208d9407e3b16f25a4c11439537b5991fb08e Mon Sep 17 00:00:00 2001 From: Rotem M Date: Tue, 8 May 2018 16:59:21 +0300 Subject: [PATCH 36/73] WIP --- detox/src/devices/AppleSimUtils.js | 1 - detox/src/devices/AppleSimUtils.test.js | 1017 +--------------- detox/src/devices/DeviceRegistry.js | 96 +- detox/src/devices/DeviceRegistry.test.js | 120 +- detox/src/devices/android/ADB.test.js | 3 +- detox/src/devices/xcrunSimctlList.mock.json | 1213 +++++++++++++++++++ detox/src/index.js | 3 - detox/src/utils/environment.js | 8 +- detox/wallaby.js | 1 + 9 files changed, 1317 insertions(+), 1145 deletions(-) create mode 100644 detox/src/devices/xcrunSimctlList.mock.json diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 25330ef108..0c1180ca32 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -69,7 +69,6 @@ class AppleSimUtils { const newestRuntime = _.maxBy(output.runtimes, r => Number(r.version)); if (newestRuntime) { - console.log(process.pid, `create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`); const result = await this._execSimctl({cmd: `create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`}); const udid = _.get(result, 'stdout').trim(); return udid; diff --git a/detox/src/devices/AppleSimUtils.test.js b/detox/src/devices/AppleSimUtils.test.js index 597ce20f0c..2d4525196a 100644 --- a/detox/src/devices/AppleSimUtils.test.js +++ b/detox/src/devices/AppleSimUtils.test.js @@ -78,7 +78,7 @@ describe('AppleSimUtils', () => { } catch (e) { } expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(1); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith('applesimutils', { - args: `--list "iPhone 6"` + args: `--list --byType "iPhone 6"` }, expect.anything(), 1, undefined); }); @@ -87,7 +87,7 @@ describe('AppleSimUtils', () => { await uut.findDeviceUDID('iPhone 6 , iOS 10.3'); } catch (e) { } expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith('applesimutils', { - args: `--list "iPhone 6, OS=iOS 10.3"` + args: `--list --byType "iPhone 6, OS=iOS 10.3"` }, expect.anything(), 1, undefined); }); @@ -262,1018 +262,11 @@ describe('AppleSimUtils', () => { describe('create', () => { - const simctlList = { - "devicetypes" : [ - { - "name" : "iPhone 4s", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-4s" - }, - { - "name" : "iPhone 5", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-5" - }, - { - "name" : "iPhone 5s", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-5s" - }, - { - "name" : "iPhone 6", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6" - }, - { - "name" : "iPhone 6 Plus", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus" - }, - { - "name" : "iPhone 6s", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6s" - }, - { - "name" : "iPhone 6s Plus", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus" - }, - { - "name" : "iPhone 7", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-7" - }, - { - "name" : "iPhone 7 Plus", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus" - }, - { - "name" : "iPhone SE", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-SE" - }, - { - "name" : "iPhone2017-A", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8" - }, - { - "name" : "iPhone2017-B", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus" - }, - { - "name" : "iPhone2017-C", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-X" - }, - { - "name" : "iPad 2", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-2" - }, - { - "name" : "iPad Retina", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Retina" - }, - { - "name" : "iPad Air", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Air" - }, - { - "name" : "iPad Air 2", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2" - }, - { - "name" : "iPad (5th generation)", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad--5th-generation-" - }, - { - "name" : "iPad Pro (9.7-inch)", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-" - }, - { - "name" : "iPad Pro (12.9-inch)", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro" - }, - { - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---2nd-generation-" - }, - { - "name" : "iPad Pro (10.5-inch)", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--10-5-inch-" - }, - { - "name" : "Apple TV", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p" - }, - { - "name" : "Apple TV 4K", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-4K" - }, - { - "name" : "Apple TV 4K (at 1080p)", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-1080p" - }, - { - "name" : "Apple Watch - 38mm", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm" - }, - { - "name" : "Apple Watch - 42mm", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm" - }, - { - "name" : "Apple Watch Series 2 - 38mm", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-38mm" - }, - { - "name" : "Apple Watch Series 2 - 42mm", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-42mm" - }, - { - "name" : "Watch2017 - 38mm", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-3-38mm" - }, - { - "name" : "Watch2017 - 42mm", - "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-3-42mm" - } - ], - "runtimes" : [ - { - "buildversion" : "13C75", - "availability" : "(available)", - "name" : "iOS 9.2", - "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-2", - "version" : "9.2" - }, - { - "buildversion" : "15A372", - "availability" : "(available)", - "name" : "iOS 11.0", - "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-11-0", - "version" : "11.0" - }, - { - "buildversion" : "15J380", - "availability" : "(available)", - "name" : "tvOS 11.0", - "identifier" : "com.apple.CoreSimulator.SimRuntime.tvOS-11-0", - "version" : "11.0" - }, - { - "buildversion" : "15R372", - "availability" : "(available)", - "name" : "watchOS 4.0", - "identifier" : "com.apple.CoreSimulator.SimRuntime.watchOS-4-0", - "version" : "4.0" - } - ], - "devices" : { - "com.apple.CoreSimulator.SimRuntime.iOS-10-3" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5", - "udid" : "D4D2213B-1A98-4EBD-8E03-F52B4E739B45" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5s", - "udid" : "F069D970-41D1-44C6-A1B1-8C0E3A10D5A0" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6", - "udid" : "15DD6668-072D-444E-BD56-C143665F6CD6" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6 Plus", - "udid" : "908DC74E-FA0B-48FE-AD88-6FBBCB017250" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s", - "udid" : "6609FFB6-08C8-4195-ADBE-D1EDC4004ECF" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s Plus", - "udid" : "08E4145F-5AE4-4BD2-8937-169F7793E6E2" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7", - "udid" : "1187FB7A-61B9-4892-B812-4E97C950C1A9" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7 Plus", - "udid" : "D12A1E7C-3E50-4168-8731-AE8DFB702C6C" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone SE", - "udid" : "ABDC82BE-A1AA-4AC3-AC63-20C3200CA868" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air", - "udid" : "36E04E65-EDC4-4199-9B8D-F5F20D907BE9" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air 2", - "udid" : "9B5CEB84-A78B-471D-BCDF-A5406A2C78B9" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad (5th generation)", - "udid" : "EE27F2B8-4ECA-48D5-9AAA-5B6B71E4B47A" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (9.7 inch)", - "udid" : "DF67BCEB-1E98-4862-8E29-4262E45C36DD" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (12.9 inch)", - "udid" : "464C614E-0B52-459E-81F8-5D48E6726A01" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "4243CB58-55C7-4668-8F75-868B6FC1E411" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (10.5-inch)", - "udid" : "FA595536-1EFD-412E-8FC8-4E9945CF59A1" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-9-2" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "86C23AE7-E9E0-4358-91EB-DEA118CF5B4C" - } - ], - "com.apple.CoreSimulator.SimRuntime.watchOS-3-2" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 38mm", - "udid" : "65216D2D-8329-4720-B7B7-56DE1DA223DE" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 42mm", - "udid" : "B288646D-8B92-4799-A5F8-55ACF7EAB4FC" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "C41A6B35-7FBD-4A25-BC59-A11DD490E543" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "1089EFA6-E851-42DD-B88F-945193DBC47C" - } - ], - "iOS 9.2" : [ - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 6s Plus", - "udid" : "9E22FA5C-1225-4BB0-9883-03AA139BA731" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-10-0" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "9EC2F2E1-3FCC-4635-BC69-7558AB64E2B8" - } - ], - "tvOS 11.0" : [ - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple TV 1080p", - "udid" : "4F521FFA-99FF-4815-B1FE-0B19AC2A740D" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple TV 4K", - "udid" : "C0A6390F-C364-4922-AE22-C983A46409A3" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple TV 4K (at 1080p)", - "udid" : "8C1B1F1E-5FED-449F-A918-6C0E808EAA3D" - } - ], - "com.apple.CoreSimulator.SimRuntime.iOS-9-3" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 4s", - "udid" : "A0C05A53-04A7-4D19-BEC9-5BF961483DD9" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5", - "udid" : "6AEBE78B-E6B3-443B-8B8F-D91F8E766A23" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5s", - "udid" : "F2132AC3-CECF-4EAF-9763-58CE584A1C94" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6", - "udid" : "A26635FD-0DCA-4679-9934-19AA7DEC59DB" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6 Plus", - "udid" : "03743681-7CA5-47C2-B4F8-CF8D03272FB6" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s", - "udid" : "291E8BFF-2576-43A1-9B14-AF07937BED6A" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s Plus", - "udid" : "FA4ACAFA-8CA1-4EF0-B594-6A856C006B51" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad 2", - "udid" : "FEF98A7E-0630-4C4C-83C1-1FB7F2129D83" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Retina", - "udid" : "FBCD1D2D-B9AC-4201-B850-BB6363CA2D7C" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air", - "udid" : "85D3A5F6-E982-4751-8C2F-3FB68A6ED2E4" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air 2", - "udid" : "CAE43B00-1766-4804-8D4B-99A48B8D7858" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro", - "udid" : "880C4E47-C6DC-45F8-BDF6-8B167561C274" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-10-1" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "95A9A35D-9C9D-4360-A266-1AB1D5D0A8CA" - } - ], - "watchOS 4.0" : [ - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple Watch - 38mm", - "udid" : "98631D9A-A2B3-4752-8A3E-92E990BAE106" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple Watch - 42mm", - "udid" : "79E7E680-0D9F-40A2-9EE4-2F7EB351A094" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "6812D5A9-2931-467F-A349-7F46953B0F32" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "70FB6CDE-A5CB-4995-9CCB-9288E93C7308" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "F080A29E-2615-46D3-B32E-D0C27EAC7D58" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "2F5B3F90-3279-4542-A08E-0A10578DBDE7" - } - ], - "com.apple.CoreSimulator.SimRuntime.watchOS-2-2" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 38mm", - "udid" : "631E3AFD-DDB4-406A-A668-556D4FEDF07C" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 42mm", - "udid" : "6E2F9E53-7659-476A-9C14-5E48C428BC36" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-10-2" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "40EDC654-D61C-4B8D-B277-95D67D543DD3" - } - ], - "com.apple.CoreSimulator.SimRuntime.watchOS-3-1" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 38mm", - "udid" : "240C26E6-FE33-41A3-8EF0-7858DA2F53B6" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 42mm", - "udid" : "C5366104-3578-4E59-9212-F2B3138D7A9E" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "06636736-4EE6-4CBF-9D5F-436CF2260448" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "DA3753BB-0B7D-4745-9530-9F2A08356A75" - } - ], - "iOS 11.0" : [ - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 5s", - "udid" : "0A66E373-5A8D-4C43-9E67-DF88CAE6263C" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 6", - "udid" : "739D456A-A219-411E-8F11-409B5B9C76E7" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 6 Plus", - "udid" : "2F84EC3D-ED0E-4D8A-9902-1F3FC1A9851A" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 6s", - "udid" : "08973AB7-9BDB-4BC0-9DF1-CA8D01B59E03" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 6s Plus", - "udid" : "912DA237-CB50-4DC9-AF8E-3371C55CC39D" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 7", - "udid" : "551A4179-C45E-44BF-82CD-235D410ECAC3" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 7 (Detox)", - "udid" : "E3F13477-6650-45D7-A1F2-A46AC8CA7221" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 7 (Detox2)", - "udid" : "EF229C34-34B8-47E8-92A1-0722BB056338" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 7 (Detox3)", - "udid" : "722DC993-CF3E-4F02-99DC-C942E24D45E9" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 7 Plus", - "udid" : "07F56D62-25E9-4119-95CE-69E87350D1D4" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 7 Plus (Detox)", - "udid" : "4A23F40C-34B8-42CD-A81D-AB10ABB60C58" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone SE", - "udid" : "095EBCAC-5BF3-4B1E-83BD-483B9AEA25AE" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 8", - "udid" : "A84142C2-3E25-49C2-AFA3-EF7046AB55D6" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 8 Plus", - "udid" : "E8170B7C-98DC-4EA2-AA76-DF41CC546634" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 8 Plus-temp", - "udid" : "79AA5C43-6C65-43BF-9FDB-48AC834853B2" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone X", - "udid" : "D53474CF-7DD1-4673-8517-E75DAD6C34D6" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPad Air", - "udid" : "9FB9BBB8-A04E-4FEA-83A4-769243D3047A" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPad Air 2", - "udid" : "9DEBD82B-4F4D-4FBF-8612-44440C2F1130" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPad (5th generation)", - "udid" : "EEC5C875-1E7F-430D-BE85-AB77C713C7CC" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPad Pro (9.7-inch)", - "udid" : "054F9054-251E-4748-98A9-247F95CFE324" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPad Pro (12.9-inch)", - "udid" : "49AD50FC-8201-43F3-8AFB-03A80B9910D4" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "BA18412F-5BB4-40B6-8C0C-D49E88343632" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPad Pro (10.5-inch)", - "udid" : "A8E67E06-D791-46E8-835D-9EA26900166A" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-9-1" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "3727084D-1D11-4D5F-B1C9-AE12D9EA25D0" - } - ], - "com.apple.CoreSimulator.SimRuntime.iOS-10-2" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5", - "udid" : "601A6052-401B-4D5F-9969-D1B252BFB63A" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5s", - "udid" : "AC2800F6-6B9F-4952-BDAD-28A0F43B621C" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6", - "udid" : "5FE03940-89F3-4DED-B924-9DD0630C5D3B" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6 Plus", - "udid" : "4E51342E-1F41-45ED-A6EA-6313FDED9E27" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s", - "udid" : "D39174C7-0DCB-4881-BD1C-18A7C82B1DC4" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s Plus", - "udid" : "BE906158-376A-4733-A6ED-65E2B79B2351" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7", - "udid" : "A3C93900-6D17-4830-8FBE-E102E4BBCBB9" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7 Plus", - "udid" : "AE64887B-7B6F-439E-8039-99D43FD1FD8C" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone SE", - "udid" : "109BD1B5-21D0-491C-998D-98EC6F2E6AD3" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Retina", - "udid" : "555728C2-B1FF-410B-B096-83EC1F491BE2" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air", - "udid" : "21A8B777-4B51-4A7B-9788-1A0E39727614" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air - 2", - "udid" : "0A607DDB-9785-430E-8561-2E0B4B367E0E" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air 2", - "udid" : "95F63516-E360-49CF-B576-FB93EEFE0A1F" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (9.7 inch)", - "udid" : "B3E96CEE-622A-4B36-8D19-5FB3165155CB" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (12.9 inch)", - "udid" : "FACC38D5-1F64-4081-9078-378C4B51C582" - } - ], - "com.apple.CoreSimulator.SimRuntime.iOS-10-1" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5", - "udid" : "69E9738A-271D-409E-AAF8-F843C2C9CB3B" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5s", - "udid" : "6CA27F3D-0F40-4BDF-81F7-D5799181F1F7" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6", - "udid" : "CB66B6DD-393A-436A-A52D-9D22A332CC65" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6 Plus", - "udid" : "F2A4AE49-FC71-43F2-B9C4-2BF0398549A7" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s", - "udid" : "2828C5F5-540F-470C-A17D-82A3E401E855" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s Plus", - "udid" : "6249369E-BBE7-4A27-B1AC-B079209C74EC" - }, - { - "state" : "Creating", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7", - "udid" : "9C9ABE4D-70C7-49DC-A396-3CB1D0E82846" - }, - { - "state" : "Creating", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7 Plus", - "udid" : "8C2A47A6-A415-4A5F-8372-4FF4CA232BD8" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone SE", - "udid" : "39CDBD89-A8CB-42E9-B4EB-E28E2958E4C9" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Retina", - "udid" : "9C029A8A-7096-4CA1-94DD-EA8F720C5FD9" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air", - "udid" : "D1CE0B39-B724-438B-935D-97C915817B19" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air 2", - "udid" : "193D0394-2580-44DC-8A04-F5823FB039CC" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (9.7 inch)", - "udid" : "518D94EB-75B2-453D-A141-7A1E1F49F382" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (12.9 inch)", - "udid" : "058A009B-4348-4281-8B9C-B5C0CE06EFF8" - } - ] - }, - "pairs" : { - "997DB5F5-8B56-4DE6-A753-B56E8719FA18" : { - "watch" : { - "name" : "Apple Watch - 42mm", - "udid" : "B288646D-8B92-4799-A5F8-55ACF7EAB4FC", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 6s Plus", - "udid" : "08E4145F-5AE4-4BD2-8937-169F7793E6E2", - "state" : "Shutdown" - }, - "state" : "(unavailable)" - }, - "D5FF253C-4716-4335-81E5-5205D108DD90" : { - "watch" : { - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "70FB6CDE-A5CB-4995-9CCB-9288E93C7308", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 7 Plus", - "udid" : "07F56D62-25E9-4119-95CE-69E87350D1D4", - "state" : "Shutdown" - }, - "state" : "(active, disconnected)" - }, - "43CCD05A-9B61-42BF-8609-83CEFF47C683" : { - "watch" : { - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "F080A29E-2615-46D3-B32E-D0C27EAC7D58", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 8", - "udid" : "A84142C2-3E25-49C2-AFA3-EF7046AB55D6", - "state" : "Shutdown" - }, - "state" : "(active, disconnected)" - }, - "5B8FD9F2-1A06-403A-9B70-588D3ECA304E" : { - "watch" : { - "name" : "Apple Watch - 38mm", - "udid" : "631E3AFD-DDB4-406A-A668-556D4FEDF07C", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 6s", - "udid" : "291E8BFF-2576-43A1-9B14-AF07937BED6A", - "state" : "Shutdown" - }, - "state" : "(unavailable)" - }, - "77ADF31D-FFBC-4415-B5F7-CB1C17B822F2" : { - "watch" : { - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "6812D5A9-2931-467F-A349-7F46953B0F32", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 7", - "udid" : "551A4179-C45E-44BF-82CD-235D410ECAC3", - "state" : "Shutdown" - }, - "state" : "(active, disconnected)" - }, - "83D9FFEA-D9E0-4A24-A65C-3B3DE9ECBD34" : { - "watch" : { - "name" : "Apple Watch - 38mm", - "udid" : "65216D2D-8329-4720-B7B7-56DE1DA223DE", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 6s", - "udid" : "6609FFB6-08C8-4195-ADBE-D1EDC4004ECF", - "state" : "Shutdown" - }, - "state" : "(unavailable)" - }, - "B6D42DDC-5779-401D-BA30-6BECB6CCAF95" : { - "watch" : { - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "1089EFA6-E851-42DD-B88F-945193DBC47C", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 7 Plus", - "udid" : "D12A1E7C-3E50-4168-8731-AE8DFB702C6C", - "state" : "Shutdown" - }, - "state" : "(unavailable)" - }, - "BDB6FE82-D93B-4979-9559-C570C176FBF0" : { - "watch" : { - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "DA3753BB-0B7D-4745-9530-9F2A08356A75", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 7 Plus", - "udid" : "AE64887B-7B6F-439E-8039-99D43FD1FD8C", - "state" : "Shutdown" - }, - "state" : "(unavailable)" - }, - "395AFC29-C727-404F-ACBA-6D81A7D499EC" : { - "watch" : { - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "2F5B3F90-3279-4542-A08E-0A10578DBDE7", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 8 Plus", - "udid" : "E8170B7C-98DC-4EA2-AA76-DF41CC546634", - "state" : "Shutdown" - }, - "state" : "(active, disconnected)" - }, - "AF4B7649-054B-40A6-A5BC-F2A0915863A3" : { - "watch" : { - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "06636736-4EE6-4CBF-9D5F-436CF2260448", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 7", - "udid" : "A3C93900-6D17-4830-8FBE-E102E4BBCBB9", - "state" : "Shutdown" - }, - "state" : "(unavailable)" - }, - "21CC02B2-F853-40BE-96D1-B9607EBFDE31" : { - "watch" : { - "name" : "Apple Watch - 42mm", - "udid" : "6E2F9E53-7659-476A-9C14-5E48C428BC36", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 6s Plus", - "udid" : "FA4ACAFA-8CA1-4EF0-B594-6A856C006B51", - "state" : "Shutdown" - }, - "state" : "(unavailable)" - }, - "A5DC73DC-7CFB-4B28-8EC4-F403BDDA3E73" : { - "watch" : { - "name" : "Apple Watch - 38mm", - "udid" : "98631D9A-A2B3-4752-8A3E-92E990BAE106", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 6s", - "udid" : "08973AB7-9BDB-4BC0-9DF1-CA8D01B59E03", - "state" : "Shutdown" - }, - "state" : "(active, disconnected)" - }, - "796D06AE-3671-4D9B-A241-B694DE1623F4" : { - "watch" : { - "name" : "Apple Watch - 42mm", - "udid" : "79E7E680-0D9F-40A2-9EE4-2F7EB351A094", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 6s Plus", - "udid" : "912DA237-CB50-4DC9-AF8E-3371C55CC39D", - "state" : "Shutdown" - }, - "state" : "(active, disconnected)" - }, - "0CFC50E9-BABF-47C0-8668-BAA97E8CCB83" : { - "watch" : { - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "C41A6B35-7FBD-4A25-BC59-A11DD490E543", - "state" : "Shutdown" - }, - "phone" : { - "name" : "iPhone 7", - "udid" : "1187FB7A-61B9-4892-B812-4E97C950C1A9", - "state" : "Shutdown" - }, - "state" : "(unavailable)" - } - } - } - ; - it('calls xcrun to get a list of runtimes/devicetypes/devices', async () => { - exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({stdout: JSON.stringify(simctlList)})); + const simctlList = require('./xcrunSimctlList.mock.json'); + exec.execWithRetriesAndLogs.mockReturnValue(Promise.resolve({stdout: JSON.stringify(simctlList)})); - const created = await uut.create('iPhone 8 Plus'); + const created = await uut.create('iPhone X'); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(2); expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith( `/usr/bin/xcrun simctl list -j`, diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 675af23aed..2dc0170045 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -1,8 +1,11 @@ const fs = require('fs'); +const path = require('path'); const plockfile = require('proper-lockfile'); const _ = require('lodash'); const retry = require('../utils/retry'); -const {DEVICE_LOCK_FILE_PATH} = require('../utils/environment'); +const environment = require('../utils/environment'); +const DEVICE_LOCK_FILE_PATH = path.join(environment.getDetoxLibraryRootPath(), 'device.registry.state.lock'); + const LOCK_RETRY_OPTIONS = {retries: 100, interval: 5}; class DeviceRegistry { @@ -10,65 +13,76 @@ class DeviceRegistry { constructor({getDeviceIdsByType, createDevice}) { this.getDeviceIdsByType = getDeviceIdsByType; this.createDevice = createDevice; - createEmptyLockFileIfNeeded(); - } - - async lock() { - await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(DEVICE_LOCK_FILE_PATH)); - } - - async unlock() { - await plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); + this._createEmptyLockFileIfNeeded(); } async freeDevice(deviceId) { - await this.lock(); - const lockedDevices = getLockedDevices(); + await this._lock(); + const lockedDevices = this._getBusyDevices(); _.remove(lockedDevices, lockedDeviceId => lockedDeviceId === deviceId); - writeLockedDevices(lockedDevices); - await this.unlock(); + this._writeBusyDevicesToLockFile(lockedDevices); + await this._unlock(); } async getDevice(deviceType) { - await this.lock(); - const deviceIds = await this.getDeviceIdsByType(deviceType); + await this._lock(); - let deviceId = getFirstUnlocked(deviceIds); + let deviceId = await this._getFreeDevice(deviceType); if (!deviceId) { deviceId = await this.createDevice(deviceType); } - const lockedDevices = getLockedDevices(); - lockedDevices.push(deviceId); - writeLockedDevices(lockedDevices); - await this.unlock(); + const busyDevices = this._getBusyDevices(); + busyDevices.push(deviceId); + this._writeBusyDevicesToLockFile(busyDevices); + await this._unlock(); return deviceId; } -} -function createEmptyLockFileIfNeeded() { - if (!fs.existsSync(DEVICE_LOCK_FILE_PATH)) { - writeLockedDevices([]); + async _lock() { + await retry(LOCK_RETRY_OPTIONS, () => plockfile.lockSync(DEVICE_LOCK_FILE_PATH)); } -} -function writeLockedDevices(lockedDevices) { - fs.writeFileSync(DEVICE_LOCK_FILE_PATH, JSON.stringify(lockedDevices)); -} + async _unlock() { + await plockfile.unlockSync(DEVICE_LOCK_FILE_PATH); + } -function getLockedDevices() { - createEmptyLockFileIfNeeded(); - const lockFileContent = fs.readFileSync(DEVICE_LOCK_FILE_PATH, 'utf-8'); - return JSON.parse(lockFileContent); -} + clear() { + this._writeBusyDevicesToLockFile([]); + } + + async isBusy(deviceId) { + await this._lock(); + const isBusy = this._getBusyDevices().includes(deviceId); + + await this._unlock(); + return isBusy; + } + + _createEmptyLockFileIfNeeded() { + if (!fs.existsSync(DEVICE_LOCK_FILE_PATH)) { + this._writeBusyDevicesToLockFile([]); + } + } + + _writeBusyDevicesToLockFile(lockedDevices) { + fs.writeFileSync(DEVICE_LOCK_FILE_PATH, JSON.stringify(lockedDevices)); + } + + _getBusyDevices() { + this._createEmptyLockFileIfNeeded(); + const lockFileContent = fs.readFileSync(DEVICE_LOCK_FILE_PATH, 'utf-8'); + return JSON.parse(lockFileContent); + } + + async _getFreeDevice(deviceType) { + const deviceIds = await this.getDeviceIdsByType(deviceType); -function getFirstUnlocked(deviceIds) { - console.log(`getFirstUnlocked ${deviceIds}`); - for (let i = 0; i < deviceIds.length; i++) { - let deviceId = deviceIds[i]; - if (!getLockedDevices().includes(deviceId)) { - console.log(`getFirstUnlocked return ${deviceId}`); - return deviceId; + for (let i = 0; i < deviceIds.length; i++) { + let deviceId = deviceIds[i]; + if (!this._getBusyDevices().includes(deviceId)) { + return deviceId; + } } } } diff --git a/detox/src/devices/DeviceRegistry.test.js b/detox/src/devices/DeviceRegistry.test.js index e3b000b595..aad3778a61 100644 --- a/detox/src/devices/DeviceRegistry.test.js +++ b/detox/src/devices/DeviceRegistry.test.js @@ -1,110 +1,62 @@ const DeviceRegistry = require('./DeviceRegistry'); -describe('device registry', () => { - +describe('DeviceRegistry', () => { let registry; - const createDevice = jest.fn(); + let createDevice = jest.fn(); + let getDeviceIdsByType = jest.fn(); - function initRegistry({numberOfDevicesPerType = 1} = {}) { - const devicesIds = Array.from(Array(numberOfDevicesPerType).keys()); - const getDeviceIdsByType = type => devicesIds.map(deviceId => `id-${deviceId}-of-type-${type}`); - return new DeviceRegistry({getDeviceIdsByType, createDevice}); + function mockDeviceList(type, length) { + const devicesIds = Array.from(Array(length).keys()); + return devicesIds.map(deviceId => `id-${deviceId}-of-type-${type}`); } - describe('create device', () => { + beforeEach(() => { + createDevice = jest.fn(); + getDeviceIdsByType = jest.fn(); + registry = new DeviceRegistry({getDeviceIdsByType, createDevice}); + registry.clear(); + }); - beforeEach(DeviceRegistry.clear); + describe(`create device`, () => { - it('should create devices if they are not available', async () => { - const numberOfDevicesPerType = 1; + it(`should create device if there's no device available`, async () => { + getDeviceIdsByType.mockReturnValue([]); - registry = initRegistry({numberOfDevicesPerType}); await registry.getDevice('iPhone X'); - expect(createDevice).toHaveBeenCalledTimes(numberOfDevicesPerType); + expect(createDevice).toHaveBeenCalledTimes(1); expect(createDevice).toHaveBeenCalledWith('iPhone X'); }); - it('should not create devices if there is no need', async () => { - const numberOfDevicesPerType = 1; - registry = initRegistry({numberOfDevicesPerType}); - try { - await registry.getDevice('iPhone X'); - } - catch (e) { - } - - expect(createDevice).not.toHaveBeenCalled(); - }); - - }); - - - describe('free device', () => { + it(`should not create device if there's no device available`, async () => { + getDeviceIdsByType.mockReturnValue(mockDeviceList('iPhone X', 1)); - beforeEach(DeviceRegistry.clear); - - it('should free device', async () => { - registry = initRegistry({}); - await registry.getDevice('iPhoneX'); - - expect(await tryGetDevice('iPhoneX')).toEqual(undefined); - - await DeviceRegistry.freeDevice('id-0-of-type-iPhoneX'); + await registry.getDevice('iPhone X'); - expect(await registry.getDevice('iPhoneX')).toEqual('id-0-of-type-iPhoneX'); + expect(createDevice).toHaveBeenCalledTimes(0); }); - }); - - it('should return a device id for a given type', async () => { - registry = initRegistry(); - DeviceRegistry.clear(); + it(`should create device if all available devices are busy`, async () => { + getDeviceIdsByType.mockReturnValue(mockDeviceList('iPhone X', 1)); - const ret = await registry.getDevice('iPhoneX'); - - expect(ret).toEqual('id-0-of-type-iPhoneX'); - }); - - it('should return a device id for a given type when the registry contains multiple ids', async () => { - registry = initRegistry({numberOfDevicesPerType: 2}); - DeviceRegistry.clear(); - const ret = await registry.getDevice('iPhoneX'); - - expect(ret).toEqual('id-0-of-type-iPhoneX'); - }); - - it('should not return a device id for a given type if the device is locked', async () => { - registry = initRegistry(); - await tryGetDevice('iPhoneX'); - const ret = await tryGetDevice('iPhoneX'); + await registry.getDevice('iPhone X'); + await registry.getDevice('iPhone X'); - expect(ret).toEqual(undefined); + expect(createDevice).toHaveBeenCalledTimes(1); + }); }); - it('should not return a device id for a given type if the device is locked in a different registry', async () => { - registry = initRegistry(); - const registry2 = initRegistry(); - try { - await registry2.getDevice('iPhoneX'); - } - catch (e) { - // ignore - } + describe('free device', () => { + it('should free device', async () => { + const deviceList = mockDeviceList('iPhone X', 1); + const deviceId = deviceList[0]; + getDeviceIdsByType.mockReturnValue(deviceList); - const ret = await tryGetDevice('iPhoneX'); + await registry.getDevice('iPhoneX'); + expect(await registry.isBusy(deviceId)).toBe(true); - expect(ret).toEqual(undefined); + await registry.freeDevice(deviceId); + expect(await registry.isBusy(deviceId)).toBe(false); + }); }); - - const tryGetDevice = async name => { - try { - await registry.getDevice(name); - } - catch (e) { - // ignore - } - } - - }); \ No newline at end of file diff --git a/detox/src/devices/android/ADB.test.js b/detox/src/devices/android/ADB.test.js index 5f5dd9e83d..43ee992ee0 100644 --- a/detox/src/devices/android/ADB.test.js +++ b/detox/src/devices/android/ADB.test.js @@ -10,8 +10,6 @@ describe('ADB', () => { getAndroidSDKPath: () => '/dev/null', })); - ADB = require('./ADB'); - jest.mock('./EmulatorTelnet'); EmulatorTelnet = require('./EmulatorTelnet'); @@ -23,6 +21,7 @@ describe('ADB', () => { }); exec = require('../../utils/exec').execWithRetriesAndLogs; + ADB = require('./ADB'); adb = new ADB(); }); diff --git a/detox/src/devices/xcrunSimctlList.mock.json b/detox/src/devices/xcrunSimctlList.mock.json new file mode 100644 index 0000000000..b04dd3d45f --- /dev/null +++ b/detox/src/devices/xcrunSimctlList.mock.json @@ -0,0 +1,1213 @@ +{ + "devicetypes" : [ + { + "name" : "iPhone 4s", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-4s" + }, + { + "name" : "iPhone 5", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-5" + }, + { + "name" : "iPhone 5s", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-5s" + }, + { + "name" : "iPhone 6", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6" + }, + { + "name" : "iPhone 6 Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus" + }, + { + "name" : "iPhone 6s", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6s" + }, + { + "name" : "iPhone 6s Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus" + }, + { + "name" : "iPhone 7", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-7" + }, + { + "name" : "iPhone 7 Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus" + }, + { + "name" : "iPhone 8", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8" + }, + { + "name" : "iPhone 8 Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus" + }, + { + "name" : "iPhone SE", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-SE" + }, + { + "name" : "iPhone X", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-X" + }, + { + "name" : "iPad 2", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-2" + }, + { + "name" : "iPad Retina", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Retina" + }, + { + "name" : "iPad Air", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Air" + }, + { + "name" : "iPad Air 2", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2" + }, + { + "name" : "iPad (5th generation)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad--5th-generation-" + }, + { + "name" : "iPad Pro (9.7-inch)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-" + }, + { + "name" : "iPad Pro (12.9-inch)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro" + }, + { + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---2nd-generation-" + }, + { + "name" : "iPad Pro (10.5-inch)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--10-5-inch-" + }, + { + "name" : "Apple TV", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p" + }, + { + "name" : "Apple TV 4K", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-4K" + }, + { + "name" : "Apple TV 4K (at 1080p)", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-1080p" + }, + { + "name" : "Apple Watch - 38mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm" + }, + { + "name" : "Apple Watch - 42mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm" + }, + { + "name" : "Apple Watch Series 2 - 38mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-38mm" + }, + { + "name" : "Apple Watch Series 2 - 42mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-42mm" + }, + { + "name" : "Apple Watch Series 3 - 38mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-3-38mm" + }, + { + "name" : "Apple Watch Series 3 - 42mm", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-3-42mm" + } + ], + "runtimes" : [ + { + "buildversion" : "13C75", + "availability" : "(available)", + "name" : "iOS 9.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-2", + "version" : "9.2" + }, + { + "buildversion" : "15E217", + "availability" : "(available)", + "name" : "iOS 11.3", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-11-3", + "version" : "11.3" + }, + { + "buildversion" : "15L211", + "availability" : "(available)", + "name" : "tvOS 11.3", + "identifier" : "com.apple.CoreSimulator.SimRuntime.tvOS-11-3", + "version" : "11.3" + }, + { + "buildversion" : "15T212", + "availability" : "(available)", + "name" : "watchOS 4.3", + "identifier" : "com.apple.CoreSimulator.SimRuntime.watchOS-4-3", + "version" : "4.3" + } + ], + "devices" : { + "com.apple.CoreSimulator.SimRuntime.iOS-10-3" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "D4D2213B-1A98-4EBD-8E03-F52B4E739B45" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "F069D970-41D1-44C6-A1B1-8C0E3A10D5A0" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "15DD6668-072D-444E-BD56-C143665F6CD6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "908DC74E-FA0B-48FE-AD88-6FBBCB017250" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "6609FFB6-08C8-4195-ADBE-D1EDC4004ECF" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "08E4145F-5AE4-4BD2-8937-169F7793E6E2" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "1187FB7A-61B9-4892-B812-4E97C950C1A9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7 Plus", + "udid" : "D12A1E7C-3E50-4168-8731-AE8DFB702C6C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone SE", + "udid" : "ABDC82BE-A1AA-4AC3-AC63-20C3200CA868" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "36E04E65-EDC4-4199-9B8D-F5F20D907BE9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "9B5CEB84-A78B-471D-BCDF-A5406A2C78B9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad (5th generation)", + "udid" : "EE27F2B8-4ECA-48D5-9AAA-5B6B71E4B47A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (9.7 inch)", + "udid" : "DF67BCEB-1E98-4862-8E29-4262E45C36DD" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9 inch)", + "udid" : "464C614E-0B52-459E-81F8-5D48E6726A01" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "udid" : "4243CB58-55C7-4668-8F75-868B6FC1E411" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (10.5-inch)", + "udid" : "FA595536-1EFD-412E-8FC8-4E9945CF59A1" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-9-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "86C23AE7-E9E0-4358-91EB-DEA118CF5B4C" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-3-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "65216D2D-8329-4720-B7B7-56DE1DA223DE" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "B288646D-8B92-4799-A5F8-55ACF7EAB4FC" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "C41A6B35-7FBD-4A25-BC59-A11DD490E543" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "1089EFA6-E851-42DD-B88F-945193DBC47C" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-11-0" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "0A66E373-5A8D-4C43-9E67-DF88CAE6263C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "739D456A-A219-411E-8F11-409B5B9C76E7" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "2F84EC3D-ED0E-4D8A-9902-1F3FC1A9851A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "08973AB7-9BDB-4BC0-9DF1-CA8D01B59E03" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "551A4179-C45E-44BF-82CD-235D410ECAC3" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7 Plus", + "udid" : "07F56D62-25E9-4119-95CE-69E87350D1D4" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 8", + "udid" : "A84142C2-3E25-49C2-AFA3-EF7046AB55D6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 8 Plus", + "udid" : "E8170B7C-98DC-4EA2-AA76-DF41CC546634" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone2017-B-Detox", + "udid" : "F9DF6AB8-C186-4E38-9D56-2BAA3729EC20" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone SE", + "udid" : "095EBCAC-5BF3-4B1E-83BD-483B9AEA25AE" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone X", + "udid" : "D53474CF-7DD1-4673-8517-E75DAD6C34D6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "9FB9BBB8-A04E-4FEA-83A4-769243D3047A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "9DEBD82B-4F4D-4FBF-8612-44440C2F1130" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad (5th generation)", + "udid" : "EEC5C875-1E7F-430D-BE85-AB77C713C7CC" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (9.7-inch)", + "udid" : "054F9054-251E-4748-98A9-247F95CFE324" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9-inch)", + "udid" : "49AD50FC-8201-43F3-8AFB-03A80B9910D4" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "udid" : "BA18412F-5BB4-40B6-8C0C-D49E88343632" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (10.5-inch)", + "udid" : "A8E67E06-D791-46E8-835D-9EA26900166A" + } + ], + "iOS 9.2" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6s Plus", + "udid" : "9E22FA5C-1225-4BB0-9883-03AA139BA731" + } + ], + "iOS 11.3" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 5s", + "udid" : "39B78018-71A0-48B0-8154-A6603D559984" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6", + "udid" : "A50461D5-1FDD-4231-BBE6-FE861646E95B" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6 Plus", + "udid" : "35F6AC74-F66C-4A20-943F-8C9D64BE790E" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6s", + "udid" : "0D16FA74-F551-4113-9F5F-84D452CABF6A" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6s Plus", + "udid" : "2459F12D-2D36-46B2-B947-D9A90B6C6A42" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 7", + "udid" : "10027F45-177A-47EB-AD7E-24103CB75AFF" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 7 Plus", + "udid" : "E32FE642-DD89-482B-BE16-4EBDAD3A6117" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 8", + "udid" : "DDD18C72-F2BC-4DD5-8312-D5E7066C37AB" + }, + { + "state" : "Booted", + "availability" : "(available)", + "name" : "iPhone 8 Plus", + "udid" : "E99A163B-1D42-4F8E-801A-B59B90F09B0C" + }, + { + "state" : "Booted", + "availability" : "(available)", + "name" : "iPhone 8 Plus-Detox", + "udid" : "AC97EE96-7F3E-45CC-87CE-5D07E43B29CD" + }, + { + "state" : "Booted", + "availability" : "(available)", + "name" : "iPhone 8 Plus-Detox", + "udid" : "4FF5B356-615A-4791-A304-A1472F1A033F" + }, + { + "state" : "Booted", + "availability" : "(available)", + "name" : "iPhone 8 Plus-Detox", + "udid" : "17480433-2AAD-4312-9E05-661702120441" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 8 Plus-Detox", + "udid" : "10EDA942-69F5-45F8-B4BB-00BF3CE05D34" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 8 Plus-Detox", + "udid" : "EC6C5F15-DAEC-4D91-A93E-067EE5772504" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone SE", + "udid" : "94DA9917-F76E-4CE9-A53E-88D2F76270E9" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone X", + "udid" : "A48A5681-0859-41C1-A05C-1210FE1CC07B" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Air", + "udid" : "38279B65-D75D-4544-BA09-1AA7D1F8BE7A" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Air 2", + "udid" : "B7DD7F19-AFCE-42AC-96FC-B3414A5A643B" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad (5th generation)", + "udid" : "4CF3B64A-A77F-402C-98A1-008256C57630" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Pro (9.7-inch)", + "udid" : "BCF27E08-E4DF-451F-86FC-0205C0797040" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Pro (12.9-inch)", + "udid" : "2F2DEC15-B92C-4D5E-AECC-E5BD01F694C7" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "udid" : "FAEF24DF-877D-4C65-9754-F3E0D54F5B80" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Pro (10.5-inch)", + "udid" : "A5BFDF79-9AC5-4ABF-91F7-BCEB6E7877FA" + } + ], + "tvOS 11.3" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV", + "udid" : "84CCF063-F06F-409E-A264-F3971CB899AF" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV 4K", + "udid" : "5F5EC33F-55CF-4917-8509-789240BE3598" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV 4K (at 1080p)", + "udid" : "962331E1-1D80-4644-89ED-BFFB46EBE7E3" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-10-0" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "9EC2F2E1-3FCC-4635-BC69-7558AB64E2B8" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-3-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "240C26E6-FE33-41A3-8EF0-7858DA2F53B6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "C5366104-3578-4E59-9212-F2B3138D7A9E" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "06636736-4EE6-4CBF-9D5F-436CF2260448" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "DA3753BB-0B7D-4745-9530-9F2A08356A75" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-9-3" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 4s", + "udid" : "A0C05A53-04A7-4D19-BEC9-5BF961483DD9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "6AEBE78B-E6B3-443B-8B8F-D91F8E766A23" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "F2132AC3-CECF-4EAF-9763-58CE584A1C94" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "A26635FD-0DCA-4679-9934-19AA7DEC59DB" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "03743681-7CA5-47C2-B4F8-CF8D03272FB6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "291E8BFF-2576-43A1-9B14-AF07937BED6A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "FA4ACAFA-8CA1-4EF0-B594-6A856C006B51" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad 2", + "udid" : "FEF98A7E-0630-4C4C-83C1-1FB7F2129D83" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Retina", + "udid" : "FBCD1D2D-B9AC-4201-B850-BB6363CA2D7C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "85D3A5F6-E982-4751-8C2F-3FB68A6ED2E4" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "CAE43B00-1766-4804-8D4B-99A48B8D7858" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro", + "udid" : "880C4E47-C6DC-45F8-BDF6-8B167561C274" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-10-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "95A9A35D-9C9D-4360-A266-1AB1D5D0A8CA" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-11-0" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "4F521FFA-99FF-4815-B1FE-0B19AC2A740D" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 4K", + "udid" : "C0A6390F-C364-4922-AE22-C983A46409A3" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 4K (at 1080p)", + "udid" : "8C1B1F1E-5FED-449F-A918-6C0E808EAA3D" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-2-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "631E3AFD-DDB4-406A-A668-556D4FEDF07C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "6E2F9E53-7659-476A-9C14-5E48C428BC36" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-10-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "40EDC654-D61C-4B8D-B277-95D67D543DD3" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-4-0" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "98631D9A-A2B3-4752-8A3E-92E990BAE106" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "79E7E680-0D9F-40A2-9EE4-2F7EB351A094" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "6812D5A9-2931-467F-A349-7F46953B0F32" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "70FB6CDE-A5CB-4995-9CCB-9288E93C7308" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 3 - 38mm", + "udid" : "F080A29E-2615-46D3-B32E-D0C27EAC7D58" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 3 - 42mm", + "udid" : "2F5B3F90-3279-4542-A08E-0A10578DBDE7" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-10-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "69E9738A-271D-409E-AAF8-F843C2C9CB3B" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "6CA27F3D-0F40-4BDF-81F7-D5799181F1F7" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "CB66B6DD-393A-436A-A52D-9D22A332CC65" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "F2A4AE49-FC71-43F2-B9C4-2BF0398549A7" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "2828C5F5-540F-470C-A17D-82A3E401E855" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "6249369E-BBE7-4A27-B1AC-B079209C74EC" + }, + { + "state" : "Creating", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "9C9ABE4D-70C7-49DC-A396-3CB1D0E82846" + }, + { + "state" : "Creating", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7 Plus", + "udid" : "8C2A47A6-A415-4A5F-8372-4FF4CA232BD8" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone SE", + "udid" : "39CDBD89-A8CB-42E9-B4EB-E28E2958E4C9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Retina", + "udid" : "9C029A8A-7096-4CA1-94DD-EA8F720C5FD9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "D1CE0B39-B724-438B-935D-97C915817B19" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "193D0394-2580-44DC-8A04-F5823FB039CC" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (9.7 inch)", + "udid" : "518D94EB-75B2-453D-A141-7A1E1F49F382" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9 inch)", + "udid" : "058A009B-4348-4281-8B9C-B5C0CE06EFF8" + } + ], + "watchOS 4.3" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch - 38mm", + "udid" : "C6EC2279-A6EB-40BE-99D2-5F11949F25E5" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch - 42mm", + "udid" : "498D4237-8640-43A7-BC80-61F112287C61" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "68B8DF0C-9837-49B9-BDB4-A6C6E34BA6EB" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "84D9A184-FDF3-4666-9B45-765E2DA1867A" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 3 - 38mm", + "udid" : "D08B8137-371E-424C-B067-F659B9CDCFAC" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 3 - 42mm", + "udid" : "3B04A39B-5BAC-4523-B23E-847B20672959" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-10-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "601A6052-401B-4D5F-9969-D1B252BFB63A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "AC2800F6-6B9F-4952-BDAD-28A0F43B621C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "5FE03940-89F3-4DED-B924-9DD0630C5D3B" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "4E51342E-1F41-45ED-A6EA-6313FDED9E27" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "D39174C7-0DCB-4881-BD1C-18A7C82B1DC4" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "BE906158-376A-4733-A6ED-65E2B79B2351" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "A3C93900-6D17-4830-8FBE-E102E4BBCBB9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7 Plus", + "udid" : "AE64887B-7B6F-439E-8039-99D43FD1FD8C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone SE", + "udid" : "109BD1B5-21D0-491C-998D-98EC6F2E6AD3" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Retina", + "udid" : "555728C2-B1FF-410B-B096-83EC1F491BE2" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "21A8B777-4B51-4A7B-9788-1A0E39727614" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air - 2", + "udid" : "0A607DDB-9785-430E-8561-2E0B4B367E0E" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "95F63516-E360-49CF-B576-FB93EEFE0A1F" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (9.7 inch)", + "udid" : "B3E96CEE-622A-4B36-8D19-5FB3165155CB" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9 inch)", + "udid" : "FACC38D5-1F64-4081-9078-378C4B51C582" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-9-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "3727084D-1D11-4D5F-B1C9-AE12D9EA25D0" + } + ] + }, + "pairs" : { + "997DB5F5-8B56-4DE6-A753-B56E8719FA18" : { + "watch" : { + "name" : "Apple Watch - 42mm", + "udid" : "B288646D-8B92-4799-A5F8-55ACF7EAB4FC", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s Plus", + "udid" : "08E4145F-5AE4-4BD2-8937-169F7793E6E2", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "21CC02B2-F853-40BE-96D1-B9607EBFDE31" : { + "watch" : { + "name" : "Apple Watch - 42mm", + "udid" : "6E2F9E53-7659-476A-9C14-5E48C428BC36", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s Plus", + "udid" : "FA4ACAFA-8CA1-4EF0-B594-6A856C006B51", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "A5DC73DC-7CFB-4B28-8EC4-F403BDDA3E73" : { + "watch" : { + "name" : "Apple Watch - 38mm", + "udid" : "98631D9A-A2B3-4752-8A3E-92E990BAE106", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s", + "udid" : "08973AB7-9BDB-4BC0-9DF1-CA8D01B59E03", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "D5FF253C-4716-4335-81E5-5205D108DD90" : { + "watch" : { + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "70FB6CDE-A5CB-4995-9CCB-9288E93C7308", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7 Plus", + "udid" : "07F56D62-25E9-4119-95CE-69E87350D1D4", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "43CCD05A-9B61-42BF-8609-83CEFF47C683" : { + "watch" : { + "name" : "Apple Watch Series 3 - 38mm", + "udid" : "F080A29E-2615-46D3-B32E-D0C27EAC7D58", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 8", + "udid" : "A84142C2-3E25-49C2-AFA3-EF7046AB55D6", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "B6D42DDC-5779-401D-BA30-6BECB6CCAF95" : { + "watch" : { + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "1089EFA6-E851-42DD-B88F-945193DBC47C", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7 Plus", + "udid" : "D12A1E7C-3E50-4168-8731-AE8DFB702C6C", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "B657FA55-A960-4089-84FC-288C093A615B" : { + "watch" : { + "name" : "Apple Watch Series 3 - 42mm", + "udid" : "3B04A39B-5BAC-4523-B23E-847B20672959", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 8 Plus", + "udid" : "E99A163B-1D42-4F8E-801A-B59B90F09B0C", + "state" : "Booted" + }, + "state" : "(active, disconnected)" + }, + "5B8FD9F2-1A06-403A-9B70-588D3ECA304E" : { + "watch" : { + "name" : "Apple Watch - 38mm", + "udid" : "631E3AFD-DDB4-406A-A668-556D4FEDF07C", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s", + "udid" : "291E8BFF-2576-43A1-9B14-AF07937BED6A", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "83D9FFEA-D9E0-4A24-A65C-3B3DE9ECBD34" : { + "watch" : { + "name" : "Apple Watch - 38mm", + "udid" : "65216D2D-8329-4720-B7B7-56DE1DA223DE", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 6s", + "udid" : "6609FFB6-08C8-4195-ADBE-D1EDC4004ECF", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "77ADF31D-FFBC-4415-B5F7-CB1C17B822F2" : { + "watch" : { + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "6812D5A9-2931-467F-A349-7F46953B0F32", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7", + "udid" : "551A4179-C45E-44BF-82CD-235D410ECAC3", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "BDB6FE82-D93B-4979-9559-C570C176FBF0" : { + "watch" : { + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "DA3753BB-0B7D-4745-9530-9F2A08356A75", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7 Plus", + "udid" : "AE64887B-7B6F-439E-8039-99D43FD1FD8C", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "395AFC29-C727-404F-ACBA-6D81A7D499EC" : { + "watch" : { + "name" : "Apple Watch Series 3 - 42mm", + "udid" : "2F5B3F90-3279-4542-A08E-0A10578DBDE7", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 8 Plus", + "udid" : "E8170B7C-98DC-4EA2-AA76-DF41CC546634", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "AF4B7649-054B-40A6-A5BC-F2A0915863A3" : { + "watch" : { + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "06636736-4EE6-4CBF-9D5F-436CF2260448", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7", + "udid" : "A3C93900-6D17-4830-8FBE-E102E4BBCBB9", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "0CFC50E9-BABF-47C0-8668-BAA97E8CCB83" : { + "watch" : { + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "C41A6B35-7FBD-4A25-BC59-A11DD490E543", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7", + "udid" : "1187FB7A-61B9-4892-B812-4E97C950C1A9", + "state" : "Shutdown" + }, + "state" : "(unavailable)" + }, + "5A604D2C-2774-465C-A3B6-0C0BFA8DAF54" : { + "watch" : { + "name" : "Apple Watch Series 3 - 38mm", + "udid" : "D08B8137-371E-424C-B067-F659B9CDCFAC", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 8", + "udid" : "DDD18C72-F2BC-4DD5-8312-D5E7066C37AB", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + }, + "F6A07D71-D43A-42BE-BFBF-CD4C5A224D1C" : { + "watch" : { + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "68B8DF0C-9837-49B9-BDB4-A6C6E34BA6EB", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7", + "udid" : "10027F45-177A-47EB-AD7E-24103CB75AFF", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + }, + "016936FC-0A77-4BD5-950B-951FBD1798A2" : { + "watch" : { + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "84D9A184-FDF3-4666-9B45-765E2DA1867A", + "state" : "Shutdown" + }, + "phone" : { + "name" : "iPhone 7 Plus", + "udid" : "E32FE642-DD89-482B-BE16-4EBDAD3A6117", + "state" : "Shutdown" + }, + "state" : "(active, disconnected)" + } + } +} diff --git a/detox/src/index.js b/detox/src/index.js index 4859b73e02..814659bb45 100644 --- a/detox/src/index.js +++ b/detox/src/index.js @@ -78,6 +78,3 @@ module.exports = Object.assign({ afterEach, DetoxConstants }, exportWrapper); - - -process.on('unhandledRejection', up => { throw up }) \ No newline at end of file diff --git a/detox/src/utils/environment.js b/detox/src/utils/environment.js index 1d851c6665..020c2b49bd 100644 --- a/detox/src/utils/environment.js +++ b/detox/src/utils/environment.js @@ -2,7 +2,7 @@ const os = require('os'); const path = require('path'); const exec = require('child-process-promise').exec; const DETOX_LIBRARY_ROOT_PATH = `${os.homedir()}/Library/Detox`; -const DEVICE_LOCK_FILE_PATH = path.join(DETOX_LIBRARY_ROOT_PATH, 'device.registry.state.lock'); + function getAndroidSDKPath() { let sdkPath = process.env.ANDROID_SDK_ROOT || process.env.ANDROID_HOME; @@ -23,9 +23,13 @@ async function getFrameworkPath() { return `${DETOX_LIBRARY_ROOT_PATH}/ios/${sha1}/Detox.framework`; } +function getDetoxLibraryRootPath() { + return DETOX_LIBRARY_ROOT_PATH; +} + module.exports = { getDetoxVersion, getFrameworkPath, getAndroidSDKPath, - DEVICE_LOCK_FILE_PATH + getDetoxLibraryRootPath }; diff --git a/detox/wallaby.js b/detox/wallaby.js index 23e8645bc8..e307256fc2 100644 --- a/detox/wallaby.js +++ b/detox/wallaby.js @@ -13,6 +13,7 @@ module.exports = function(wallaby) { files: [ 'package.json', 'src/**/*.js', + 'src/**/*.mock.*', '!src/**/*.test.js', ], From c48d49dedab1bcfc6f8b25d38841a7f576d87904 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Tue, 8 May 2018 17:19:50 +0300 Subject: [PATCH 37/73] WIP --- detox/test/package.json | 2 +- scripts/ci.ios.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/detox/test/package.json b/detox/test/package.json index 7d3d0a1412..1cb2af2d47 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -6,7 +6,7 @@ "test": ":", "packager": "react-native start", "detox-server": "detox run-server", - "e2e:ios-multi": "detox test --configuration ios.sim.release-multi --debug-synchronization 10000 --loglevel info", + "e2e:ios-multi": "detox test --configuration ios.sim.release-multi --debug-synchronization 10000", "e2e:ios": "detox test --configuration ios.sim.release --debug-synchronization 10000", "e2e:android": "detox test --configuration android.emu.release --loglevel verbose", diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index 22075eff1c..41e5acffbb 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -6,5 +6,5 @@ run_f "$(dirname "$0")/unit.ios.sh" pushd detox/test run_f "npm run build:ios" -run_f "npm run e2e:ios" +run_f "npm run e2e:ios-multi" popd From 320113cec98cf6807acfb97dcf88b527eee834cc Mon Sep 17 00:00:00 2001 From: Rotem M Date: Tue, 8 May 2018 17:59:51 +0300 Subject: [PATCH 38/73] trigger build --- scripts/ci.ios.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index 41e5acffbb..3fdc8a06f1 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -8,3 +8,4 @@ pushd detox/test run_f "npm run build:ios" run_f "npm run e2e:ios-multi" popd + \ No newline at end of file From ffc4e2084841d4a211392e8ba1b1ce05fcb50477 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 8 May 2018 18:12:26 +0300 Subject: [PATCH 39/73] Trigger build --- scripts/ci.ios.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index 3fdc8a06f1..41e5acffbb 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -8,4 +8,3 @@ pushd detox/test run_f "npm run build:ios" run_f "npm run e2e:ios-multi" popd - \ No newline at end of file From 688a31b08894fd64c6b07bf6bbbcdb3fb647b128 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 8 May 2018 18:26:27 +0300 Subject: [PATCH 40/73] Trigger build From 1f21ca482ce10a0e43642de9c615f033927a225c Mon Sep 17 00:00:00 2001 From: Rotem M Date: Tue, 8 May 2018 18:35:50 +0300 Subject: [PATCH 41/73] waitFor timeout increased --- detox/test/e2e/05.waitfor.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/detox/test/e2e/05.waitfor.test.js b/detox/test/e2e/05.waitfor.test.js index 90fac31b8b..7c474d2754 100644 --- a/detox/test/e2e/05.waitfor.test.js +++ b/detox/test/e2e/05.waitfor.test.js @@ -6,19 +6,19 @@ describe('WaitFor', () => { it('should wait until an element is created and exists in layout', async () => { await expect(element(by.id('createdAndVisibleText'))).toNotExist(); - await waitFor(element(by.id('createdAndVisibleText'))).toExist().withTimeout(2000); + await waitFor(element(by.id('createdAndVisibleText'))).toExist().withTimeout(20000); await expect(element(by.id('createdAndVisibleText'))).toExist(); }); it('should wait until an invisible element becomes visible', async() => { await expect(element(by.id('invisibleBecomingVisibleText'))).toBeNotVisible(); - await waitFor(element(by.id('invisibleBecomingVisibleText'))).toBeVisible().withTimeout(2000); + await waitFor(element(by.id('invisibleBecomingVisibleText'))).toBeVisible().withTimeout(20000); await expect(element(by.id('invisibleBecomingVisibleText'))).toBeVisible(); }); it('should wait until an element is removed', async() => { await expect(element(by.id('deletedFromHierarchyText'))).toBeVisible(); - await waitFor(element(by.id('deletedFromHierarchyText'))).toBeNotVisible().withTimeout(2000); + await waitFor(element(by.id('deletedFromHierarchyText'))).toBeNotVisible().withTimeout(20000); await expect(element(by.id('deletedFromHierarchyText'))).toBeNotVisible(); }); From 0f9007fc04e1045d69c17a6f7e06f530901ddce5 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Tue, 8 May 2018 18:36:18 +0300 Subject: [PATCH 42/73] maxWorkers=2 --- detox/test/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/test/package.json b/detox/test/package.json index 1cb2af2d47..5816b16459 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -49,7 +49,7 @@ "build": "set -o pipefail && export CODE_SIGNING_REQUIRED=NO && export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -project ios/example.xcodeproj -scheme example_ci -configuration Release -sdk iphonesimulator -derivedDataPath ios/build | xcpretty", "type": "ios.simulator", "name": "iPhone 8 Plus", - "maxWorkers": 3 + "maxWorkers": 2 }, "ios.none": { "binaryPath": "ios", From 52d0f8620d9ce9259ff9c1ae5066140e5c45b384 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 8 May 2018 20:59:33 +0300 Subject: [PATCH 43/73] Add line for trigger build --- scripts/ci.ios.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index 41e5acffbb..7afad463b8 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -8,3 +8,4 @@ pushd detox/test run_f "npm run build:ios" run_f "npm run e2e:ios-multi" popd + From 5b11bc9a57302c86fb61df79cb4644f890a9e7a2 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 8 May 2018 21:15:17 +0300 Subject: [PATCH 44/73] Revert "Add line for trigger build" This reverts commit 52d0f8620d9ce9259ff9c1ae5066140e5c45b384. --- scripts/ci.ios.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index 7afad463b8..41e5acffbb 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -8,4 +8,3 @@ pushd detox/test run_f "npm run build:ios" run_f "npm run e2e:ios-multi" popd - From d088827fdc5f2d1bbb837c6c130688be4d48ee9a Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 8 May 2018 21:34:44 +0300 Subject: [PATCH 45/73] last trigger build --- scripts/ci.ios.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index 41e5acffbb..7afad463b8 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -8,3 +8,4 @@ pushd detox/test run_f "npm run build:ios" run_f "npm run e2e:ios-multi" popd + From 8eea0a729c12f6e488a40314e6ca1805da2d949d Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 8 May 2018 22:13:01 +0300 Subject: [PATCH 46/73] Revert "last trigger build" This reverts commit d088827fdc5f2d1bbb837c6c130688be4d48ee9a. --- scripts/ci.ios.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index 7afad463b8..41e5acffbb 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -8,4 +8,3 @@ pushd detox/test run_f "npm run build:ios" run_f "npm run e2e:ios-multi" popd - From cdd18b0087de2b5d4a3f506d0c929c78d4c1024f Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 8 May 2018 22:27:41 +0300 Subject: [PATCH 47/73] Update ci.ios.sh From 920faba03493f9db31ab385ea572755dc7eb5afa Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 8 May 2018 22:39:41 +0300 Subject: [PATCH 48/73] Add line to ci ios --- scripts/ci.ios.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ci.ios.sh b/scripts/ci.ios.sh index 41e5acffbb..7afad463b8 100755 --- a/scripts/ci.ios.sh +++ b/scripts/ci.ios.sh @@ -8,3 +8,4 @@ pushd detox/test run_f "npm run build:ios" run_f "npm run e2e:ios-multi" popd + From 6931a0ec835e453c1be3f03fded664cd34de4bd4 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Wed, 9 May 2018 08:13:48 +0300 Subject: [PATCH 49/73] Fix platfrom for jest --- detox/local-cli/detox-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index ba800c4c5c..921cd2f042 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -114,8 +114,8 @@ function runJest() { const maxWorkers = currentConfiguration.maxWorkers || 1; const configFile = runnerConfig ? `--config=${runnerConfig}` : ''; - const platform = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(program.platform)}).)*$'` : ''; - const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxWorkers} ${platform}`; + const platformString = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(platform)}).)*$'` : ''; + const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxWorkers} ${platformString}`; const env = Object.assign({}, process.env, { configuration: program.configuration, loglevel: program.loglevel, From 7547c99afeb252d85b5072231b35d151980e94ba Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Wed, 9 May 2018 08:40:56 +0300 Subject: [PATCH 50/73] Fix jest invert platform --- detox/local-cli/detox-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 921cd2f042..64171973fb 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -114,7 +114,7 @@ function runJest() { const maxWorkers = currentConfiguration.maxWorkers || 1; const configFile = runnerConfig ? `--config=${runnerConfig}` : ''; - const platformString = program.platform ? `--testNamePattern='^((?!${getPlatformSpecificString(platform)}).)*$'` : ''; + const platformString = platform ? `--testNamePattern='^((?!${getPlatformSpecificString(platform)}).)*$'` : ''; const command = `node_modules/.bin/jest ${testFolder} ${configFile} --maxWorkers=${maxWorkers} ${platformString}`; const env = Object.assign({}, process.env, { configuration: program.configuration, From 0f64ffaaf76428d894ff099996cb780f306814c3 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Wed, 9 May 2018 09:12:42 +0300 Subject: [PATCH 51/73] Trigger build --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 8007e8f595..9c13379f16 100644 --- a/package.json +++ b/package.json @@ -5,3 +5,4 @@ "release": "node scripts/release.js" } } + From 6267fe212b3fd8620e3cb12fe615e8d903e3f8f8 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sat, 12 May 2018 17:04:44 +0300 Subject: [PATCH 52/73] use detox-test to cleanup lockfile --- detox/local-cli/detox-test.js | 5 ++--- detox/src/client/Client.js | 4 +++- detox/src/devices/DeviceRegistry.js | 3 +-- detox/src/utils/environment.js | 11 ++++++++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/detox/local-cli/detox-test.js b/detox/local-cli/detox-test.js index 64171973fb..375c2fca90 100644 --- a/detox/local-cli/detox-test.js +++ b/detox/local-cli/detox-test.js @@ -6,6 +6,7 @@ const cp = require('child_process'); const _ = require('lodash'); const CustomError = require('../src/errors/CustomError'); +const environment = require('../src/utils/environment'); const config = require(path.join(process.cwd(), 'package.json')).detox; class DetoxConfigError extends CustomError {} @@ -162,9 +163,7 @@ function getPlatformSpecificString(platform) { function clearDeviceRegistryLockFile() { const fs = require('fs'); - const os = require('os'); - const LOCK_FILE = path.join(os.homedir(),'device.registry.state.lock'); - fs.writeFileSync(LOCK_FILE, '[]'); + fs.writeFileSync(environment.getDeviceLockFilePath(), '[]'); } function getDefaultConfiguration() { diff --git a/detox/src/client/Client.js b/detox/src/client/Client.js index 426becbd12..e525a17794 100644 --- a/detox/src/client/Client.js +++ b/detox/src/client/Client.js @@ -36,7 +36,9 @@ class Client { async cleanup() { clearTimeout(this.slowInvocationStatusHandler); if (this.isConnected && !this.pandingAppCrash) { - await this.sendAction(new actions.Cleanup(this.successfulTestRun)); + if(this.ws.isOpen()) { + await this.sendAction(new actions.Cleanup(this.successfulTestRun)); + } this.isConnected = false; } diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 2dc0170045..0acbbfe9de 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -1,10 +1,9 @@ const fs = require('fs'); -const path = require('path'); const plockfile = require('proper-lockfile'); const _ = require('lodash'); const retry = require('../utils/retry'); const environment = require('../utils/environment'); -const DEVICE_LOCK_FILE_PATH = path.join(environment.getDetoxLibraryRootPath(), 'device.registry.state.lock'); +const DEVICE_LOCK_FILE_PATH = environment.getDeviceLockFilePath(); const LOCK_RETRY_OPTIONS = {retries: 100, interval: 5}; diff --git a/detox/src/utils/environment.js b/detox/src/utils/environment.js index 020c2b49bd..e7c638ba72 100644 --- a/detox/src/utils/environment.js +++ b/detox/src/utils/environment.js @@ -1,8 +1,8 @@ const os = require('os'); const path = require('path'); const exec = require('child-process-promise').exec; -const DETOX_LIBRARY_ROOT_PATH = `${os.homedir()}/Library/Detox`; - +const DETOX_LIBRARY_ROOT_PATH = path.join(os.homedir(), 'Library', 'Detox'); +const DEVICE_LOCK_FILE_PATH = path.join(DETOX_LIBRARY_ROOT_PATH, 'device.registry.state.lock'); function getAndroidSDKPath() { let sdkPath = process.env.ANDROID_SDK_ROOT || process.env.ANDROID_HOME; @@ -27,9 +27,14 @@ function getDetoxLibraryRootPath() { return DETOX_LIBRARY_ROOT_PATH; } +function getDeviceLockFilePath() { + return DEVICE_LOCK_FILE_PATH; +} + module.exports = { getDetoxVersion, getFrameworkPath, getAndroidSDKPath, - getDetoxLibraryRootPath + getDetoxLibraryRootPath, + getDeviceLockFilePath }; From a4484ddfe4696cb1e61487ed8c522cf7b8640be1 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sat, 12 May 2018 17:05:05 +0300 Subject: [PATCH 53/73] fix waitFor screen, should not be flaky anymore --- detox/test/e2e/05.waitfor.test.js | 13 +++---- detox/test/src/Screens/WaitForScreen.js | 50 ++++++++++--------------- 2 files changed, 24 insertions(+), 39 deletions(-) diff --git a/detox/test/e2e/05.waitfor.test.js b/detox/test/e2e/05.waitfor.test.js index 7c474d2754..d935683a8c 100644 --- a/detox/test/e2e/05.waitfor.test.js +++ b/detox/test/e2e/05.waitfor.test.js @@ -1,4 +1,4 @@ -describe('WaitFor', () => { +describe.only('WaitFor', () => { beforeEach(async() => { await device.reloadReactNative(); await element(by.text('WaitFor')).tap(); @@ -6,25 +6,22 @@ describe('WaitFor', () => { it('should wait until an element is created and exists in layout', async () => { await expect(element(by.id('createdAndVisibleText'))).toNotExist(); + await element(by.id('GoButton')).tap(); await waitFor(element(by.id('createdAndVisibleText'))).toExist().withTimeout(20000); await expect(element(by.id('createdAndVisibleText'))).toExist(); }); - it('should wait until an invisible element becomes visible', async() => { - await expect(element(by.id('invisibleBecomingVisibleText'))).toBeNotVisible(); - await waitFor(element(by.id('invisibleBecomingVisibleText'))).toBeVisible().withTimeout(20000); - await expect(element(by.id('invisibleBecomingVisibleText'))).toBeVisible(); - }); - it('should wait until an element is removed', async() => { await expect(element(by.id('deletedFromHierarchyText'))).toBeVisible(); + await element(by.id('GoButton')).tap(); await waitFor(element(by.id('deletedFromHierarchyText'))).toBeNotVisible().withTimeout(20000); await expect(element(by.id('deletedFromHierarchyText'))).toBeNotVisible(); }); it('should find element by scrolling until it is visible', async() => { await expect(element(by.text('Text5'))).toBeNotVisible(); - await waitFor(element(by.text('Text5'))).toBeVisible().whileElement(by.id('ScrollView630')).scroll(50, 'down'); + await element(by.id('GoButton')).tap(); + await waitFor(element(by.text('Text5'))).toBeVisible().whileElement(by.id('ScrollView')).scroll(50, 'down'); await expect(element(by.text('Text5'))).toBeVisible(); }); diff --git a/detox/test/src/Screens/WaitForScreen.js b/detox/test/src/Screens/WaitForScreen.js index a9c3107611..62b961343e 100644 --- a/detox/test/src/Screens/WaitForScreen.js +++ b/detox/test/src/Screens/WaitForScreen.js @@ -1,43 +1,28 @@ -import React, { Component } from 'react'; +import React, {Component} from 'react'; import { Text, View, ScrollView, Animated, - NativeModules + TouchableOpacity } from 'react-native'; -const NativeModule = NativeModules.NativeModule; - export default class WaitForScreen extends Component { constructor(props) { super(props); this.state = { - greeting: undefined, - showsUp: false, + clicked: false, becomeVisibleLeft: new Animated.Value(-500) }; - NativeModule.nativeSetTimeout(1000, () => { - this.setState({showsUp: true}); - }); - - NativeModule.nativeSetTimeout(500, () => { - Animated.timing(this.state.becomeVisibleLeft, {toValue: 0, duration: 1000}).start(); - }); } render() { - if (this.state.greeting) return this.renderAfterButton(); return ( - {!this.state.showsUp ? false : - I am being created after 1 sec - } - - + Text1 Text2 Text3 @@ -49,24 +34,27 @@ export default class WaitForScreen extends Component { - {this.state.showsUp ? false : - I am being removed after 1 sec + {this.state.clicked ? false : + I am being removed 2 sec after click + } + + {!this.state.clicked ? false : + I am being created 2 sec after click } - I become visible after 1 sec + + Go + ); } - renderAfterButton() { - return ( - - - {this.state.greeting}!!! - - - ); + onGoButtonPress() { + setTimeout(() => { + this.setState({ + clicked: true + }); + }, 2000); } - } From 57a7b38b6c34285f66e144072e220f5fed4879fc Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sat, 12 May 2018 17:27:33 +0300 Subject: [PATCH 54/73] added unit test for a new edge case --- detox/src/client/Client.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/detox/src/client/Client.test.js b/detox/src/client/Client.test.js index 151c2c92c3..560a601ff3 100644 --- a/detox/src/client/Client.test.js +++ b/detox/src/client/Client.test.js @@ -75,6 +75,17 @@ describe('Client', () => { expect(client.ws.send).not.toHaveBeenCalled(); }); + it(`cleanup() - if "connected" but ws is closed should do nothing`, async () => { + await connect(); + client.ws.send.mockReturnValueOnce(response("ready", {}, 1)); + await client.waitUntilReady(); + + client.ws.isOpen.mockReturnValue(false); + await client.cleanup(); + + expect(client.ws.send).toHaveBeenCalledTimes(2); + }); + it(`execute() - "invokeResult" on an invocation object should resolve`, async () => { await connect(); client.ws.send.mockReturnValueOnce(response("invokeResult", {result: "(GREYElementInteraction)"}, 1)); From efb39a65f2da4009422990e7623fde5242cd7281 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sat, 12 May 2018 20:22:57 +0300 Subject: [PATCH 55/73] better visiblity on messages passing on a closed ws --- detox/src/client/AsyncWebSocket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/client/AsyncWebSocket.js b/detox/src/client/AsyncWebSocket.js index 8c76a622cd..e1fa27fdb5 100644 --- a/detox/src/client/AsyncWebSocket.js +++ b/detox/src/client/AsyncWebSocket.js @@ -51,7 +51,7 @@ class AsyncWebSocket { async send(message, messageId) { if (!this.ws) { - throw new Error(`Can't send a message on a closed websocket, init the by calling 'open()'. Message: ${message}`); + throw new Error(`Can't send a message on a closed websocket, init the by calling 'open()'. Message: ${JSON.stringify(message)}`); } return new Promise(async(resolve, reject) => { From a3c9e1e078f15f0671e82cd255d60b8d6e0d6328 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sat, 12 May 2018 21:41:16 +0300 Subject: [PATCH 56/73] WAT --- detox/src/client/AsyncWebSocket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/client/AsyncWebSocket.js b/detox/src/client/AsyncWebSocket.js index e1fa27fdb5..86037dcf96 100644 --- a/detox/src/client/AsyncWebSocket.js +++ b/detox/src/client/AsyncWebSocket.js @@ -51,7 +51,7 @@ class AsyncWebSocket { async send(message, messageId) { if (!this.ws) { - throw new Error(`Can't send a message on a closed websocket, init the by calling 'open()'. Message: ${JSON.stringify(message)}`); + throw new Error(`Can't send a message on a closed websocket, init the by calling 'open()'. Message: ${JSON.stringify(message)}`); } return new Promise(async(resolve, reject) => { From c9c40895b47c2c76fcecd945d02702e091147179 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sat, 12 May 2018 23:20:55 +0300 Subject: [PATCH 57/73] only call currentStatus if ws is open --- detox/src/client/Client.js | 7 +++++-- detox/src/client/Client.test.js | 36 ++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/detox/src/client/Client.js b/detox/src/client/Client.js index e525a17794..d6d15d8b0a 100644 --- a/detox/src/client/Client.js +++ b/detox/src/client/Client.js @@ -104,8 +104,11 @@ class Client { slowInvocationStatus() { return setTimeout(async () => { - const status = await this.currentStatus(); - this.slowInvocationStatusHandler = this.slowInvocationStatus(); + console.log(this.ws.isOpen()) + if (this.ws.isOpen()) { + const status = await this.currentStatus(); + this.slowInvocationStatusHandler = this.slowInvocationStatus(); + } }, this.slowInvocationTimeout); } } diff --git a/detox/src/client/Client.test.js b/detox/src/client/Client.test.js index 560a601ff3..4dd45db8e8 100644 --- a/detox/src/client/Client.test.js +++ b/detox/src/client/Client.test.js @@ -10,10 +10,11 @@ describe('Client', () => { beforeEach(() => { jest.mock('npmlog'); WebSocket = jest.mock('./AsyncWebSocket'); - Client = require('./Client'); jest.mock('../utils/argparse'); argparse = require('../utils/argparse'); + + Client = require('./Client'); }); it(`reloadReactNative() - should receive ready from device and resolve`, async () => { @@ -96,26 +97,29 @@ describe('Client', () => { expect(client.ws.send).toHaveBeenCalledTimes(2); }); - async function executeWithSlowInvocation(invocationTime) { + it(`execute() - fast invocation should not trigger "slowInvocationStatus"`, async () => { argparse.getArgValue.mockReturnValue(2); // set debug-slow-invocations - await connect(); - - client.ws.send.mockReturnValueOnce(timeout(invocationTime).then(()=> response("invokeResult", {result:"(GREYElementInteraction)"}, 1))) - .mockReturnValueOnce(response("currentStatusResult", {"state":"busy","resources":[{"name":"App State","info":{"prettyPrint":"Waiting for network requests to finish.","elements":["__NSCFLocalDataTask:0x7fc95d72b6c0"],"appState":"Waiting for network requests to finish."}},{"name":"Dispatch Queue","info":{"queue":"OS_dispatch_queue_main: com.apple.main-thread[0x10805ea80] = { xrefcnt = 0x80000000, refcnt = 0x80000000, target = com.apple.root.default-qos.overcommit[0x10805f1c0], width = 0x1, state = 0x000fffe000000403, in-flight = 0, thread = 0x403 }","prettyPrint":"com.apple.main-thread"}}]}, 2)); - - const call = invoke.call(invoke.IOS.Class('GREYMatchers'), 'matcherForAccessibilityLabel:', 'test'); - await client.execute(call); - } - - it(`execute() - fast invocation should not trigger "slowInvocationStatus"`, async () => { await executeWithSlowInvocation(1); expect(client.ws.send).toHaveBeenLastCalledWith({"params": {"args": ["test"], "method": "matcherForAccessibilityLabel:", "target": {"type": "Class", "value": "GREYMatchers"}}, "type": "invoke"}, undefined); + expect(client.ws.send).toHaveBeenCalledTimes(2); }); it(`execute() - slow invocation should trigger "slowInvocationStatus:`, async () => { + argparse.getArgValue.mockReturnValue(2); // set debug-slow-invocations + await connect(); await executeWithSlowInvocation(4); expect(client.ws.send).toHaveBeenLastCalledWith({"params": {}, "type": "currentStatus"}, undefined); + expect(client.ws.send).toHaveBeenCalledTimes(3); + }); + + it(`execute() - slow invocation should do nothing if ws was closed`, async () => { + argparse.getArgValue.mockReturnValue(2); // set debug-slow-invocations + await connect(); + client.ws.isOpen.mockReturnValue(false); + await executeWithSlowInvocation(4); + + expect(client.ws.send).toHaveBeenCalledTimes(2); }); it(`execute() - "invokeResult" on an invocation function should resolve`, async () => { @@ -196,6 +200,14 @@ describe('Client', () => { })); } + async function executeWithSlowInvocation(invocationTime) { + client.ws.send.mockReturnValueOnce(timeout(invocationTime).then(()=> response("invokeResult", {result:"(GREYElementInteraction)"}, 1))) + .mockReturnValueOnce(response("currentStatusResult", {"state":"busy","resources":[{"name":"App State","info":{"prettyPrint":"Waiting for network requests to finish.","elements":["__NSCFLocalDataTask:0x7fc95d72b6c0"],"appState":"Waiting for network requests to finish."}},{"name":"Dispatch Queue","info":{"queue":"OS_dispatch_queue_main: com.apple.main-thread[0x10805ea80] = { xrefcnt = 0x80000000, refcnt = 0x80000000, target = com.apple.root.default-qos.overcommit[0x10805f1c0], width = 0x1, state = 0x000fffe000000403, in-flight = 0, thread = 0x403 }","prettyPrint":"com.apple.main-thread"}}]}, 2)); + + const call = invoke.call(invoke.IOS.Class('GREYMatchers'), 'matcherForAccessibilityLabel:', 'test'); + await client.execute(call); + } + async function timeout(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } From 9b51f72afdd9e62d1236704ac97c5e18f8735958 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sat, 12 May 2018 23:55:57 +0300 Subject: [PATCH 58/73] increase verbosity for debug purposes --- detox/src/client/Client.js | 1 - detox/test/package.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/detox/src/client/Client.js b/detox/src/client/Client.js index d6d15d8b0a..eaf6ca0c15 100644 --- a/detox/src/client/Client.js +++ b/detox/src/client/Client.js @@ -104,7 +104,6 @@ class Client { slowInvocationStatus() { return setTimeout(async () => { - console.log(this.ws.isOpen()) if (this.ws.isOpen()) { const status = await this.currentStatus(); this.slowInvocationStatusHandler = this.slowInvocationStatus(); diff --git a/detox/test/package.json b/detox/test/package.json index 5816b16459..910e48db9c 100644 --- a/detox/test/package.json +++ b/detox/test/package.json @@ -6,7 +6,7 @@ "test": ":", "packager": "react-native start", "detox-server": "detox run-server", - "e2e:ios-multi": "detox test --configuration ios.sim.release-multi --debug-synchronization 10000", + "e2e:ios-multi": "detox test --configuration ios.sim.release-multi --debug-synchronization 10000 --loglevel verbose", "e2e:ios": "detox test --configuration ios.sim.release --debug-synchronization 10000", "e2e:android": "detox test --configuration android.emu.release --loglevel verbose", From 3a082bcb1e60af16ffda491ed96c5785bcfdf51d Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sun, 13 May 2018 14:29:18 +0300 Subject: [PATCH 59/73] per platfrom app data path --- detox/package.json | 1 + detox/src/utils/appdatapath.js | 39 ++++++++++++++++++++++++++++++++++ detox/src/utils/environment.js | 5 +++-- 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 detox/src/utils/appdatapath.js diff --git a/detox/package.json b/detox/package.json index 95b194332d..272489a30a 100644 --- a/detox/package.json +++ b/detox/package.json @@ -79,6 +79,7 @@ "debug.js", "src/ios/earlgreyapi", "src/android/espressoapi", + "appdatapath.js", ".test.js", ".mock.js" ], diff --git a/detox/src/utils/appdatapath.js b/detox/src/utils/appdatapath.js new file mode 100644 index 0000000000..cb8e4d57b0 --- /dev/null +++ b/detox/src/utils/appdatapath.js @@ -0,0 +1,39 @@ +const os = require('os'); +const path = require('path'); + +function darwin() { + return path.join(os.homedir(), 'Library'); +} + +function linux() { + if (process.env.XDG_DATA_HOME) { + return path.join(process.env.XDG_DATA_HOME); + } + + return path.join(os.homedir(), '.local', 'share'); +} + +function win32() { + if (process.env.LOCALAPPDATA) { + return path.join(process.env.LOCALAPPDATA, 'data'); + } + + return path.join(process.env.USERPROFILE, 'Application Data'); +} + +function appDataPath() { + switch (os.platform()) { + case 'darwin': + return darwin(); + case 'linux': + return linux(); + case 'win32': + return win32(); + default: + throw new Error(`${os.platform()} is not supported`); + } +} + +module.exports = { + appDataPath +}; diff --git a/detox/src/utils/environment.js b/detox/src/utils/environment.js index e7c638ba72..59bcbe8380 100644 --- a/detox/src/utils/environment.js +++ b/detox/src/utils/environment.js @@ -1,7 +1,8 @@ -const os = require('os'); const path = require('path'); const exec = require('child-process-promise').exec; -const DETOX_LIBRARY_ROOT_PATH = path.join(os.homedir(), 'Library', 'Detox'); +const appdatapath = require('./appdatapath'); + +const DETOX_LIBRARY_ROOT_PATH = path.join(appdatapath.appDataPath(), 'Detox'); const DEVICE_LOCK_FILE_PATH = path.join(DETOX_LIBRARY_ROOT_PATH, 'device.registry.state.lock'); function getAndroidSDKPath() { From d76a43a52f64fff77c9cafc721d904276e22f3b3 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Sun, 13 May 2018 14:45:18 +0300 Subject: [PATCH 60/73] ensure file exists, create including path if needed --- detox/src/devices/DeviceRegistry.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index 0acbbfe9de..ebdb6532b4 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const fs = require('fs-extra'); const plockfile = require('proper-lockfile'); const _ = require('lodash'); const retry = require('../utils/retry'); @@ -60,6 +60,7 @@ class DeviceRegistry { _createEmptyLockFileIfNeeded() { if (!fs.existsSync(DEVICE_LOCK_FILE_PATH)) { + fs.ensureFileSync(DEVICE_LOCK_FILE_PATH); this._writeBusyDevicesToLockFile([]); } } From 3f14a38b30d290d1b431a74f2723e9bd218f7843 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Mon, 14 May 2018 10:36:03 +0300 Subject: [PATCH 61/73] always query applesimutils byOS --- detox/src/devices/AppleSimUtils.js | 49 +- detox/src/devices/AppleSimUtils.test.js | 61 +- detox/src/devices/xcrunSimctlList.mock.json | 833 +++++++++++--------- 3 files changed, 517 insertions(+), 426 deletions(-) diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 0c1180ca32..c0436d301b 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -29,8 +29,20 @@ class AppleSimUtils { const statusLogs = { trying: `Searching for device matching ${query}...` }; - let correctQuery = this._correctQueryWithOS(query); - const response = await this._execAppleSimUtils({ args: `--list --byType "${correctQuery}"` }, statusLogs, 1); + + let type; + let os; + if (_.includes(query, ',')) { + const parts = _.split(query, ','); + type = parts[0].trim(); + os = parts[1].trim(); + } else { + type = query; + const deviceInfo = await this.deviceTypeAndNewestRuntimeFor(query); + os = deviceInfo.newestRuntime.version; + } + + const response = await this._execAppleSimUtils({ args: `--list --byType "${type}" --byOS "${os}"`}, statusLogs, 1); const parsed = this._parseResponseFromAppleSimUtils(response); const udids = _.map(parsed, 'udid'); if (!udids || !udids.length || !udids[0]) { @@ -61,15 +73,19 @@ class AppleSimUtils { return (_.isEqual(device.state, 'Booted') || _.isEqual(device.state, 'Booting')); } - async create(name) { + async deviceTypeAndNewestRuntimeFor(name) { const result = await this._execSimctl({ cmd: `list -j` }); const stdout = _.get(result, 'stdout'); const output = JSON.parse(stdout); const deviceType = _.filter(output.devicetypes, { 'name': name})[0]; const newestRuntime = _.maxBy(output.runtimes, r => Number(r.version)); + return { deviceType, newestRuntime }; + } + async create(name) { + const deviceInfo = await this.deviceTypeAndNewestRuntimeFor(name); - if (newestRuntime) { - const result = await this._execSimctl({cmd: `create "${name}-Detox" "${deviceType.identifier}" "${newestRuntime.identifier}"`}); + if (deviceInfo.newestRuntime) { + const result = await this._execSimctl({cmd: `create "${name}-Detox" "${deviceInfo.deviceType.identifier}" "${deviceInfo.newestRuntime.identifier}"`}); const udid = _.get(result, 'stdout').trim(); return udid; } else { @@ -175,29 +191,6 @@ class AppleSimUtils { return await exec.execWithRetriesAndLogs(`/usr/bin/xcrun simctl ${cmd}`, undefined, statusLogs, retries); } - _correctQueryWithOS(query) { - let correctQuery = query; - if (_.includes(query, ',')) { - const parts = _.split(query, ','); - correctQuery = `${parts[0].trim()}, OS=${parts[1].trim()}`; - } - return correctQuery; - } - - //convertXcode9(name) { - // const IPHONES = { - // "iPhone 8": "iPhone2017-A", - // "iPhone 8 Plus": "iPhone2017-B", - // "iPhone X": "iPhone2017-C" - // }; - // - // if (IPHONES[name]) { - // return IPHONES[name]; - // } else { - // return name; - // } - //} - _parseResponseFromAppleSimUtils(response) { let out = _.get(response, 'stdout'); if (_.isEmpty(out)) { diff --git a/detox/src/devices/AppleSimUtils.test.js b/detox/src/devices/AppleSimUtils.test.js index 2d4525196a..38f774a5a5 100644 --- a/detox/src/devices/AppleSimUtils.test.js +++ b/detox/src/devices/AppleSimUtils.test.js @@ -1,4 +1,5 @@ const _ = require('lodash'); +const simctlList = require('./xcrunSimctlList.mock.json'); describe('AppleSimUtils', () => { let AppleSimUtils; @@ -34,7 +35,10 @@ describe('AppleSimUtils', () => { describe('findDevicesUDID', () => { it('return multiple devices', async () => { - exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({ + exec.execWithRetriesAndLogs + .mockReturnValueOnce(Promise.resolve({ + stdout: JSON.stringify(simctlList)})) + .mockReturnValueOnce(Promise.resolve({ stdout: JSON.stringify([ { "state": "Shutdown", @@ -71,50 +75,46 @@ describe('AppleSimUtils', () => { describe('findDeviceUDID', () => { - it('correct params', async () => { - expect(exec.execWithRetriesAndLogs).not.toHaveBeenCalled(); - try { - await uut.findDeviceUDID('iPhone 6'); - } catch (e) { } - expect(exec.execWithRetriesAndLogs).toHaveBeenCalledTimes(1); - expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith('applesimutils', { - args: `--list --byType "iPhone 6"` - }, expect.anything(), 1, undefined); - }); it('adapted to new api with optional OS', async () => { try { await uut.findDeviceUDID('iPhone 6 , iOS 10.3'); } catch (e) { } expect(exec.execWithRetriesAndLogs).toHaveBeenCalledWith('applesimutils', { - args: `--list --byType "iPhone 6, OS=iOS 10.3"` + args: `--list --byType "iPhone 6" --byOS "iOS 10.3"` }, expect.anything(), 1, undefined); }); it('returns udid from found device', async () => { - exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({ - stdout: JSON.stringify([ - { - "state": "Shutdown", - "availability": "(available)", - "name": "iPhone 6", - "udid": "the uuid", - "os": { - "version": "10.3.1", - "availability": "(available)", - "name": "iOS 10.3", - "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-10-3", - "buildversion": "14E8301" - } - } - ]) - })); + exec.execWithRetriesAndLogs + .mockReturnValueOnce(Promise.resolve({ + stdout: JSON.stringify(simctlList)})) + .mockReturnValueOnce(Promise.resolve({ + stdout: JSON.stringify([ + { + "state": "Shutdown", + "availability": "(available)", + "name": "iPhone 6", + "udid": "the uuid", + "os": { + "version": "10.3.1", + "availability": "(available)", + "name": "iOS 10.3", + "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-10-3", + "buildversion": "14E8301" + } + } + ]) + })); const result = await uut.findDeviceUDID('iPhone 7'); expect(result).toEqual('the uuid'); }); it('handles stderr as if stdout', async () => { - exec.execWithRetriesAndLogs.mockReturnValueOnce(Promise.resolve({ + exec.execWithRetriesAndLogs + .mockReturnValueOnce(Promise.resolve({ + stdout: JSON.stringify(simctlList)})) + .mockReturnValueOnce(Promise.resolve({ stderr: JSON.stringify([ { "state": "Shutdown", @@ -263,7 +263,6 @@ describe('AppleSimUtils', () => { describe('create', () => { it('calls xcrun to get a list of runtimes/devicetypes/devices', async () => { - const simctlList = require('./xcrunSimctlList.mock.json'); exec.execWithRetriesAndLogs.mockReturnValue(Promise.resolve({stdout: JSON.stringify(simctlList)})); const created = await uut.create('iPhone X'); diff --git a/detox/src/devices/xcrunSimctlList.mock.json b/detox/src/devices/xcrunSimctlList.mock.json index b04dd3d45f..f70377f1b4 100644 --- a/detox/src/devices/xcrunSimctlList.mock.json +++ b/detox/src/devices/xcrunSimctlList.mock.json @@ -133,6 +133,13 @@ "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-9-2", "version" : "9.2" }, + { + "buildversion" : "15C107", + "availability" : "(available)", + "name" : "iOS 11.2", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-11-2", + "version" : "11.2" + }, { "buildversion" : "15E217", "availability" : "(available)", @@ -156,6 +163,142 @@ } ], "devices" : { + "watchOS 4.3" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch - 38mm", + "udid" : "C6EC2279-A6EB-40BE-99D2-5F11949F25E5" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch - 42mm", + "udid" : "498D4237-8640-43A7-BC80-61F112287C61" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "68B8DF0C-9837-49B9-BDB4-A6C6E34BA6EB" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "84D9A184-FDF3-4666-9B45-765E2DA1867A" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 3 - 38mm", + "udid" : "D08B8137-371E-424C-B067-F659B9CDCFAC" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple Watch Series 3 - 42mm", + "udid" : "3B04A39B-5BAC-4523-B23E-847B20672959" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-2-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "631E3AFD-DDB4-406A-A668-556D4FEDF07C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "6E2F9E53-7659-476A-9C14-5E48C428BC36" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-3-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "240C26E6-FE33-41A3-8EF0-7858DA2F53B6" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "C5366104-3578-4E59-9212-F2B3138D7A9E" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "06636736-4EE6-4CBF-9D5F-436CF2260448" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "DA3753BB-0B7D-4745-9530-9F2A08356A75" + } + ], + "tvOS 11.3" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV", + "udid" : "84CCF063-F06F-409E-A264-F3971CB899AF" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV 4K", + "udid" : "5F5EC33F-55CF-4917-8509-789240BE3598" + }, + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "Apple TV 4K (at 1080p)", + "udid" : "962331E1-1D80-4644-89ED-BFFB46EBE7E3" + } + ], + "com.apple.CoreSimulator.SimRuntime.watchOS-4-0" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 38mm", + "udid" : "98631D9A-A2B3-4752-8A3E-92E990BAE106" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch - 42mm", + "udid" : "79E7E680-0D9F-40A2-9EE4-2F7EB351A094" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 38mm", + "udid" : "6812D5A9-2931-467F-A349-7F46953B0F32" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 2 - 42mm", + "udid" : "70FB6CDE-A5CB-4995-9CCB-9288E93C7308" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 3 - 38mm", + "udid" : "F080A29E-2615-46D3-B32E-D0C27EAC7D58" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple Watch Series 3 - 42mm", + "udid" : "2F5B3F90-3279-4542-A08E-0A10578DBDE7" + } + ], "com.apple.CoreSimulator.SimRuntime.iOS-10-3" : [ { "state" : "Shutdown", @@ -238,54 +381,198 @@ { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (12.9 inch)", - "udid" : "464C614E-0B52-459E-81F8-5D48E6726A01" + "name" : "iPad Pro (12.9 inch)", + "udid" : "464C614E-0B52-459E-81F8-5D48E6726A01" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "udid" : "4243CB58-55C7-4668-8F75-868B6FC1E411" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (10.5-inch)", + "udid" : "FA595536-1EFD-412E-8FC8-4E9945CF59A1" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-10-2" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "601A6052-401B-4D5F-9969-D1B252BFB63A" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "AC2800F6-6B9F-4952-BDAD-28A0F43B621C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "5FE03940-89F3-4DED-B924-9DD0630C5D3B" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "4E51342E-1F41-45ED-A6EA-6313FDED9E27" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "D39174C7-0DCB-4881-BD1C-18A7C82B1DC4" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "BE906158-376A-4733-A6ED-65E2B79B2351" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "A3C93900-6D17-4830-8FBE-E102E4BBCBB9" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7 Plus", + "udid" : "AE64887B-7B6F-439E-8039-99D43FD1FD8C" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone SE", + "udid" : "109BD1B5-21D0-491C-998D-98EC6F2E6AD3" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Retina", + "udid" : "555728C2-B1FF-410B-B096-83EC1F491BE2" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air", + "udid" : "21A8B777-4B51-4A7B-9788-1A0E39727614" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air - 2", + "udid" : "0A607DDB-9785-430E-8561-2E0B4B367E0E" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Air 2", + "udid" : "95F63516-E360-49CF-B576-FB93EEFE0A1F" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (9.7 inch)", + "udid" : "B3E96CEE-622A-4B36-8D19-5FB3165155CB" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPad Pro (12.9 inch)", + "udid" : "FACC38D5-1F64-4081-9078-378C4B51C582" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-10-1" : [ + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5", + "udid" : "69E9738A-271D-409E-AAF8-F843C2C9CB3B" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 5s", + "udid" : "6CA27F3D-0F40-4BDF-81F7-D5799181F1F7" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6", + "udid" : "CB66B6DD-393A-436A-A52D-9D22A332CC65" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6 Plus", + "udid" : "F2A4AE49-FC71-43F2-B9C4-2BF0398549A7" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s", + "udid" : "2828C5F5-540F-470C-A17D-82A3E401E855" + }, + { + "state" : "Shutdown", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 6s Plus", + "udid" : "6249369E-BBE7-4A27-B1AC-B079209C74EC" + }, + { + "state" : "Creating", + "availability" : " (unavailable, runtime profile not found)", + "name" : "iPhone 7", + "udid" : "9C9ABE4D-70C7-49DC-A396-3CB1D0E82846" }, { - "state" : "Shutdown", + "state" : "Creating", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "4243CB58-55C7-4668-8F75-868B6FC1E411" + "name" : "iPhone 7 Plus", + "udid" : "8C2A47A6-A415-4A5F-8372-4FF4CA232BD8" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (10.5-inch)", - "udid" : "FA595536-1EFD-412E-8FC8-4E9945CF59A1" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-9-2" : [ + "name" : "iPhone SE", + "udid" : "39CDBD89-A8CB-42E9-B4EB-E28E2958E4C9" + }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "86C23AE7-E9E0-4358-91EB-DEA118CF5B4C" - } - ], - "com.apple.CoreSimulator.SimRuntime.watchOS-3-2" : [ + "name" : "iPad Retina", + "udid" : "9C029A8A-7096-4CA1-94DD-EA8F720C5FD9" + }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 38mm", - "udid" : "65216D2D-8329-4720-B7B7-56DE1DA223DE" + "name" : "iPad Air", + "udid" : "D1CE0B39-B724-438B-935D-97C915817B19" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 42mm", - "udid" : "B288646D-8B92-4799-A5F8-55ACF7EAB4FC" + "name" : "iPad Air 2", + "udid" : "193D0394-2580-44DC-8A04-F5823FB039CC" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "C41A6B35-7FBD-4A25-BC59-A11DD490E543" + "name" : "iPad Pro (9.7 inch)", + "udid" : "518D94EB-75B2-453D-A141-7A1E1F49F382" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "1089EFA6-E851-42DD-B88F-945193DBC47C" + "name" : "iPad Pro (12.9 inch)", + "udid" : "058A009B-4348-4281-8B9C-B5C0CE06EFF8" } ], "com.apple.CoreSimulator.SimRuntime.iOS-11-0" : [ @@ -398,322 +685,126 @@ "udid" : "A8E67E06-D791-46E8-835D-9EA26900166A" } ], - "iOS 9.2" : [ - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPhone 6s Plus", - "udid" : "9E22FA5C-1225-4BB0-9883-03AA139BA731" - } - ], - "iOS 11.3" : [ + "iOS 11.2" : [ { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 5s", - "udid" : "39B78018-71A0-48B0-8154-A6603D559984" + "udid" : "AA74BAAB-6253-457D-90F3-294F15299CD6" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 6", - "udid" : "A50461D5-1FDD-4231-BBE6-FE861646E95B" + "udid" : "418B18D4-26EE-46AC-B76D-6574A6DDC4A0" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 6 Plus", - "udid" : "35F6AC74-F66C-4A20-943F-8C9D64BE790E" + "udid" : "85474103-1335-4047-A4D5-91C4D1CDBD58" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 6s", - "udid" : "0D16FA74-F551-4113-9F5F-84D452CABF6A" + "udid" : "90010B41-74A6-40DC-AEC9-974E4F6264E7" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 6s Plus", - "udid" : "2459F12D-2D36-46B2-B947-D9A90B6C6A42" + "udid" : "2BA073FB-6172-4334-A655-2B31C6C82657" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 7", - "udid" : "10027F45-177A-47EB-AD7E-24103CB75AFF" + "udid" : "06962D58-6401-45F5-82F7-413977796685" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 7 Plus", - "udid" : "E32FE642-DD89-482B-BE16-4EBDAD3A6117" + "udid" : "34B6906D-9A1A-440B-96CD-34CC3C3E1720" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 8", - "udid" : "DDD18C72-F2BC-4DD5-8312-D5E7066C37AB" + "udid" : "2A62AB9F-5592-46EB-BAA4-725424DF0D79" }, { - "state" : "Booted", + "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 8 Plus", - "udid" : "E99A163B-1D42-4F8E-801A-B59B90F09B0C" - }, - { - "state" : "Booted", - "availability" : "(available)", - "name" : "iPhone 8 Plus-Detox", - "udid" : "AC97EE96-7F3E-45CC-87CE-5D07E43B29CD" - }, - { - "state" : "Booted", - "availability" : "(available)", - "name" : "iPhone 8 Plus-Detox", - "udid" : "4FF5B356-615A-4791-A304-A1472F1A033F" - }, - { - "state" : "Booted", - "availability" : "(available)", - "name" : "iPhone 8 Plus-Detox", - "udid" : "17480433-2AAD-4312-9E05-661702120441" + "udid" : "BA78368D-C17E-4804-A566-C9113C2AD0C6" }, { "state" : "Shutdown", "availability" : "(available)", - "name" : "iPhone 8 Plus-Detox", - "udid" : "10EDA942-69F5-45F8-B4BB-00BF3CE05D34" + "name" : "iPhone 8 Plus", + "udid" : "A0FEE9AE-A47F-4702-BEEF-BF7CDCB0E07F" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone 8 Plus-Detox", - "udid" : "EC6C5F15-DAEC-4D91-A93E-067EE5772504" + "udid" : "700BA886-CF0F-4264-85AE-48DF552B61DC" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone SE", - "udid" : "94DA9917-F76E-4CE9-A53E-88D2F76270E9" + "udid" : "203BB3AB-1DF7-4E42-9725-F6A536D3AD00" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPhone X", - "udid" : "A48A5681-0859-41C1-A05C-1210FE1CC07B" + "udid" : "DF1DBE73-B9B0-4754-A2AD-40CDB50E0D2D" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPad Air", - "udid" : "38279B65-D75D-4544-BA09-1AA7D1F8BE7A" + "udid" : "B29729B8-4B5C-45DB-BA50-86E5F50CC4DB" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPad Air 2", - "udid" : "B7DD7F19-AFCE-42AC-96FC-B3414A5A643B" + "udid" : "DA9863FC-0FBF-43A0-A505-A47AB05E4895" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPad (5th generation)", - "udid" : "4CF3B64A-A77F-402C-98A1-008256C57630" + "udid" : "D360469E-B8F5-4303-B95A-1BB44606EC14" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPad Pro (9.7-inch)", - "udid" : "BCF27E08-E4DF-451F-86FC-0205C0797040" + "udid" : "0AE4EEEB-013D-49F9-AEAB-ED52D293AFA5" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPad Pro (12.9-inch)", - "udid" : "2F2DEC15-B92C-4D5E-AECC-E5BD01F694C7" + "udid" : "1DDD896F-FA47-4E3F-8977-1C6196A2835E" }, { "state" : "Shutdown", "availability" : "(available)", "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "FAEF24DF-877D-4C65-9754-F3E0D54F5B80" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "iPad Pro (10.5-inch)", - "udid" : "A5BFDF79-9AC5-4ABF-91F7-BCEB6E7877FA" - } - ], - "tvOS 11.3" : [ - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple TV", - "udid" : "84CCF063-F06F-409E-A264-F3971CB899AF" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple TV 4K", - "udid" : "5F5EC33F-55CF-4917-8509-789240BE3598" + "udid" : "DA4721B5-AFD4-4A73-BCC3-ED19640B7AED" }, { "state" : "Shutdown", "availability" : "(available)", - "name" : "Apple TV 4K (at 1080p)", - "udid" : "962331E1-1D80-4644-89ED-BFFB46EBE7E3" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-10-0" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "9EC2F2E1-3FCC-4635-BC69-7558AB64E2B8" - } - ], - "com.apple.CoreSimulator.SimRuntime.watchOS-3-1" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 38mm", - "udid" : "240C26E6-FE33-41A3-8EF0-7858DA2F53B6" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 42mm", - "udid" : "C5366104-3578-4E59-9212-F2B3138D7A9E" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "06636736-4EE6-4CBF-9D5F-436CF2260448" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "DA3753BB-0B7D-4745-9530-9F2A08356A75" - } - ], - "com.apple.CoreSimulator.SimRuntime.iOS-9-3" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 4s", - "udid" : "A0C05A53-04A7-4D19-BEC9-5BF961483DD9" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5", - "udid" : "6AEBE78B-E6B3-443B-8B8F-D91F8E766A23" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5s", - "udid" : "F2132AC3-CECF-4EAF-9763-58CE584A1C94" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6", - "udid" : "A26635FD-0DCA-4679-9934-19AA7DEC59DB" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6 Plus", - "udid" : "03743681-7CA5-47C2-B4F8-CF8D03272FB6" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s", - "udid" : "291E8BFF-2576-43A1-9B14-AF07937BED6A" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s Plus", - "udid" : "FA4ACAFA-8CA1-4EF0-B594-6A856C006B51" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad 2", - "udid" : "FEF98A7E-0630-4C4C-83C1-1FB7F2129D83" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Retina", - "udid" : "FBCD1D2D-B9AC-4201-B850-BB6363CA2D7C" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air", - "udid" : "85D3A5F6-E982-4751-8C2F-3FB68A6ED2E4" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air 2", - "udid" : "CAE43B00-1766-4804-8D4B-99A48B8D7858" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro", - "udid" : "880C4E47-C6DC-45F8-BDF6-8B167561C274" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-10-1" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "95A9A35D-9C9D-4360-A266-1AB1D5D0A8CA" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-11-0" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "4F521FFA-99FF-4815-B1FE-0B19AC2A740D" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 4K", - "udid" : "C0A6390F-C364-4922-AE22-C983A46409A3" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 4K (at 1080p)", - "udid" : "8C1B1F1E-5FED-449F-A918-6C0E808EAA3D" - } - ], - "com.apple.CoreSimulator.SimRuntime.watchOS-2-2" : [ - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 38mm", - "udid" : "631E3AFD-DDB4-406A-A668-556D4FEDF07C" - }, - { - "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 42mm", - "udid" : "6E2F9E53-7659-476A-9C14-5E48C428BC36" + "name" : "iPad Pro (10.5-inch)", + "udid" : "5069E6F3-92EC-41FE-919B-26289FF3A3A4" } ], "com.apple.CoreSimulator.SimRuntime.tvOS-10-2" : [ @@ -724,266 +815,274 @@ "udid" : "40EDC654-D61C-4B8D-B277-95D67D543DD3" } ], - "com.apple.CoreSimulator.SimRuntime.watchOS-4-0" : [ + "iOS 11.3" : [ { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 38mm", - "udid" : "98631D9A-A2B3-4752-8A3E-92E990BAE106" + "availability" : "(available)", + "name" : "iPhone 5s", + "udid" : "39B78018-71A0-48B0-8154-A6603D559984" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch - 42mm", - "udid" : "79E7E680-0D9F-40A2-9EE4-2F7EB351A094" + "availability" : "(available)", + "name" : "iPhone 6", + "udid" : "A50461D5-1FDD-4231-BBE6-FE861646E95B" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "6812D5A9-2931-467F-A349-7F46953B0F32" + "availability" : "(available)", + "name" : "iPhone 6 Plus", + "udid" : "35F6AC74-F66C-4A20-943F-8C9D64BE790E" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "70FB6CDE-A5CB-4995-9CCB-9288E93C7308" + "availability" : "(available)", + "name" : "iPhone 6s", + "udid" : "0D16FA74-F551-4113-9F5F-84D452CABF6A" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "F080A29E-2615-46D3-B32E-D0C27EAC7D58" + "availability" : "(available)", + "name" : "iPhone 6s Plus", + "udid" : "2459F12D-2D36-46B2-B947-D9A90B6C6A42" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "2F5B3F90-3279-4542-A08E-0A10578DBDE7" - } - ], - "com.apple.CoreSimulator.SimRuntime.iOS-10-1" : [ + "availability" : "(available)", + "name" : "iPhone 7", + "udid" : "10027F45-177A-47EB-AD7E-24103CB75AFF" + }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5", - "udid" : "69E9738A-271D-409E-AAF8-F843C2C9CB3B" + "availability" : "(available)", + "name" : "iPhone 7 Plus", + "udid" : "E32FE642-DD89-482B-BE16-4EBDAD3A6117" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5s", - "udid" : "6CA27F3D-0F40-4BDF-81F7-D5799181F1F7" + "availability" : "(available)", + "name" : "iPhone 8", + "udid" : "DDD18C72-F2BC-4DD5-8312-D5E7066C37AB" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6", - "udid" : "CB66B6DD-393A-436A-A52D-9D22A332CC65" + "availability" : "(available)", + "name" : "iPhone 8 Plus", + "udid" : "E99A163B-1D42-4F8E-801A-B59B90F09B0C" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6 Plus", - "udid" : "F2A4AE49-FC71-43F2-B9C4-2BF0398549A7" + "availability" : "(available)", + "name" : "iPhone SE", + "udid" : "94DA9917-F76E-4CE9-A53E-88D2F76270E9" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s", - "udid" : "2828C5F5-540F-470C-A17D-82A3E401E855" + "availability" : "(available)", + "name" : "iPhone X", + "udid" : "A48A5681-0859-41C1-A05C-1210FE1CC07B" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s Plus", - "udid" : "6249369E-BBE7-4A27-B1AC-B079209C74EC" + "availability" : "(available)", + "name" : "iPad Air", + "udid" : "38279B65-D75D-4544-BA09-1AA7D1F8BE7A" }, { - "state" : "Creating", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7", - "udid" : "9C9ABE4D-70C7-49DC-A396-3CB1D0E82846" + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad Air 2", + "udid" : "B7DD7F19-AFCE-42AC-96FC-B3414A5A643B" }, { - "state" : "Creating", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7 Plus", - "udid" : "8C2A47A6-A415-4A5F-8372-4FF4CA232BD8" + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPad (5th generation)", + "udid" : "4CF3B64A-A77F-402C-98A1-008256C57630" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone SE", - "udid" : "39CDBD89-A8CB-42E9-B4EB-E28E2958E4C9" + "availability" : "(available)", + "name" : "iPad Pro (9.7-inch)", + "udid" : "BCF27E08-E4DF-451F-86FC-0205C0797040" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Retina", - "udid" : "9C029A8A-7096-4CA1-94DD-EA8F720C5FD9" + "availability" : "(available)", + "name" : "iPad Pro (12.9-inch)", + "udid" : "2F2DEC15-B92C-4D5E-AECC-E5BD01F694C7" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air", - "udid" : "D1CE0B39-B724-438B-935D-97C915817B19" + "availability" : "(available)", + "name" : "iPad Pro (12.9-inch) (2nd generation)", + "udid" : "FAEF24DF-877D-4C65-9754-F3E0D54F5B80" }, { "state" : "Shutdown", - "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air 2", - "udid" : "193D0394-2580-44DC-8A04-F5823FB039CC" - }, + "availability" : "(available)", + "name" : "iPad Pro (10.5-inch)", + "udid" : "A5BFDF79-9AC5-4ABF-91F7-BCEB6E7877FA" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-10-1" : [ { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (9.7 inch)", - "udid" : "518D94EB-75B2-453D-A141-7A1E1F49F382" - }, + "name" : "Apple TV 1080p", + "udid" : "95A9A35D-9C9D-4360-A266-1AB1D5D0A8CA" + } + ], + "iOS 9.2" : [ + { + "state" : "Shutdown", + "availability" : "(available)", + "name" : "iPhone 6s Plus", + "udid" : "9E22FA5C-1225-4BB0-9883-03AA139BA731" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-10-0" : [ { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (12.9 inch)", - "udid" : "058A009B-4348-4281-8B9C-B5C0CE06EFF8" + "name" : "Apple TV 1080p", + "udid" : "9EC2F2E1-3FCC-4635-BC69-7558AB64E2B8" } ], - "watchOS 4.3" : [ + "com.apple.CoreSimulator.SimRuntime.watchOS-3-2" : [ { "state" : "Shutdown", - "availability" : "(available)", + "availability" : " (unavailable, runtime profile not found)", "name" : "Apple Watch - 38mm", - "udid" : "C6EC2279-A6EB-40BE-99D2-5F11949F25E5" + "udid" : "65216D2D-8329-4720-B7B7-56DE1DA223DE" }, { "state" : "Shutdown", - "availability" : "(available)", + "availability" : " (unavailable, runtime profile not found)", "name" : "Apple Watch - 42mm", - "udid" : "498D4237-8640-43A7-BC80-61F112287C61" + "udid" : "B288646D-8B92-4799-A5F8-55ACF7EAB4FC" }, { "state" : "Shutdown", - "availability" : "(available)", + "availability" : " (unavailable, runtime profile not found)", "name" : "Apple Watch Series 2 - 38mm", - "udid" : "68B8DF0C-9837-49B9-BDB4-A6C6E34BA6EB" + "udid" : "C41A6B35-7FBD-4A25-BC59-A11DD490E543" }, { "state" : "Shutdown", - "availability" : "(available)", + "availability" : " (unavailable, runtime profile not found)", "name" : "Apple Watch Series 2 - 42mm", - "udid" : "84D9A184-FDF3-4666-9B45-765E2DA1867A" - }, - { - "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "D08B8137-371E-424C-B067-F659B9CDCFAC" - }, + "udid" : "1089EFA6-E851-42DD-B88F-945193DBC47C" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-9-2" : [ { "state" : "Shutdown", - "availability" : "(available)", - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "3B04A39B-5BAC-4523-B23E-847B20672959" + "availability" : " (unavailable, runtime profile not found)", + "name" : "Apple TV 1080p", + "udid" : "86C23AE7-E9E0-4358-91EB-DEA118CF5B4C" } ], - "com.apple.CoreSimulator.SimRuntime.iOS-10-2" : [ + "com.apple.CoreSimulator.SimRuntime.tvOS-9-1" : [ { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5", - "udid" : "601A6052-401B-4D5F-9969-D1B252BFB63A" - }, + "name" : "Apple TV 1080p", + "udid" : "3727084D-1D11-4D5F-B1C9-AE12D9EA25D0" + } + ], + "com.apple.CoreSimulator.SimRuntime.tvOS-11-0" : [ { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 5s", - "udid" : "AC2800F6-6B9F-4952-BDAD-28A0F43B621C" + "name" : "Apple TV 1080p", + "udid" : "4F521FFA-99FF-4815-B1FE-0B19AC2A740D" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6", - "udid" : "5FE03940-89F3-4DED-B924-9DD0630C5D3B" + "name" : "Apple TV 4K", + "udid" : "C0A6390F-C364-4922-AE22-C983A46409A3" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6 Plus", - "udid" : "4E51342E-1F41-45ED-A6EA-6313FDED9E27" - }, + "name" : "Apple TV 4K (at 1080p)", + "udid" : "8C1B1F1E-5FED-449F-A918-6C0E808EAA3D" + } + ], + "com.apple.CoreSimulator.SimRuntime.iOS-9-3" : [ { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s", - "udid" : "D39174C7-0DCB-4881-BD1C-18A7C82B1DC4" + "name" : "iPhone 4s", + "udid" : "A0C05A53-04A7-4D19-BEC9-5BF961483DD9" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 6s Plus", - "udid" : "BE906158-376A-4733-A6ED-65E2B79B2351" + "name" : "iPhone 5", + "udid" : "6AEBE78B-E6B3-443B-8B8F-D91F8E766A23" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7", - "udid" : "A3C93900-6D17-4830-8FBE-E102E4BBCBB9" + "name" : "iPhone 5s", + "udid" : "F2132AC3-CECF-4EAF-9763-58CE584A1C94" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone 7 Plus", - "udid" : "AE64887B-7B6F-439E-8039-99D43FD1FD8C" + "name" : "iPhone 6", + "udid" : "A26635FD-0DCA-4679-9934-19AA7DEC59DB" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPhone SE", - "udid" : "109BD1B5-21D0-491C-998D-98EC6F2E6AD3" + "name" : "iPhone 6 Plus", + "udid" : "03743681-7CA5-47C2-B4F8-CF8D03272FB6" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Retina", - "udid" : "555728C2-B1FF-410B-B096-83EC1F491BE2" + "name" : "iPhone 6s", + "udid" : "291E8BFF-2576-43A1-9B14-AF07937BED6A" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air", - "udid" : "21A8B777-4B51-4A7B-9788-1A0E39727614" + "name" : "iPhone 6s Plus", + "udid" : "FA4ACAFA-8CA1-4EF0-B594-6A856C006B51" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air - 2", - "udid" : "0A607DDB-9785-430E-8561-2E0B4B367E0E" + "name" : "iPad 2", + "udid" : "FEF98A7E-0630-4C4C-83C1-1FB7F2129D83" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Air 2", - "udid" : "95F63516-E360-49CF-B576-FB93EEFE0A1F" + "name" : "iPad Retina", + "udid" : "FBCD1D2D-B9AC-4201-B850-BB6363CA2D7C" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (9.7 inch)", - "udid" : "B3E96CEE-622A-4B36-8D19-5FB3165155CB" + "name" : "iPad Air", + "udid" : "85D3A5F6-E982-4751-8C2F-3FB68A6ED2E4" }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "iPad Pro (12.9 inch)", - "udid" : "FACC38D5-1F64-4081-9078-378C4B51C582" - } - ], - "com.apple.CoreSimulator.SimRuntime.tvOS-9-1" : [ + "name" : "iPad Air 2", + "udid" : "CAE43B00-1766-4804-8D4B-99A48B8D7858" + }, { "state" : "Shutdown", "availability" : " (unavailable, runtime profile not found)", - "name" : "Apple TV 1080p", - "udid" : "3727084D-1D11-4D5F-B1C9-AE12D9EA25D0" + "name" : "iPad Pro", + "udid" : "880C4E47-C6DC-45F8-BDF6-8B167561C274" } ] }, @@ -1075,7 +1174,7 @@ "phone" : { "name" : "iPhone 8 Plus", "udid" : "E99A163B-1D42-4F8E-801A-B59B90F09B0C", - "state" : "Booted" + "state" : "Shutdown" }, "state" : "(active, disconnected)" }, From f1d8b48eeb4ac4260e5c8cc05c3e6e4ed0617e9c Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Mon, 14 May 2018 11:19:25 +0300 Subject: [PATCH 62/73] Triggering PR build --- detox/src/devices/AppleSimUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index c0436d301b..5d152e60da 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -265,4 +265,4 @@ class LogsInfo { } } -module.exports = AppleSimUtils; \ No newline at end of file +module.exports = AppleSimUtils; From c0393b07df373a83c2f6178b0b98845e1c71d945 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Mon, 14 May 2018 12:20:05 +0300 Subject: [PATCH 63/73] print stderrs of after all retries failed --- detox/src/utils/exec.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/detox/src/utils/exec.js b/detox/src/utils/exec.js index 741fd34394..daa5ce93b7 100644 --- a/detox/src/utils/exec.js +++ b/detox/src/utils/exec.js @@ -20,22 +20,26 @@ async function execWithRetriesAndLogs(bin, options, statusLogs, retries = 10, in log.verbose(`${_operationCounter}: ${cmd}`); let result; - await retry({retries, interval}, async () => { - if (statusLogs && statusLogs.trying) { - log.info(`${_operationCounter}: ${statusLogs.trying}`); + + try { + await retry({retries, interval}, async () => { + if (statusLogs && statusLogs.trying) { + log.info(`${_operationCounter}: ${statusLogs.trying}`); + } + result = await exec(cmd); + }); + } catch(ex) { + if (ex.stderr) { + log.error(`${_operationCounter}: ${ex.stderr.trim()}, exited with code ${ex.code}`); } - result = await exec(cmd); - }); + } + if (result === undefined) { throw new Error(`${_operationCounter}: running "${cmd}" returned undefined`); } if (result.stdout) { - log.verbose(`${_operationCounter}: stdout:`, result.stdout); - } - - if (result.stderr) { - log.verbose(`${_operationCounter}: stderr:`, result.stderr); + log.verbose(`${_operationCounter}: stdout: ${result.stdout}`); } if (statusLogs && statusLogs.successful) { From 86b1b8a8915ca48092e7c145ec84d06e32ba50fb Mon Sep 17 00:00:00 2001 From: Rotem M Date: Mon, 14 May 2018 12:24:14 +0300 Subject: [PATCH 64/73] print stderrs of after all retries failed --- detox/src/utils/exec.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/detox/src/utils/exec.js b/detox/src/utils/exec.js index daa5ce93b7..e7440026f2 100644 --- a/detox/src/utils/exec.js +++ b/detox/src/utils/exec.js @@ -28,10 +28,8 @@ async function execWithRetriesAndLogs(bin, options, statusLogs, retries = 10, in } result = await exec(cmd); }); - } catch(ex) { - if (ex.stderr) { - log.error(`${_operationCounter}: ${ex.stderr.trim()}, exited with code ${ex.code}`); - } + } catch (ex) { + log.error(`${_operationCounter}: ${ex.stderr.trim()}, exited with code ${ex.code}`); } if (result === undefined) { From 1084c20369b4684d4d2058be20ca523d04571e44 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Mon, 14 May 2018 12:26:51 +0300 Subject: [PATCH 65/73] Revert "Triggering PR build" This reverts commit f1d8b48eeb4ac4260e5c8cc05c3e6e4ed0617e9c. --- detox/src/devices/AppleSimUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/devices/AppleSimUtils.js b/detox/src/devices/AppleSimUtils.js index 5d152e60da..c0436d301b 100644 --- a/detox/src/devices/AppleSimUtils.js +++ b/detox/src/devices/AppleSimUtils.js @@ -265,4 +265,4 @@ class LogsInfo { } } -module.exports = AppleSimUtils; +module.exports = AppleSimUtils; \ No newline at end of file From 87c357fa39ddfc6203be5672e8fc095c42612735 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Mon, 14 May 2018 12:52:24 +0300 Subject: [PATCH 66/73] Trigger PR after fixed jenkins --- detox/src/utils/exec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/detox/src/utils/exec.js b/detox/src/utils/exec.js index e7440026f2..a21865c466 100644 --- a/detox/src/utils/exec.js +++ b/detox/src/utils/exec.js @@ -55,4 +55,3 @@ async function execWithRetriesAndLogs(bin, options, statusLogs, retries = 10, in module.exports = { execWithRetriesAndLogs }; - From e6743dad3e8c736f0fb168bfaa7c16801b1f3657 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Mon, 14 May 2018 12:58:10 +0300 Subject: [PATCH 67/73] Revert "Trigger PR after fixed jenkins" This reverts commit 87c357fa39ddfc6203be5672e8fc095c42612735. --- detox/src/utils/exec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/detox/src/utils/exec.js b/detox/src/utils/exec.js index a21865c466..e7440026f2 100644 --- a/detox/src/utils/exec.js +++ b/detox/src/utils/exec.js @@ -55,3 +55,4 @@ async function execWithRetriesAndLogs(bin, options, statusLogs, retries = 10, in module.exports = { execWithRetriesAndLogs }; + From 0c73826beb180f2dab63d9e51b25d8702339d566 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Mon, 14 May 2018 13:15:23 +0300 Subject: [PATCH 68/73] Last try trigger PR --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 9c13379f16..8007e8f595 100644 --- a/package.json +++ b/package.json @@ -5,4 +5,3 @@ "release": "node scripts/release.js" } } - From 00cd14b8c794707e436c27677c4ae5df099f48b8 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Mon, 14 May 2018 13:31:52 +0300 Subject: [PATCH 69/73] Revert "Last try trigger PR" This reverts commit 0c73826beb180f2dab63d9e51b25d8702339d566. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 8007e8f595..9c13379f16 100644 --- a/package.json +++ b/package.json @@ -5,3 +5,4 @@ "release": "node scripts/release.js" } } + From dd792493b63b0ac4dda1cc97b9cc89640532f699 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Tue, 15 May 2018 09:43:42 +0300 Subject: [PATCH 70/73] Revert "Revert "Last try trigger PR"" This reverts commit 00cd14b8c794707e436c27677c4ae5df099f48b8. --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 9c13379f16..8007e8f595 100644 --- a/package.json +++ b/package.json @@ -5,4 +5,3 @@ "release": "node scripts/release.js" } } - From d91bd9c9128d31bf2d24d3a58814b092a8b238a8 Mon Sep 17 00:00:00 2001 From: Shalom Yerushalmy Date: Tue, 15 May 2018 10:22:20 +0300 Subject: [PATCH 71/73] Add empty line to package.json for triggering build --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 8007e8f595..9c13379f16 100644 --- a/package.json +++ b/package.json @@ -5,3 +5,4 @@ "release": "node scripts/release.js" } } + From c6c90f456ff6716c773c363e4fb38e0d05bb1959 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Tue, 22 May 2018 10:03:18 +0300 Subject: [PATCH 72/73] update xcode --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d48a844909..64e901de2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ matrix: include: - language: objective-c os: osx - osx_image: xcode9.2 + osx_image: xcode9.3 env: - REACT_NATIVE_VERSION=0.53.3 install: @@ -14,7 +14,7 @@ matrix: - ./scripts/ci.ios.sh - language: objective-c os: osx - osx_image: xcode9.2 + osx_image: xcode9.3 env: - REACT_NATIVE_VERSION=0.51.1 install: @@ -42,7 +42,7 @@ matrix: # Example Projects - language: objective-c os: osx - osx_image: xcode9 + osx_image: xcode9.3 env: - REACT_NATIVE_VERSION=0.51.1 install: From c6357aea3f7170deba6d41621fc2e567884a2472 Mon Sep 17 00:00:00 2001 From: Rotem M Date: Mon, 28 May 2018 23:57:53 +0300 Subject: [PATCH 73/73] MOAR retries --- detox/src/devices/DeviceRegistry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js index ebdb6532b4..3be567d0e3 100644 --- a/detox/src/devices/DeviceRegistry.js +++ b/detox/src/devices/DeviceRegistry.js @@ -5,7 +5,7 @@ const retry = require('../utils/retry'); const environment = require('../utils/environment'); const DEVICE_LOCK_FILE_PATH = environment.getDeviceLockFilePath(); -const LOCK_RETRY_OPTIONS = {retries: 100, interval: 5}; +const LOCK_RETRY_OPTIONS = {retries: 10000, interval: 5}; class DeviceRegistry {