From 56595d48a33ae348be746c7f0ac5707cd3fa5a0a Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 27 Aug 2019 01:08:23 +0900 Subject: [PATCH 01/18] fix: Follow the new bundleid if running env on Xcode 11 --- lib/driver.js | 4 +- lib/wda/webdriveragent.js | 51 ++- test/unit/webdriveragent-specs.js | 549 +++++++++++++++++++++++++----- 3 files changed, 503 insertions(+), 101 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index 93704b07c..ffa49272e 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -486,7 +486,7 @@ class XCUITestDriver extends BaseDriver { return await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => { if (this.opts.useNewWDA) { log.debug(`Capability 'useNewWDA' set to true, so uninstalling WDA before proceeding`); - await this.wda.quitAndUninstall(); + await this.wda.quitAndUninstall(this.opts.updatedWDABundleId); this.logEvent('wdaUninstalled'); } else if (!util.hasValue(this.wda.webDriverAgentUrl)) { await this.wda.setupCaching(this.opts.updatedWDABundleId); @@ -500,7 +500,7 @@ class XCUITestDriver extends BaseDriver { throw new Error(msg); } log.warn('Quitting and uninstalling WebDriverAgent'); - await this.wda.quitAndUninstall(); + await this.wda.quitAndUninstall(this.opts.updatedWDABundleId); throw new Error(msg); }; diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index 40dad759b..c3765afc7 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -13,10 +13,10 @@ import { exec } from 'teen_process'; import AsyncLock from 'async-lock'; import { BOOTSTRAP_PATH, WDA_BUNDLE_ID, WDA_RUNNER_BUNDLE_ID, checkForDependencies } from 'appium-webdriveragent'; - const WDA_LAUNCH_TIMEOUT = 60 * 1000; const WDA_AGENT_PORT = 8100; const WDA_BASE_URL = 'http://localhost'; +const WDA_XCTRUNNER_SUFFIX = '.xctrunner'; const SHARED_RESOURCES_GUARD = new AsyncLock(); @@ -155,10 +155,27 @@ class WebDriverAgent { } } - async uninstall () { - log.debug(`Removing WDA application from device`); + /** + * Uninstall WDA from the test device. + * If WDA is built by Xcode 10-, the bundle id is WDA_BUNDLE_ID. + * If WDA is build by Xcode 11, the bundle id is 'com.facebook.WebDriverAgentRunner.xctrunner' for simulator. + * 'com.customised.WDA.xctrunner' for real device if a user sets 'updatedWDABundleId' as 'com.customised.WDA'. + * + * @param {string} updatedWDABundleId The bundle id which will be uninstalled + */ + async uninstall (updatedWDABundleId = WDA_RUNNER_BUNDLE_ID) { try { - await this.device.removeApp(WDA_BUNDLE_ID); + if (this.xcodeVersion.major < 11) { + // Can remove without errors + log.debug(`Removing WDA application from device: '${WDA_BUNDLE_ID}'`); + await this.device.removeApp(WDA_BUNDLE_ID); + } else { + // On simulator, the bundle id should be 'com.facebook.WebDriverAgentRunner.xctrunner' + // even if 'updatedWDABundleId' was given + const bundle_id = `${this.realDevice ? updatedWDABundleId : WDA_RUNNER_BUNDLE_ID}${WDA_XCTRUNNER_SUFFIX}`; + log.debug(`Removing WDA application from device: '${bundle_id}'`); + await this.device.removeApp(bundle_id); + } } catch (e) { log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? Original error: ${JSON.stringify(e)}`); } @@ -349,10 +366,12 @@ class WebDriverAgent { productBundleIdentifier, upgradedAt, } = status.build; + // for real device if (util.hasValue(productBundleIdentifier) && util.hasValue(updatedWDABundleId) && updatedWDABundleId !== productBundleIdentifier) { log.info(`Will uninstall running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`); - return await this.uninstall(); + return await this.uninstall(productBundleIdentifier); } + // for simulator if (util.hasValue(productBundleIdentifier) && !util.hasValue(updatedWDABundleId) && WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier) { log.info(`Will uninstall running WDA since its bundle id is not equal to the default value ${WDA_RUNNER_BUNDLE_ID}`); return await this.uninstall(); @@ -364,7 +383,7 @@ class WebDriverAgent { if (actualUpgradeTimestamp && upgradedAt && _.toLower(`${actualUpgradeTimestamp}`) !== _.toLower(`${upgradedAt}`)) { log.info('Will uninstall running WDA since it has different version in comparison to the one ' + `which is bundled with appium-xcuitest-driver module (${actualUpgradeTimestamp} != ${upgradedAt})`); - return await this.uninstall(); + return await this.uninstall(productBundleIdentifier); } const message = util.hasValue(productBundleIdentifier) @@ -374,9 +393,25 @@ class WebDriverAgent { this.webDriverAgentUrl = this.url.href; } - async quitAndUninstall () { + /** + * Quit and uninstall running WDA. + * Uninstall given updatedWDABundleId, 'WDA_RUNNER_BUNDLE_ID' or running 'productBundleIdentifier + * for Xcode 11. Uninstall 'WDA_BUNDLE_ID' for Xcode 10-. + * + * @param {string} updatedWDABundleId The bundle id which will be uninstalled + */ + async quitAndUninstall (updatedWDABundleId = WDA_RUNNER_BUNDLE_ID) { await this.quit(); - await this.uninstall(); + + const status = await this.getStatus(); + if (status && status.build) { + const { productBundleIdentifier } = status.build; + if (util.hasValue(productBundleIdentifier)) { + updatedWDABundleId = productBundleIdentifier; + } + } + + await this.uninstall(updatedWDABundleId); } } diff --git a/test/unit/webdriveragent-specs.js b/test/unit/webdriveragent-specs.js index 0b37828e4..b773310f2 100644 --- a/test/unit/webdriveragent-specs.js +++ b/test/unit/webdriveragent-specs.js @@ -110,134 +110,501 @@ describe('get url', function () { }); describe('setupCaching()', function () { + let opts = {}; let wda; let wdaStub; - let wdaStubUninstall; + let wdaStubRemoveApp; + let wdaDevice; const getTimestampStub = sinon.stub(utils, 'getWDAUpgradeTimestamp'); - beforeEach(function () { - wda = new WebDriverAgent('1'); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubUninstall = sinon.stub(wda, 'uninstall'); - }); + describe('Xcode 10, simulator', function () { + beforeEach(function () { + opts = {}; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + }); - afterEach(function () { - for (const stub of [wdaStub, wdaStubUninstall, getTimestampStub]) { - if (stub) { - stub.reset(); + afterEach(function () { + opts = {}; + for (const stub of [wdaStub, wdaStubRemoveApp, getTimestampStub]) { + if (stub) { + stub.reset(); + } } - } - }); + }); - it('should not call uninstall since no Running WDA', async function () { - wdaStub.callsFake(function () { - return null; + it('should not call uninstall since no Running WDA', async function () { + wdaStub.callsFake(function () { + return null; + }); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; }); - wdaStubUninstall.callsFake(_.noop); - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.notCalled.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); + it('should not call uninstall since running WDA has only time', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21' }}; + }); + wdaStubRemoveApp.callsFake(_.noop); - it('should not call uninstall since running WDA has only time', async function () { - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21' }}; + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); }); - wdaStubUninstall.callsFake(_.noop); - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.notCalled.should.be.true; - wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); - }); + it('should call uninstall once since bundle id is not default without updatedWDABundleId capability', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; + }); + wdaStubRemoveApp.callsFake(_.noop); - it('should call uninstall once since bundle id is not default without updatedWDABundleId capability', async function () { - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; }); - wdaStubUninstall.callsFake(_.noop); - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.calledOnce.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); + it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () { + opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }}; + }); - it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () { - const updatedWDABundleId = 'com.example.WebDriverAgent'; - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }}; + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; }); - wdaStubUninstall.callsFake(_.noop); + it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () { + opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; + }); - await wda.setupCaching(updatedWDABundleId); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.calledOnce.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); + wdaStubRemoveApp.callsFake(_.noop); - it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () { - const updatedWDABundleId = 'com.example.WebDriverAgent'; - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); + }); + + it('should call uninstall default bundle id if current revision differs from the bundled one', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; + }); + getTimestampStub.callsFake(() => '2'); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching('something'); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; + }); + + it('should call uninstall default bundle id if current revision differs from the bundled one and running productBundleIdentifier is default value', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1', productBundleIdentifier: 'com.facebook.WebDriverAgentRunner' }}; + }); + getTimestampStub.callsFake(() => '2'); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; + }); + + it('should not call uninstall if current revision is the same as the bundled one', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; + }); + getTimestampStub.callsFake(() => '1'); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching('something'); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; }); - wdaStubUninstall.callsFake(_.noop); + it('should not call uninstall if current revision cannot be retrieved from WDA status', async function () { + wdaStub.callsFake(function () { + return {build: {}}; + }); + getTimestampStub.callsFake(() => '1'); + wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(updatedWDABundleId); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.notCalled.should.be.true; - wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); + await wda.setupCaching('something'); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + }); + + it('should not call uninstall if current revision cannot be retrieved from the file system', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; + }); + getTimestampStub.callsFake(() => null); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching('something'); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + }); }); - it('should call uninstall if current revision differs from the bundled one', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; + describe('Xcode 11, real device', function () { + beforeEach(function () { + opts = {}; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + }); + + afterEach(function () { + opts = {}; + for (const stub of [wdaStub, wdaStubRemoveApp, getTimestampStub]) { + if (stub) { + stub.reset(); + } + } + }); + + it('should not call uninstall since no Running WDA', async function () { + wdaStub.callsFake(function () { + return null; + }); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; + }); + + it('should not call uninstall since running WDA has only time', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21' }}; + }); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); + }); + + it('should call uninstall once since bundle id is not default without updatedWDABundleId capability', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; + }); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; + }); + + it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () { + opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }}; + }); + + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.example.different.WebDriverAgent.xctrunner').calledOnce.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; + }); + + it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () { + opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; + }); + + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); + }); + + it('should call uninstall default bundle id if current revision differs from the bundled one', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; + }); + getTimestampStub.callsFake(() => '2'); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching('something'); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + }); + + it('should call uninstall default bundle id if current revision differs from the bundled one and running productBundleIdentifier is default value', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1', productBundleIdentifier: 'com.facebook.WebDriverAgentRunner' }}; + }); + getTimestampStub.callsFake(() => '2'); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + }); + + it('should not call uninstall if current revision is the same as the bundled one', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; + }); + getTimestampStub.callsFake(() => '1'); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching('something'); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + }); + + it('should not call uninstall if current revision cannot be retrieved from WDA status', async function () { + wdaStub.callsFake(function () { + return {build: {}}; + }); + getTimestampStub.callsFake(() => '1'); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching('something'); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; }); - getTimestampStub.callsFake(() => '2'); - wdaStubUninstall.callsFake(_.noop); - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.calledOnce.should.be.true; + it('should not call uninstall if current revision cannot be retrieved from the file system', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; + }); + getTimestampStub.callsFake(() => null); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.setupCaching('something'); + wdaStub.calledOnce.should.be.true; + wdaStubRemoveApp.notCalled.should.be.true; + }); }); +}); - it('should not call uninstall if current revision is the same as the bundled one', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; +describe('quitAndUninstall()', function () { + let opts = {}; + let wda; + let wdaStub; + let wdaStubRemoveApp; + let wdaStubQuit; + let wdaDevice; + + + describe('with Xcode 10, Simulator', function () { + beforeEach(function () { + opts = {}; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubQuit = sinon.stub(wda, 'quit'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + }); + + afterEach(function () { + opts = {}; + for (const stub of [wdaStub, wdaStubQuit, wdaStubRemoveApp]) { + if (stub) { + stub.reset(); + } + } + }); + + it('should uninstall default app since no Running WDA and no updatedWDABundleId', async function () { + wdaStub.callsFake(function () { + return null; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; }); - getTimestampStub.callsFake(() => '1'); - wdaStubUninstall.callsFake(_.noop); - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.notCalled.should.be.true; + it('should uninstall updatedWDABundleId with no running WDA', async function () { + opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaStub.callsFake(function () { + return null; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; + }); + + it('should uninstall productBundleIdentifier prior than updatedWDABundleId', async function () { + opts.updatedWDABundleId = 'com.example.updatedWDABundleId.WebDriverAgent'; + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.productBundleIdentifier.WebDriverAgent' }}; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; + }); + + it('should uninstall productBundleIdentifier', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.productBundleIdentifier.WebDriverAgent' }}; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; + }); }); - it('should not call uninstall if current revision cannot be retrieved from WDA status', async function () { - wdaStub.callsFake(function () { - return {build: {}}; + describe('with Xcode 11, real device', function () { + beforeEach(function () { + opts = {}; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubQuit = sinon.stub(wda, 'quit'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + }); + + afterEach(function () { + opts = {}; + for (const stub of [wdaStub, wdaStubQuit, wdaStubRemoveApp]) { + if (stub) { + stub.reset(); + } + } + }); + + it('should uninstall default app since no Running WDA and no updatedWDABundleId', async function () { + wdaStub.callsFake(function () { + return null; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + }); + + it('should uninstall updatedWDABundleId with no running WDA', async function () { + opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaStub.callsFake(function () { + return null; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.example.WebDriverAgent.xctrunner').calledOnce.should.be.true; + }); + + it('should uninstall productBundleIdentifier prior than updatedWDABundleId', async function () { + opts.updatedWDABundleId = 'com.example.updatedWDABundleId.WebDriverAgent'; + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.productBundleIdentifier.WebDriverAgent' }}; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.example.productBundleIdentifier.WebDriverAgent.xctrunner').calledOnce.should.be.true; }); - getTimestampStub.callsFake(() => '1'); - wdaStubUninstall.callsFake(_.noop); - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.notCalled.should.be.true; + it('should uninstall productBundleIdentifier', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.productBundleIdentifier.WebDriverAgent' }}; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.example.productBundleIdentifier.WebDriverAgent.xctrunner').calledOnce.should.be.true; + }); }); - it('should not call uninstall if current revision cannot be retrieved from the file system', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; + describe('with Xcode 11, simulator', function () { + beforeEach(function () { + opts = {}; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: false}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubQuit = sinon.stub(wda, 'quit'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + }); + + afterEach(function () { + opts = {}; + for (const stub of [wdaStub, wdaStubQuit, wdaStubRemoveApp]) { + if (stub) { + stub.reset(); + } + } + }); + + it('should uninstall default app since no Running WDA and no updatedWDABundleId', async function () { + wdaStub.callsFake(function () { + return null; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; }); - getTimestampStub.callsFake(() => null); - wdaStubUninstall.callsFake(_.noop); - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubUninstall.notCalled.should.be.true; + it('should uninstall updatedWDABundleId with no running WDA', async function () { + opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaStub.callsFake(function () { + return null; + }); + wdaStubQuit.callsFake(_.noop); + wdaStubRemoveApp.callsFake(_.noop); + + await wda.quitAndUninstall(opts.updatedWDABundleId); + wdaStub.calledOnce.should.be.true; + wdaStubQuit.calledOnce.should.be.true; + wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + }); }); -}); \ No newline at end of file +}); From d2c5fb13e48dd46e8e37c9863e9a3f3eb3962750 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 27 Aug 2019 01:34:09 +0900 Subject: [PATCH 02/18] tweak quit --- lib/wda/webdriveragent.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index c3765afc7..77402b407 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -401,8 +401,6 @@ class WebDriverAgent { * @param {string} updatedWDABundleId The bundle id which will be uninstalled */ async quitAndUninstall (updatedWDABundleId = WDA_RUNNER_BUNDLE_ID) { - await this.quit(); - const status = await this.getStatus(); if (status && status.build) { const { productBundleIdentifier } = status.build; @@ -411,6 +409,7 @@ class WebDriverAgent { } } + await this.quit(); await this.uninstall(updatedWDABundleId); } } From e16a3623a08ff477828ed622137092a7118f9d5e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 27 Aug 2019 23:23:01 +0900 Subject: [PATCH 03/18] simplify uninstall --- lib/wda/webdriveragent.js | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index 77402b407..7de8d8f37 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -53,6 +53,8 @@ class WebDriverAgent { this.usePrebuiltWDA = args.usePrebuiltWDA; this.derivedDataPath = args.derivedDataPath; + this.updatedWDABundleId = args.updatedWDABundleId; + this.xcodebuild = new XcodeBuild(this.xcodeVersion, this.device, { platformVersion: this.platformVersion, platformName: this.platformName, @@ -68,7 +70,7 @@ class WebDriverAgent { keychainPassword: args.keychainPassword, useSimpleBuildTest: args.useSimpleBuildTest, usePrebuiltWDA: args.usePrebuiltWDA, - updatedWDABundleId: args.updatedWDABundleId, + updatedWDABundleId: this.updatedWDABundleId, launchTimeout: args.wdaLaunchTimeout || WDA_LAUNCH_TIMEOUT, wdaRemotePort: this.realDevice ? WDA_AGENT_PORT : (this.wdaLocalPort || WDA_AGENT_PORT), useXctestrunFile: this.useXctestrunFile, @@ -159,23 +161,25 @@ class WebDriverAgent { * Uninstall WDA from the test device. * If WDA is built by Xcode 10-, the bundle id is WDA_BUNDLE_ID. * If WDA is build by Xcode 11, the bundle id is 'com.facebook.WebDriverAgentRunner.xctrunner' for simulator. - * 'com.customised.WDA.xctrunner' for real device if a user sets 'updatedWDABundleId' as 'com.customised.WDA'. + * 'com.customised.WDA.xctrunner' for real device if a user sets 'bundleId' as 'com.customised.WDA'. * - * @param {string} updatedWDABundleId The bundle id which will be uninstalled + * @param {string} bundleId The bundle id which will be uninstalled */ - async uninstall (updatedWDABundleId = WDA_RUNNER_BUNDLE_ID) { + async uninstall (bundleId = WDA_RUNNER_BUNDLE_ID) { try { - if (this.xcodeVersion.major < 11) { - // Can remove without errors - log.debug(`Removing WDA application from device: '${WDA_BUNDLE_ID}'`); - await this.device.removeApp(WDA_BUNDLE_ID); - } else { - // On simulator, the bundle id should be 'com.facebook.WebDriverAgentRunner.xctrunner' - // even if 'updatedWDABundleId' was given - const bundle_id = `${this.realDevice ? updatedWDABundleId : WDA_RUNNER_BUNDLE_ID}${WDA_XCTRUNNER_SUFFIX}`; - log.debug(`Removing WDA application from device: '${bundle_id}'`); - await this.device.removeApp(bundle_id); - } + // For (this.xcodeVersion && this.xcodeVersion.major < 11) + // this.xcodeVersion will be null when this.opts.webDriverAgentUrl is given. + // But webDriverAgentUrl has a value means users use their own WDA instead of this class. + // We can expect uninstall does not happen, in general. + // For Xcode 11+ + // On simulator, the bundle id should be 'com.facebook.WebDriverAgentRunner.xctrunner' + // even if 'updatedWDABundleId' was given + bundleId = (this.xcodeVersion && this.xcodeVersion.major < 11) + ? WDA_BUNDLE_ID + : `${this.realDevice ? bundleId : WDA_RUNNER_BUNDLE_ID}${WDA_XCTRUNNER_SUFFIX}`; + log.debug(`Removing WDA application from device: '${bundleId}'`); + await this.device.removeApp(bundleId); + } catch (e) { log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? Original error: ${JSON.stringify(e)}`); } From 6588ae003e396212cd8e2b39eae8897d66505ca5 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 27 Aug 2019 23:31:03 +0900 Subject: [PATCH 04/18] remove args from quitAndUninstall --- lib/driver.js | 6 ++--- lib/wda/webdriveragent.js | 11 +++++---- test/unit/webdriveragent-specs.js | 37 +++++++++++++++++++------------ 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index ffa49272e..165cd9b57 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -486,10 +486,10 @@ class XCUITestDriver extends BaseDriver { return await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => { if (this.opts.useNewWDA) { log.debug(`Capability 'useNewWDA' set to true, so uninstalling WDA before proceeding`); - await this.wda.quitAndUninstall(this.opts.updatedWDABundleId); + await this.wda.quitAndUninstall(); this.logEvent('wdaUninstalled'); } else if (!util.hasValue(this.wda.webDriverAgentUrl)) { - await this.wda.setupCaching(this.opts.updatedWDABundleId); + await this.wda.setupCaching(); } // local helper for the two places we need to uninstall wda and re-start it @@ -500,7 +500,7 @@ class XCUITestDriver extends BaseDriver { throw new Error(msg); } log.warn('Quitting and uninstalling WebDriverAgent'); - await this.wda.quitAndUninstall(this.opts.updatedWDABundleId); + await this.wda.quitAndUninstall(); throw new Error(msg); }; diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index 7de8d8f37..ce33a061a 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -179,7 +179,6 @@ class WebDriverAgent { : `${this.realDevice ? bundleId : WDA_RUNNER_BUNDLE_ID}${WDA_XCTRUNNER_SUFFIX}`; log.debug(`Removing WDA application from device: '${bundleId}'`); await this.device.removeApp(bundleId); - } catch (e) { log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? Original error: ${JSON.stringify(e)}`); } @@ -404,17 +403,21 @@ class WebDriverAgent { * * @param {string} updatedWDABundleId The bundle id which will be uninstalled */ - async quitAndUninstall (updatedWDABundleId = WDA_RUNNER_BUNDLE_ID) { + async quitAndUninstall () { + let bundleId = util.hasValue(this.updatedWDABundleId) + ? this.updatedWDABundleId + : WDA_RUNNER_BUNDLE_ID; + const status = await this.getStatus(); if (status && status.build) { const { productBundleIdentifier } = status.build; if (util.hasValue(productBundleIdentifier)) { - updatedWDABundleId = productBundleIdentifier; + bundleId = productBundleIdentifier; } } await this.quit(); - await this.uninstall(updatedWDABundleId); + await this.uninstall(bundleId); } } diff --git a/test/unit/webdriveragent-specs.js b/test/unit/webdriveragent-specs.js index b773310f2..64452965a 100644 --- a/test/unit/webdriveragent-specs.js +++ b/test/unit/webdriveragent-specs.js @@ -439,7 +439,7 @@ describe('quitAndUninstall()', function () { wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; @@ -453,7 +453,7 @@ describe('quitAndUninstall()', function () { wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; @@ -467,7 +467,7 @@ describe('quitAndUninstall()', function () { wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; @@ -480,7 +480,7 @@ describe('quitAndUninstall()', function () { wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; @@ -513,21 +513,26 @@ describe('quitAndUninstall()', function () { wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; }); it('should uninstall updatedWDABundleId with no running WDA', async function () { - opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + // override + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true, updatedWDABundleId: 'com.example.WebDriverAgent'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubQuit = sinon.stub(wda, 'quit'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); wdaStub.callsFake(function () { return null; }); wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.example.WebDriverAgent.xctrunner').calledOnce.should.be.true; @@ -541,7 +546,7 @@ describe('quitAndUninstall()', function () { wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.example.productBundleIdentifier.WebDriverAgent.xctrunner').calledOnce.should.be.true; @@ -554,7 +559,7 @@ describe('quitAndUninstall()', function () { wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.example.productBundleIdentifier.WebDriverAgent.xctrunner').calledOnce.should.be.true; @@ -563,7 +568,6 @@ describe('quitAndUninstall()', function () { describe('with Xcode 11, simulator', function () { beforeEach(function () { - opts = {}; wdaDevice = { removeApp: () => {} }; wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: false}); wdaStub = sinon.stub(wda, 'getStatus'); @@ -572,7 +576,6 @@ describe('quitAndUninstall()', function () { }); afterEach(function () { - opts = {}; for (const stub of [wdaStub, wdaStubQuit, wdaStubRemoveApp]) { if (stub) { stub.reset(); @@ -587,21 +590,27 @@ describe('quitAndUninstall()', function () { wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; }); it('should uninstall updatedWDABundleId with no running WDA', async function () { - opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + // override + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'com.example.WebDriverAgent'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubQuit = sinon.stub(wda, 'quit'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + wdaStub.callsFake(function () { return null; }); wdaStubQuit.callsFake(_.noop); wdaStubRemoveApp.callsFake(_.noop); - await wda.quitAndUninstall(opts.updatedWDABundleId); + await wda.quitAndUninstall(); wdaStub.calledOnce.should.be.true; wdaStubQuit.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; From 5b18d3edbe3f65103e247498e7331e97ad93e10e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 27 Aug 2019 23:45:48 +0900 Subject: [PATCH 05/18] remove arg for setupCaching --- lib/wda/webdriveragent.js | 6 +-- test/unit/webdriveragent-specs.js | 62 ++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index ce33a061a..d2af29e4b 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -358,7 +358,7 @@ class WebDriverAgent { * * @param {string} updatedWDABundleId BundleId you'd like to use */ - async setupCaching (updatedWDABundleId) { + async setupCaching () { const status = await this.getStatus(); if (!status || !status.build) { log.debug('WDA is currently not running. There is nothing to cache'); @@ -370,12 +370,12 @@ class WebDriverAgent { upgradedAt, } = status.build; // for real device - if (util.hasValue(productBundleIdentifier) && util.hasValue(updatedWDABundleId) && updatedWDABundleId !== productBundleIdentifier) { + if (util.hasValue(productBundleIdentifier) && util.hasValue(this.updatedWDABundleId) && this.updatedWDABundleId !== productBundleIdentifier) { log.info(`Will uninstall running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`); return await this.uninstall(productBundleIdentifier); } // for simulator - if (util.hasValue(productBundleIdentifier) && !util.hasValue(updatedWDABundleId) && WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier) { + if (util.hasValue(productBundleIdentifier) && !util.hasValue(this.updatedWDABundleId) && WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier) { log.info(`Will uninstall running WDA since its bundle id is not equal to the default value ${WDA_RUNNER_BUNDLE_ID}`); return await this.uninstall(); } diff --git a/test/unit/webdriveragent-specs.js b/test/unit/webdriveragent-specs.js index 64452965a..d7384c049 100644 --- a/test/unit/webdriveragent-specs.js +++ b/test/unit/webdriveragent-specs.js @@ -119,7 +119,6 @@ describe('setupCaching()', function () { describe('Xcode 10, simulator', function () { beforeEach(function () { - opts = {}; wdaDevice = { removeApp: () => {} }; wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false}); wdaStub = sinon.stub(wda, 'getStatus'); @@ -127,7 +126,6 @@ describe('setupCaching()', function () { }); afterEach(function () { - opts = {}; for (const stub of [wdaStub, wdaStubRemoveApp, getTimestampStub]) { if (stub) { stub.reset(); @@ -141,7 +139,7 @@ describe('setupCaching()', function () { }); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(opts.updatedWDABundleId); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.notCalled.should.be.true; _.isUndefined(wda.webDriverAgentUrl).should.be.true; @@ -153,7 +151,7 @@ describe('setupCaching()', function () { }); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(opts.updatedWDABundleId); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.notCalled.should.be.true; wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); @@ -165,35 +163,42 @@ describe('setupCaching()', function () { }); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(opts.updatedWDABundleId); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; _.isUndefined(wda.webDriverAgentUrl).should.be.true; }); it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () { - opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'com.example.WebDriverAgent'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); wdaStub.callsFake(function () { return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }}; }); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(opts.updatedWDABundleId); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; _.isUndefined(wda.webDriverAgentUrl).should.be.true; }); it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () { - opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'com.example.WebDriverAgent'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + wdaStub.callsFake(function () { return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; }); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(opts.updatedWDABundleId); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.notCalled.should.be.true; wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); @@ -218,43 +223,58 @@ describe('setupCaching()', function () { getTimestampStub.callsFake(() => '2'); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(opts.updatedWDABundleId); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; }); it('should not call uninstall if current revision is the same as the bundled one', async function () { + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'something'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + wdaStub.callsFake(function () { return {build: { upgradedAt: '1' }}; }); getTimestampStub.callsFake(() => '1'); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching('something'); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.notCalled.should.be.true; }); it('should not call uninstall if current revision cannot be retrieved from WDA status', async function () { + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'something'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + wdaStub.callsFake(function () { return {build: {}}; }); getTimestampStub.callsFake(() => '1'); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching('something'); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.notCalled.should.be.true; }); it('should not call uninstall if current revision cannot be retrieved from the file system', async function () { + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'something'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + wdaStub.callsFake(function () { return {build: { upgradedAt: '1' }}; }); getTimestampStub.callsFake(() => null); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching('something'); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.notCalled.should.be.true; }); @@ -315,28 +335,36 @@ describe('setupCaching()', function () { }); it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () { - opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true, updatedWDABundleId: 'com.example.WebDriverAgent'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + wdaStub.callsFake(function () { return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }}; }); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(opts.updatedWDABundleId); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.withArgs('com.example.different.WebDriverAgent.xctrunner').calledOnce.should.be.true; _.isUndefined(wda.webDriverAgentUrl).should.be.true; }); it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () { - opts.updatedWDABundleId = 'com.example.WebDriverAgent'; + wdaDevice = { removeApp: () => {} }; + wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true, updatedWDABundleId: 'com.example.WebDriverAgent'}); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + wdaStub.callsFake(function () { return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; }); wdaStubRemoveApp.callsFake(_.noop); - await wda.setupCaching(opts.updatedWDABundleId); + await wda.setupCaching(); wdaStub.calledOnce.should.be.true; wdaStubRemoveApp.notCalled.should.be.true; wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); From 9ab2c3eea96f40276835787f9933aed6a6b931c1 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 28 Aug 2019 00:55:07 +0900 Subject: [PATCH 06/18] add parsing plist --- lib/wda/utils.js | 22 +++++++++++++++++++++ lib/wda/webdriveragent.js | 11 ++++++++++- test/unit/wda/utils-specs.js | 37 +++++++++++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/lib/wda/utils.js b/lib/wda/utils.js index 2835acf2e..23ad83410 100644 --- a/lib/wda/utils.js +++ b/lib/wda/utils.js @@ -212,6 +212,27 @@ function getXctestrunFileName (deviceInfo, version) { : `WebDriverAgentRunner_iphone${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun`; } + +/** + * Return the path of Info.plist file + * @param {DeviceInfo} deviceInfo + * @param {string} bootstrapPath + * @return {string} returns Info.plist file path + */ +function getBundleIdFromInfoPlistPath (deviceInfo, bootstrapPath) { + const infoPlist = isTvOS(deviceInfo.platformName) + ? `Debug-appletv${deviceInfo.isRealDevice ? 'os' : 'simulator'}/WebDriverAgentRunner_tvOS-Runner.app/Info.plist` + : `Debug-iphone${deviceInfo.isRealDevice ? 'os' : 'simulator'}/WebDriverAgentRunner-Runner.app/Info.plist`; + + return path.resolve(bootstrapPath, infoPlist); +} + +async function getCFBundleIdentifierFromPlist (deviceInfo, bootstrapPath) { + const parsedPlist = await plist.parsePlistFile( + getBundleIdFromInfoPlistPath(deviceInfo, bootstrapPath), false); + return parsedPlist.CFBundleIdentifier; +} + async function killProcess (name, proc) { if (proc && proc.proc) { log.info(`Shutting down ${name} process (pid ${proc.proc.pid})`); @@ -263,6 +284,7 @@ async function getWDAUpgradeTimestamp (bootstrapPath) { export { updateProjectFile, resetProjectFile, setRealDeviceSecurity, fixForXcode9, getAdditionalRunContent, getXctestrunFileName, + getBundleIdFromInfoPlistPath, getCFBundleIdentifierFromPlist, generateXcodeConfigFile, setXctestrunFile, getXctestrunFilePath, killProcess, randomInt, getWDAUpgradeTimestamp, CARTHAGE_ROOT, }; diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index d2af29e4b..87d3aca1b 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -5,7 +5,7 @@ import { JWProxy } from 'appium-base-driver'; import { fs, util } from 'appium-support'; import log from '../logger'; import { NoSessionProxy } from './no-session-proxy'; -import { getWDAUpgradeTimestamp, CARTHAGE_ROOT } from './utils'; +import { getWDAUpgradeTimestamp, CARTHAGE_ROOT, getCFBundleIdentifierFromPlist } from './utils'; import { resetXCTestProcesses, getPIDsListeningOnPort, isLocalHost } from '../utils'; import XcodeBuild from './xcodebuild'; import iProxy from './iproxy'; @@ -401,6 +401,9 @@ class WebDriverAgent { * Uninstall given updatedWDABundleId, 'WDA_RUNNER_BUNDLE_ID' or running 'productBundleIdentifier * for Xcode 11. Uninstall 'WDA_BUNDLE_ID' for Xcode 10-. * + * If it fails to get 'await this.getStatus()', it will try to read + * bundle id from plist by WDA. + * * @param {string} updatedWDABundleId The bundle id which will be uninstalled */ async quitAndUninstall () { @@ -414,6 +417,12 @@ class WebDriverAgent { if (util.hasValue(productBundleIdentifier)) { bundleId = productBundleIdentifier; } + } else { + const parsedBundleId = await getCFBundleIdentifierFromPlist( + {isRealDevice: this.isRealDevice, platformName: this.platformName}, this.bootstrapPath); + if (util.hasValue(parsedBundleId)) { + bundleId = parsedBundleId; + } } await this.quit(); diff --git a/test/unit/wda/utils-specs.js b/test/unit/wda/utils-specs.js index c28fb27b4..0521ff732 100644 --- a/test/unit/wda/utils-specs.js +++ b/test/unit/wda/utils-specs.js @@ -1,4 +1,5 @@ -import { getXctestrunFilePath, getAdditionalRunContent, getXctestrunFileName } from '../../../lib/wda/utils'; +import { getXctestrunFilePath, getAdditionalRunContent, + getXctestrunFileName, getBundleIdFromInfoPlistPath } from '../../../lib/wda/utils'; import { PLATFORM_NAME_IOS, PLATFORM_NAME_TVOS } from '../../../lib/desired-caps'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; @@ -159,4 +160,38 @@ describe('utils', function () { 'WebDriverAgentRunner_tvOS_appletvsimulator10.2.0-x86_64.xctestrun'); }); }); + + describe('#getBundleIdFromInfoPlistPath', function () { + it('should return ios format, real device', function () { + const platformName = 'iOs'; + const deviceInfo = {isRealDevice: true, platformName}; + + getBundleIdFromInfoPlistPath(deviceInfo, 'path/to/build/product').endsWith( + 'path/to/build/product/Debug-iphoneos/WebDriverAgentRunner-Runner.app/Info.plist').should.be.true; + }); + + it('should return ios format, simulator', function () { + const platformName = 'ios'; + const deviceInfo = {isRealDevice: false, platformName}; + + getBundleIdFromInfoPlistPath(deviceInfo, 'path/to/build/product').endsWith( + 'path/to/build/product/Debug-iphonesimulator/WebDriverAgentRunner-Runner.app/Info.plist').should.be.true; + }); + + it('should return tvos format, real device', function () { + const platformName = 'tVos'; + const deviceInfo = {isRealDevice: true, platformName}; + + getBundleIdFromInfoPlistPath(deviceInfo, 'path/to/build/product').endsWith( + 'path/to/build/product/Debug-appletvos/WebDriverAgentRunner_tvOS-Runner.app/Info.plist').should.be.true; + }); + + it('should return tvos format, simulator', function () { + const platformName = 'tvOS'; + const deviceInfo = {isRealDevice: false, platformName}; + + getBundleIdFromInfoPlistPath(deviceInfo, 'path/to/build/product').endsWith( + 'path/to/build/product/Debug-appletvsimulator/WebDriverAgentRunner_tvOS-Runner.app/Info.plist').should.be.true; + }); + }); }); From 7c5e41d85cc90607e8d57388ba6504fe8bb0846c Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 28 Aug 2019 01:03:40 +0900 Subject: [PATCH 07/18] remove a line --- lib/wda/webdriveragent.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index b931faf0a..fe8420a35 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -414,8 +414,6 @@ class WebDriverAgent { * * If it fails to get 'await this.getStatus()', it will try to read * bundle id from plist by WDA. - * - * @param {string} updatedWDABundleId The bundle id which will be uninstalled */ async quitAndUninstall () { let bundleId = util.hasValue(this.updatedWDABundleId) From 24078cd18bf064301d28a79531e4625b26bcafe4 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 29 Aug 2019 22:29:46 +0900 Subject: [PATCH 08/18] get bundleid via ios-device, revert some implementations --- lib/wda/utils.js | 24 +- lib/wda/webdriveragent.js | 82 ++--- test/unit/wda/utils-specs.js | 36 +- test/unit/webdriveragent-specs.js | 584 +++++------------------------- 4 files changed, 130 insertions(+), 596 deletions(-) diff --git a/lib/wda/utils.js b/lib/wda/utils.js index 23ad83410..d640dca0d 100644 --- a/lib/wda/utils.js +++ b/lib/wda/utils.js @@ -211,29 +211,8 @@ function getXctestrunFileName (deviceInfo, version) { ? `WebDriverAgentRunner_tvOS_appletv${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun` : `WebDriverAgentRunner_iphone${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun`; } - - -/** - * Return the path of Info.plist file - * @param {DeviceInfo} deviceInfo - * @param {string} bootstrapPath - * @return {string} returns Info.plist file path - */ -function getBundleIdFromInfoPlistPath (deviceInfo, bootstrapPath) { - const infoPlist = isTvOS(deviceInfo.platformName) - ? `Debug-appletv${deviceInfo.isRealDevice ? 'os' : 'simulator'}/WebDriverAgentRunner_tvOS-Runner.app/Info.plist` - : `Debug-iphone${deviceInfo.isRealDevice ? 'os' : 'simulator'}/WebDriverAgentRunner-Runner.app/Info.plist`; - - return path.resolve(bootstrapPath, infoPlist); -} - -async function getCFBundleIdentifierFromPlist (deviceInfo, bootstrapPath) { - const parsedPlist = await plist.parsePlistFile( - getBundleIdFromInfoPlistPath(deviceInfo, bootstrapPath), false); - return parsedPlist.CFBundleIdentifier; -} - async function killProcess (name, proc) { + if (proc && proc.proc) { log.info(`Shutting down ${name} process (pid ${proc.proc.pid})`); try { @@ -284,7 +263,6 @@ async function getWDAUpgradeTimestamp (bootstrapPath) { export { updateProjectFile, resetProjectFile, setRealDeviceSecurity, fixForXcode9, getAdditionalRunContent, getXctestrunFileName, - getBundleIdFromInfoPlistPath, getCFBundleIdentifierFromPlist, generateXcodeConfigFile, setXctestrunFile, getXctestrunFilePath, killProcess, randomInt, getWDAUpgradeTimestamp, CARTHAGE_ROOT, }; diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index fe8420a35..64cb4fb70 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -5,18 +5,19 @@ import { JWProxy } from 'appium-base-driver'; import { fs, util } from 'appium-support'; import log from '../logger'; import { NoSessionProxy } from './no-session-proxy'; -import { getWDAUpgradeTimestamp, CARTHAGE_ROOT, getCFBundleIdentifierFromPlist } from './utils'; +import { getWDAUpgradeTimestamp, CARTHAGE_ROOT } from './utils'; import { resetXCTestProcesses, getPIDsListeningOnPort, isLocalHost } from '../utils'; import XcodeBuild from './xcodebuild'; import iProxy from './iproxy'; import { exec } from 'teen_process'; import AsyncLock from 'async-lock'; import { BOOTSTRAP_PATH, WDA_BUNDLE_ID, WDA_RUNNER_BUNDLE_ID, checkForDependencies } from 'appium-webdriveragent'; +import { services } from 'appium-ios-device'; const WDA_LAUNCH_TIMEOUT = 60 * 1000; const WDA_AGENT_PORT = 8100; const WDA_BASE_URL = 'http://localhost'; -const WDA_XCTRUNNER_SUFFIX = '.xctrunner'; +const WDA_CF_BUNDLE_NAME = 'WebDriverAgentRunner-Runner'; const SHARED_RESOURCES_GUARD = new AsyncLock(); @@ -158,27 +159,17 @@ class WebDriverAgent { } /** - * Uninstall WDA from the test device. - * If WDA is built by Xcode 10-, the bundle id is WDA_BUNDLE_ID. - * If WDA is build by Xcode 11, the bundle id is 'com.facebook.WebDriverAgentRunner.xctrunner' for simulator. - * 'com.customised.WDA.xctrunner' for real device if a user sets 'bundleId' as 'com.customised.WDA'. - * - * @param {string} bundleId The bundle id which will be uninstalled + * Uninstall WDAs from the test device. + * Over Xcode 11, multiple WDA can be in the device since Xcode 11 generates different WDA. + * Appium does not expect multiple WDAs are running on a device. */ - async uninstall (bundleId = WDA_RUNNER_BUNDLE_ID) { + async uninstall () { try { - // For (this.xcodeVersion && this.xcodeVersion.major < 11) - // this.xcodeVersion will be null when this.opts.webDriverAgentUrl is given. - // But webDriverAgentUrl has a value means users use their own WDA instead of this class. - // We can expect uninstall does not happen, in general. - // For Xcode 11+ - // On simulator, the bundle id should be 'com.facebook.WebDriverAgentRunner.xctrunner' - // even if 'updatedWDABundleId' was given - bundleId = (this.xcodeVersion && this.xcodeVersion.major < 11) - ? WDA_BUNDLE_ID - : `${this.realDevice ? bundleId : WDA_RUNNER_BUNDLE_ID}${WDA_XCTRUNNER_SUFFIX}`; - log.debug(`Removing WDA application from device: '${bundleId}'`); - await this.device.removeApp(bundleId); + const bundleIds = await this.getInstalledWDBundleId(); + log.debug(`Uninstalling ${bundleIds}`); + for (const bundleId of bundleIds) { + await this.device.removeApp(bundleId); + } } catch (e) { log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? Original error: ${JSON.stringify(e)}`); } @@ -383,7 +374,7 @@ class WebDriverAgent { // for real device if (util.hasValue(productBundleIdentifier) && util.hasValue(this.updatedWDABundleId) && this.updatedWDABundleId !== productBundleIdentifier) { log.info(`Will uninstall running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`); - return await this.uninstall(productBundleIdentifier); + return await this.uninstall(); } // for simulator if (util.hasValue(productBundleIdentifier) && !util.hasValue(this.updatedWDABundleId) && WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier) { @@ -397,7 +388,7 @@ class WebDriverAgent { if (actualUpgradeTimestamp && upgradedAt && _.toLower(`${actualUpgradeTimestamp}`) !== _.toLower(`${upgradedAt}`)) { log.info('Will uninstall running WDA since it has different version in comparison to the one ' + `which is bundled with appium-xcuitest-driver module (${actualUpgradeTimestamp} != ${upgradedAt})`); - return await this.uninstall(productBundleIdentifier); + return await this.uninstall(); } const message = util.hasValue(productBundleIdentifier) @@ -409,33 +400,34 @@ class WebDriverAgent { /** * Quit and uninstall running WDA. - * Uninstall given updatedWDABundleId, 'WDA_RUNNER_BUNDLE_ID' or running 'productBundleIdentifier - * for Xcode 11. Uninstall 'WDA_BUNDLE_ID' for Xcode 10-. - * - * If it fails to get 'await this.getStatus()', it will try to read - * bundle id from plist by WDA. */ async quitAndUninstall () { - let bundleId = util.hasValue(this.updatedWDABundleId) - ? this.updatedWDABundleId - : WDA_RUNNER_BUNDLE_ID; + await this.quit(); + await this.uninstall(); + } - const status = await this.getStatus(); - if (status && status.build) { - const { productBundleIdentifier } = status.build; - if (util.hasValue(productBundleIdentifier)) { - bundleId = productBundleIdentifier; - } - } else { - const parsedBundleId = await getCFBundleIdentifierFromPlist( - {isRealDevice: this.isRealDevice, platformName: this.platformName}, this.bootstrapPath); - if (util.hasValue(parsedBundleId)) { - bundleId = parsedBundleId; + /** + * Get WDA bundleIds installed in the target device. + * Over Xcode 11, multiple WDA can be in a device since Xcode 11 + * set their bundleIds as 'xxxxxx.xctrunner'. + * + * @returns {Array} A list of User level apps' bundle ids which has + * 'CFBundleName' attribute as 'WebDriverAgentRunner-Runner'. + */ + async getInstalledWDBundleId () { + const service = await services.startInstallationProxyService(this.device.udid); + try { + const applications = await service.listApplications({applicationType: 'User'}); + const bundleIds = []; + for (const [key, value] of Object.entries(applications)) { + if (value.CFBundleName === WDA_CF_BUNDLE_NAME) { + bundleIds.push(key); + } } + return bundleIds; + } finally { + service.close(); } - - await this.quit(); - await this.uninstall(bundleId); } } diff --git a/test/unit/wda/utils-specs.js b/test/unit/wda/utils-specs.js index 0521ff732..a950ddc62 100644 --- a/test/unit/wda/utils-specs.js +++ b/test/unit/wda/utils-specs.js @@ -1,5 +1,5 @@ import { getXctestrunFilePath, getAdditionalRunContent, - getXctestrunFileName, getBundleIdFromInfoPlistPath } from '../../../lib/wda/utils'; + getXctestrunFileName } from '../../../lib/wda/utils'; import { PLATFORM_NAME_IOS, PLATFORM_NAME_TVOS } from '../../../lib/desired-caps'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; @@ -160,38 +160,4 @@ describe('utils', function () { 'WebDriverAgentRunner_tvOS_appletvsimulator10.2.0-x86_64.xctestrun'); }); }); - - describe('#getBundleIdFromInfoPlistPath', function () { - it('should return ios format, real device', function () { - const platformName = 'iOs'; - const deviceInfo = {isRealDevice: true, platformName}; - - getBundleIdFromInfoPlistPath(deviceInfo, 'path/to/build/product').endsWith( - 'path/to/build/product/Debug-iphoneos/WebDriverAgentRunner-Runner.app/Info.plist').should.be.true; - }); - - it('should return ios format, simulator', function () { - const platformName = 'ios'; - const deviceInfo = {isRealDevice: false, platformName}; - - getBundleIdFromInfoPlistPath(deviceInfo, 'path/to/build/product').endsWith( - 'path/to/build/product/Debug-iphonesimulator/WebDriverAgentRunner-Runner.app/Info.plist').should.be.true; - }); - - it('should return tvos format, real device', function () { - const platformName = 'tVos'; - const deviceInfo = {isRealDevice: true, platformName}; - - getBundleIdFromInfoPlistPath(deviceInfo, 'path/to/build/product').endsWith( - 'path/to/build/product/Debug-appletvos/WebDriverAgentRunner_tvOS-Runner.app/Info.plist').should.be.true; - }); - - it('should return tvos format, simulator', function () { - const platformName = 'tvOS'; - const deviceInfo = {isRealDevice: false, platformName}; - - getBundleIdFromInfoPlistPath(deviceInfo, 'path/to/build/product').endsWith( - 'path/to/build/product/Debug-appletvsimulator/WebDriverAgentRunner_tvOS-Runner.app/Info.plist').should.be.true; - }); - }); }); diff --git a/test/unit/webdriveragent-specs.js b/test/unit/webdriveragent-specs.js index d7384c049..060cd701e 100644 --- a/test/unit/webdriveragent-specs.js +++ b/test/unit/webdriveragent-specs.js @@ -110,538 +110,136 @@ describe('get url', function () { }); describe('setupCaching()', function () { - let opts = {}; let wda; let wdaStub; - let wdaStubRemoveApp; - let wdaDevice; + let wdaStubUninstall; const getTimestampStub = sinon.stub(utils, 'getWDAUpgradeTimestamp'); - describe('Xcode 10, simulator', function () { - beforeEach(function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - }); - - afterEach(function () { - for (const stub of [wdaStub, wdaStubRemoveApp, getTimestampStub]) { - if (stub) { - stub.reset(); - } - } - }); - - it('should not call uninstall since no Running WDA', async function () { - wdaStub.callsFake(function () { - return null; - }); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); - - it('should not call uninstall since running WDA has only time', async function () { - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21' }}; - }); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); - }); - - it('should call uninstall once since bundle id is not default without updatedWDABundleId capability', async function () { - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; - }); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); - - it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'com.example.WebDriverAgent'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }}; - }); - - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); - - it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'com.example.WebDriverAgent'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; - }); - - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); - }); - - it('should call uninstall default bundle id if current revision differs from the bundled one', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; - }); - getTimestampStub.callsFake(() => '2'); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; - }); - - it('should call uninstall default bundle id if current revision differs from the bundled one and running productBundleIdentifier is default value', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1', productBundleIdentifier: 'com.facebook.WebDriverAgentRunner' }}; - }); - getTimestampStub.callsFake(() => '2'); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; - }); - - it('should not call uninstall if current revision is the same as the bundled one', async function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'something'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; - }); - getTimestampStub.callsFake(() => '1'); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - }); - - it('should not call uninstall if current revision cannot be retrieved from WDA status', async function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'something'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - - wdaStub.callsFake(function () { - return {build: {}}; - }); - getTimestampStub.callsFake(() => '1'); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - }); - - it('should not call uninstall if current revision cannot be retrieved from the file system', async function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'something'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; - }); - getTimestampStub.callsFake(() => null); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - }); + beforeEach(function () { + wda = new WebDriverAgent('1'); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubUninstall = sinon.stub(wda, 'uninstall'); }); - describe('Xcode 11, real device', function () { - beforeEach(function () { - opts = {}; - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - }); - - afterEach(function () { - opts = {}; - for (const stub of [wdaStub, wdaStubRemoveApp, getTimestampStub]) { - if (stub) { - stub.reset(); - } + afterEach(function () { + for (const stub of [wdaStub, wdaStubUninstall, getTimestampStub]) { + if (stub) { + stub.reset(); } - }); - - it('should not call uninstall since no Running WDA', async function () { - wdaStub.callsFake(function () { - return null; - }); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(opts.updatedWDABundleId); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); - - it('should not call uninstall since running WDA has only time', async function () { - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21' }}; - }); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(opts.updatedWDABundleId); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); - }); - - it('should call uninstall once since bundle id is not default without updatedWDABundleId capability', async function () { - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; - }); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(opts.updatedWDABundleId); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); - - it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true, updatedWDABundleId: 'com.example.WebDriverAgent'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }}; - }); - - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.example.different.WebDriverAgent.xctrunner').calledOnce.should.be.true; - _.isUndefined(wda.webDriverAgentUrl).should.be.true; - }); - - it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true, updatedWDABundleId: 'com.example.WebDriverAgent'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; - }); - - wdaStubRemoveApp.callsFake(_.noop); - - await wda.setupCaching(); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); - }); - - it('should call uninstall default bundle id if current revision differs from the bundled one', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; - }); - getTimestampStub.callsFake(() => '2'); - wdaStubRemoveApp.callsFake(_.noop); + } + }); - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + it('should not call uninstall since no Running WDA', async function () { + wdaStub.callsFake(function () { + return null; }); + wdaStubUninstall.callsFake(_.noop); - it('should call uninstall default bundle id if current revision differs from the bundled one and running productBundleIdentifier is default value', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1', productBundleIdentifier: 'com.facebook.WebDriverAgentRunner' }}; - }); - getTimestampStub.callsFake(() => '2'); - wdaStubRemoveApp.callsFake(_.noop); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.notCalled.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; + }); - await wda.setupCaching(opts.updatedWDABundleId); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + it('should not call uninstall since running WDA has only time', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21' }}; }); + wdaStubUninstall.callsFake(_.noop); - it('should not call uninstall if current revision is the same as the bundled one', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; - }); - getTimestampStub.callsFake(() => '1'); - wdaStubRemoveApp.callsFake(_.noop); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.notCalled.should.be.true; + wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); + }); - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; + it('should call uninstall once since bundle id is not default without updatedWDABundleId capability', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; }); + wdaStubUninstall.callsFake(_.noop); - it('should not call uninstall if current revision cannot be retrieved from WDA status', async function () { - wdaStub.callsFake(function () { - return {build: {}}; - }); - getTimestampStub.callsFake(() => '1'); - wdaStubRemoveApp.callsFake(_.noop); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.calledOnce.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; + }); - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; + it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () { + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }}; }); - it('should not call uninstall if current revision cannot be retrieved from the file system', async function () { - wdaStub.callsFake(function () { - return {build: { upgradedAt: '1' }}; - }); - getTimestampStub.callsFake(() => null); - wdaStubRemoveApp.callsFake(_.noop); + wdaStubUninstall.callsFake(_.noop); - await wda.setupCaching('something'); - wdaStub.calledOnce.should.be.true; - wdaStubRemoveApp.notCalled.should.be.true; - }); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.calledOnce.should.be.true; + _.isUndefined(wda.webDriverAgentUrl).should.be.true; }); -}); - -describe('quitAndUninstall()', function () { - let opts = {}; - let wda; - let wdaStub; - let wdaStubRemoveApp; - let wdaStubQuit; - let wdaDevice; - - - describe('with Xcode 10, Simulator', function () { - beforeEach(function () { - opts = {}; - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 10}, {device: wdaDevice, realDevice: false}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubQuit = sinon.stub(wda, 'quit'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - }); - afterEach(function () { - opts = {}; - for (const stub of [wdaStub, wdaStubQuit, wdaStubRemoveApp]) { - if (stub) { - stub.reset(); - } - } - }); - - it('should uninstall default app since no Running WDA and no updatedWDABundleId', async function () { - wdaStub.callsFake(function () { - return null; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; - }); + it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () { + wda = new WebDriverAgent('1', { updatedWDABundleId: 'com.example.WebDriverAgent' }); + wdaStub = sinon.stub(wda, 'getStatus'); + wdaStubUninstall = sinon.stub(wda, 'uninstall'); - it('should uninstall updatedWDABundleId with no running WDA', async function () { - opts.updatedWDABundleId = 'com.example.WebDriverAgent'; - wdaStub.callsFake(function () { - return null; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; + wdaStub.callsFake(function () { + return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }}; }); - it('should uninstall productBundleIdentifier prior than updatedWDABundleId', async function () { - opts.updatedWDABundleId = 'com.example.updatedWDABundleId.WebDriverAgent'; - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.productBundleIdentifier.WebDriverAgent' }}; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; - }); + wdaStubUninstall.callsFake(_.noop); - it('should uninstall productBundleIdentifier', async function () { - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.productBundleIdentifier.WebDriverAgent' }}; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.apple.test.WebDriverAgentRunner-Runner').calledOnce.should.be.true; - }); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.notCalled.should.be.true; + wda.webDriverAgentUrl.should.equal('http://localhost:8100/'); }); - describe('with Xcode 11, real device', function () { - beforeEach(function () { - opts = {}; - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubQuit = sinon.stub(wda, 'quit'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - }); - - afterEach(function () { - opts = {}; - for (const stub of [wdaStub, wdaStubQuit, wdaStubRemoveApp]) { - if (stub) { - stub.reset(); - } - } - }); - - it('should uninstall default app since no Running WDA and no updatedWDABundleId', async function () { - wdaStub.callsFake(function () { - return null; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + it('should call uninstall if current revision differs from the bundled one', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; }); + getTimestampStub.callsFake(() => '2'); + wdaStubUninstall.callsFake(_.noop); - it('should uninstall updatedWDABundleId with no running WDA', async function () { - // override - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: true, updatedWDABundleId: 'com.example.WebDriverAgent'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubQuit = sinon.stub(wda, 'quit'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - wdaStub.callsFake(function () { - return null; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.example.WebDriverAgent.xctrunner').calledOnce.should.be.true; - }); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.calledOnce.should.be.true; + }); - it('should uninstall productBundleIdentifier prior than updatedWDABundleId', async function () { - opts.updatedWDABundleId = 'com.example.updatedWDABundleId.WebDriverAgent'; - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.productBundleIdentifier.WebDriverAgent' }}; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.example.productBundleIdentifier.WebDriverAgent.xctrunner').calledOnce.should.be.true; + it('should not call uninstall if current revision is the same as the bundled one', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; }); + getTimestampStub.callsFake(() => '1'); + wdaStubUninstall.callsFake(_.noop); - it('should uninstall productBundleIdentifier', async function () { - wdaStub.callsFake(function () { - return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.productBundleIdentifier.WebDriverAgent' }}; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.example.productBundleIdentifier.WebDriverAgent.xctrunner').calledOnce.should.be.true; - }); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.notCalled.should.be.true; }); - describe('with Xcode 11, simulator', function () { - beforeEach(function () { - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: false}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubQuit = sinon.stub(wda, 'quit'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); + it('should not call uninstall if current revision cannot be retrieved from WDA status', async function () { + wdaStub.callsFake(function () { + return {build: {}}; }); + getTimestampStub.callsFake(() => '1'); + wdaStubUninstall.callsFake(_.noop); - afterEach(function () { - for (const stub of [wdaStub, wdaStubQuit, wdaStubRemoveApp]) { - if (stub) { - stub.reset(); - } - } - }); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.notCalled.should.be.true; + }); - it('should uninstall default app since no Running WDA and no updatedWDABundleId', async function () { - wdaStub.callsFake(function () { - return null; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; + it('should not call uninstall if current revision cannot be retrieved from the file system', async function () { + wdaStub.callsFake(function () { + return {build: { upgradedAt: '1' }}; }); + getTimestampStub.callsFake(() => null); + wdaStubUninstall.callsFake(_.noop); - it('should uninstall updatedWDABundleId with no running WDA', async function () { - // override - wdaDevice = { removeApp: () => {} }; - wda = new WebDriverAgent({major: 11}, {device: wdaDevice, realDevice: false, updatedWDABundleId: 'com.example.WebDriverAgent'}); - wdaStub = sinon.stub(wda, 'getStatus'); - wdaStubQuit = sinon.stub(wda, 'quit'); - wdaStubRemoveApp = sinon.stub(wdaDevice, 'removeApp'); - - wdaStub.callsFake(function () { - return null; - }); - wdaStubQuit.callsFake(_.noop); - wdaStubRemoveApp.callsFake(_.noop); - - await wda.quitAndUninstall(); - wdaStub.calledOnce.should.be.true; - wdaStubQuit.calledOnce.should.be.true; - wdaStubRemoveApp.withArgs('com.facebook.WebDriverAgentRunner.xctrunner').calledOnce.should.be.true; - }); + await wda.setupCaching(); + wdaStub.calledOnce.should.be.true; + wdaStubUninstall.notCalled.should.be.true; }); }); From 6c8523be14a8977e393701d12d65764915044a5a Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 29 Aug 2019 23:12:26 +0900 Subject: [PATCH 09/18] add get bundlids for simulator --- lib/real-device-management.js | 22 +++++++++++++++++++-- lib/simulator-management.js | 12 +++++++++++- lib/wda/webdriveragent.js | 36 +++++++++++++++++------------------ 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/lib/real-device-management.js b/lib/real-device-management.js index facac5e95..66e5f0c3a 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -1,4 +1,4 @@ -import { utilities } from 'appium-ios-device'; +import { utilities, services } from 'appium-ios-device'; import IOSDeploy from './ios-deploy'; import log from './logger'; @@ -66,5 +66,23 @@ function getRealDeviceObj (udid) { return new IOSDeploy(udid); } + +async function getIBundleIdsByCFBundleName (device, cFBundleName) { + const service = await services.startInstallationProxyService(device.udid); + try { + const applications = await service.listApplications({applicationType: 'User'}); + const bundleIds = []; + for (const [key, value] of Object.entries(applications)) { + if (value.CFBundleName === cFBundleName) { + bundleIds.push(key); + } + } + return bundleIds; + } finally { + service.close(); + } +} + + export { getConnectedDevices, getOSVersion, runRealDeviceReset, installToRealDevice, - getRealDeviceObj }; + getRealDeviceObj, getIBundleIdsByCFBundleName }; diff --git a/lib/simulator-management.js b/lib/simulator-management.js index 45bfe9fb7..270bdf97f 100644 --- a/lib/simulator-management.js +++ b/lib/simulator-management.js @@ -214,5 +214,15 @@ async function shutdownOtherSimulators (currentDevice) { } } +async function getInstalledBundleIds (device, candidateBundleIds) { + const bundleIds = []; + for (const bundleId of candidateBundleIds) { + if (await device.isAppInstalled(bundleId)) { + bundleIds.push(bundleId); + } + } + return bundleIds; +} + export { createSim, getExistingSim, runSimulatorReset, installToSimulator, - shutdownSimulator, shutdownOtherSimulators }; + shutdownSimulator, shutdownOtherSimulators, getInstalledBundleIds }; diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index 64cb4fb70..04ddc94f3 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -12,12 +12,14 @@ import iProxy from './iproxy'; import { exec } from 'teen_process'; import AsyncLock from 'async-lock'; import { BOOTSTRAP_PATH, WDA_BUNDLE_ID, WDA_RUNNER_BUNDLE_ID, checkForDependencies } from 'appium-webdriveragent'; -import { services } from 'appium-ios-device'; +import { getIBundleIdsByCFBundleName } from '../real-device-management'; +import { getInstalledBundleIds } from '../simulator-management'; const WDA_LAUNCH_TIMEOUT = 60 * 1000; const WDA_AGENT_PORT = 8100; const WDA_BASE_URL = 'http://localhost'; const WDA_CF_BUNDLE_NAME = 'WebDriverAgentRunner-Runner'; +const WDA_BUNDLE_ID_XCODE11 = 'com.facebook.WebDriverAgentRunner.xctrunner'; // FIXME: Move to appium-webdriveragent const SHARED_RESOURCES_GUARD = new AsyncLock(); @@ -33,7 +35,7 @@ class WebDriverAgent { this.platformName = args.platformName; this.iosSdkVersion = args.iosSdkVersion; this.host = args.host; - this.realDevice = !!args.realDevice; + this.isRealDevice = !!args.realDevice; this.setWDAPaths(args.bootstrapPath, args.agentPath); @@ -62,7 +64,7 @@ class WebDriverAgent { iosSdkVersion: this.iosSdkVersion, agentPath: this.agentPath, bootstrapPath: this.bootstrapPath, - realDevice: this.realDevice, + realDevice: this.isRealDevice, showXcodeLog: args.showXcodeLog, xcodeConfigFile: args.xcodeConfigFile, xcodeOrgId: args.xcodeOrgId, @@ -73,7 +75,7 @@ class WebDriverAgent { usePrebuiltWDA: args.usePrebuiltWDA, updatedWDABundleId: this.updatedWDABundleId, launchTimeout: args.wdaLaunchTimeout || WDA_LAUNCH_TIMEOUT, - wdaRemotePort: this.realDevice ? WDA_AGENT_PORT : (this.wdaLocalPort || WDA_AGENT_PORT), + wdaRemotePort: this.isRealDevice ? WDA_AGENT_PORT : (this.wdaLocalPort || WDA_AGENT_PORT), useXctestrunFile: this.useXctestrunFile, derivedDataPath: args.derivedDataPath, mjpegServerPort: args.mjpegServerPort, @@ -166,7 +168,12 @@ class WebDriverAgent { async uninstall () { try { const bundleIds = await this.getInstalledWDBundleId(); - log.debug(`Uninstalling ${bundleIds}`); + if (_.isEmpty(bundleIds)) { + log.debug('No WDAs on the device.'); + return; + } + + log.debug(`Uninstalling WDAs: '${bundleIds}'`); for (const bundleId of bundleIds) { await this.device.removeApp(bundleId); } @@ -232,7 +239,7 @@ class WebDriverAgent { }); } // We need to provide WDA local port, because it might be occupied with - await resetXCTestProcesses(this.device.udid, !this.realDevice); + await resetXCTestProcesses(this.device.udid, !this.isRealDevice); await this.ensureConnection(); @@ -289,7 +296,7 @@ class WebDriverAgent { } async ensureConnection () { - if (!this.realDevice || this.webDriverAgentUrl || this.iproxy) { + if (!this.isRealDevice || this.webDriverAgentUrl || this.iproxy) { return; } if (isLocalHost(this.wdaBaseUrl)) { @@ -415,19 +422,10 @@ class WebDriverAgent { * 'CFBundleName' attribute as 'WebDriverAgentRunner-Runner'. */ async getInstalledWDBundleId () { - const service = await services.startInstallationProxyService(this.device.udid); - try { - const applications = await service.listApplications({applicationType: 'User'}); - const bundleIds = []; - for (const [key, value] of Object.entries(applications)) { - if (value.CFBundleName === WDA_CF_BUNDLE_NAME) { - bundleIds.push(key); - } - } - return bundleIds; - } finally { - service.close(); + if (this.isRealDevice) { + return await getIBundleIdsByCFBundleName(this.device, WDA_CF_BUNDLE_NAME); } + return await getInstalledBundleIds(this.device, [WDA_BUNDLE_ID, WDA_BUNDLE_ID_XCODE11]); } } From 014267557682a59518d8f031fb3542a9369f1715 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 29 Aug 2019 23:48:07 +0900 Subject: [PATCH 10/18] tweak docstring --- lib/real-device-management.js | 11 +++++++++++ lib/wda/utils.js | 1 - test/unit/wda/utils-specs.js | 3 +-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/real-device-management.js b/lib/real-device-management.js index 66e5f0c3a..5c3eafa17 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -66,7 +66,18 @@ function getRealDeviceObj (udid) { return new IOSDeploy(udid); } +/** + * @typedef {Object} RealDevice + * @param {string} udid The udid of the target device + */ +/** + * @param {RealDevice} The real device object which has 'udid' attribute + * @param {string} cFBundleName The name of CFBundleName in Info.plist + * + * @returns {Array} A list of User level apps' bundle ids which has + * 'CFBundleName' attribute as 'cFBundleName'. + */ async function getIBundleIdsByCFBundleName (device, cFBundleName) { const service = await services.startInstallationProxyService(device.udid); try { diff --git a/lib/wda/utils.js b/lib/wda/utils.js index d640dca0d..0302d65dc 100644 --- a/lib/wda/utils.js +++ b/lib/wda/utils.js @@ -212,7 +212,6 @@ function getXctestrunFileName (deviceInfo, version) { : `WebDriverAgentRunner_iphone${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun`; } async function killProcess (name, proc) { - if (proc && proc.proc) { log.info(`Shutting down ${name} process (pid ${proc.proc.pid})`); try { diff --git a/test/unit/wda/utils-specs.js b/test/unit/wda/utils-specs.js index a950ddc62..c28fb27b4 100644 --- a/test/unit/wda/utils-specs.js +++ b/test/unit/wda/utils-specs.js @@ -1,5 +1,4 @@ -import { getXctestrunFilePath, getAdditionalRunContent, - getXctestrunFileName } from '../../../lib/wda/utils'; +import { getXctestrunFilePath, getAdditionalRunContent, getXctestrunFileName } from '../../../lib/wda/utils'; import { PLATFORM_NAME_IOS, PLATFORM_NAME_TVOS } from '../../../lib/desired-caps'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; From c7beac73adaae1d9ce04a4dbb7ee28b590686ee6 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 29 Aug 2019 23:51:09 +0900 Subject: [PATCH 11/18] tweak control flow --- lib/wda/webdriveragent.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index 04ddc94f3..c1e12cdfe 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -418,14 +418,12 @@ class WebDriverAgent { * Over Xcode 11, multiple WDA can be in a device since Xcode 11 * set their bundleIds as 'xxxxxx.xctrunner'. * - * @returns {Array} A list of User level apps' bundle ids which has - * 'CFBundleName' attribute as 'WebDriverAgentRunner-Runner'. + * @returns {Array} A list of User level apps' bundle ids. */ async getInstalledWDBundleId () { - if (this.isRealDevice) { - return await getIBundleIdsByCFBundleName(this.device, WDA_CF_BUNDLE_NAME); - } - return await getInstalledBundleIds(this.device, [WDA_BUNDLE_ID, WDA_BUNDLE_ID_XCODE11]); + return this.isRealDevice + ? await getIBundleIdsByCFBundleName(this.device, WDA_CF_BUNDLE_NAME) + : await getInstalledBundleIds(this.device, [WDA_BUNDLE_ID, WDA_BUNDLE_ID_XCODE11]); } } From ba1c56dbfb748544ae0f0828bef2fa6cede0f6e6 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 29 Aug 2019 23:56:19 +0900 Subject: [PATCH 12/18] fix reviews --- lib/real-device-management.js | 12 ++++++------ lib/wda/webdriveragent.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/real-device-management.js b/lib/real-device-management.js index 5c3eafa17..13c9d00f3 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -72,19 +72,19 @@ function getRealDeviceObj (udid) { */ /** - * @param {RealDevice} The real device object which has 'udid' attribute - * @param {string} cFBundleName The name of CFBundleName in Info.plist + * @param {RealDevice} device The real device object which has 'udid' attribute + * @param {string} bundleName The name of CFBundleName in Info.plist * * @returns {Array} A list of User level apps' bundle ids which has - * 'CFBundleName' attribute as 'cFBundleName'. + * 'CFBundleName' attribute as 'bundleName'. */ -async function getIBundleIdsByCFBundleName (device, cFBundleName) { +async function getBundleIdsByBundleName (device, bundleName) { const service = await services.startInstallationProxyService(device.udid); try { const applications = await service.listApplications({applicationType: 'User'}); const bundleIds = []; for (const [key, value] of Object.entries(applications)) { - if (value.CFBundleName === cFBundleName) { + if (value.CFBundleName === bundleName) { bundleIds.push(key); } } @@ -96,4 +96,4 @@ async function getIBundleIdsByCFBundleName (device, cFBundleName) { export { getConnectedDevices, getOSVersion, runRealDeviceReset, installToRealDevice, - getRealDeviceObj, getIBundleIdsByCFBundleName }; + getRealDeviceObj, getBundleIdsByBundleName }; diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index c1e12cdfe..cb704699a 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -12,7 +12,7 @@ import iProxy from './iproxy'; import { exec } from 'teen_process'; import AsyncLock from 'async-lock'; import { BOOTSTRAP_PATH, WDA_BUNDLE_ID, WDA_RUNNER_BUNDLE_ID, checkForDependencies } from 'appium-webdriveragent'; -import { getIBundleIdsByCFBundleName } from '../real-device-management'; +import { getBundleIdsByBundleName } from '../real-device-management'; import { getInstalledBundleIds } from '../simulator-management'; const WDA_LAUNCH_TIMEOUT = 60 * 1000; @@ -422,7 +422,7 @@ class WebDriverAgent { */ async getInstalledWDBundleId () { return this.isRealDevice - ? await getIBundleIdsByCFBundleName(this.device, WDA_CF_BUNDLE_NAME) + ? await getBundleIdsByBundleName(this.device, WDA_CF_BUNDLE_NAME) : await getInstalledBundleIds(this.device, [WDA_BUNDLE_ID, WDA_BUNDLE_ID_XCODE11]); } } From fa771f99c35abf86df5f58c68537a31ef398fdb1 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 30 Aug 2019 00:28:04 +0900 Subject: [PATCH 13/18] use bluebird for async for --- lib/real-device-management.js | 13 ++++++------- lib/simulator-management.js | 5 +++-- lib/wda/webdriveragent.js | 5 +++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/real-device-management.js b/lib/real-device-management.js index 13c9d00f3..05f3fac9f 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -1,7 +1,7 @@ import { utilities, services } from 'appium-ios-device'; import IOSDeploy from './ios-deploy'; import log from './logger'; - +import _ from 'lodash'; async function getConnectedDevices () { return await utilities.getConnectedDevices(); @@ -82,13 +82,12 @@ async function getBundleIdsByBundleName (device, bundleName) { const service = await services.startInstallationProxyService(device.udid); try { const applications = await service.listApplications({applicationType: 'User'}); - const bundleIds = []; - for (const [key, value] of Object.entries(applications)) { - if (value.CFBundleName === bundleName) { - bundleIds.push(key); + return _.reduce(applications, (acc, {CFBundleName}, key) => { + if (CFBundleName === bundleName) { + acc.push(key); } - } - return bundleIds; + return acc; + }, []); } finally { service.close(); } diff --git a/lib/simulator-management.js b/lib/simulator-management.js index 270bdf97f..d1e6370cf 100644 --- a/lib/simulator-management.js +++ b/lib/simulator-management.js @@ -1,3 +1,4 @@ +import B from 'bluebird'; import path from 'path'; import { getSimulator } from 'appium-ios-simulator'; import { createDevice, getDevices, terminate, shutdown } from 'node-simctl'; @@ -216,11 +217,11 @@ async function shutdownOtherSimulators (currentDevice) { async function getInstalledBundleIds (device, candidateBundleIds) { const bundleIds = []; - for (const bundleId of candidateBundleIds) { + await B.filter(candidateBundleIds, async (bundleId) => { if (await device.isAppInstalled(bundleId)) { bundleIds.push(bundleId); } - } + }); return bundleIds; } diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index cb704699a..f45b822e7 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -1,3 +1,4 @@ +import B from 'bluebird'; import _ from 'lodash'; import path from 'path'; import url from 'url'; @@ -174,9 +175,9 @@ class WebDriverAgent { } log.debug(`Uninstalling WDAs: '${bundleIds}'`); - for (const bundleId of bundleIds) { + await B.each(bundleIds, async (bundleId) => { await this.device.removeApp(bundleId); - } + }); } catch (e) { log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? Original error: ${JSON.stringify(e)}`); } From df279bd486e82679df0e1bddd61247e001c1c47b Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 30 Aug 2019 13:27:26 +0900 Subject: [PATCH 14/18] fix review --- lib/simulator-management.js | 8 +------- lib/wda/webdriveragent.js | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/simulator-management.js b/lib/simulator-management.js index d1e6370cf..40793a087 100644 --- a/lib/simulator-management.js +++ b/lib/simulator-management.js @@ -216,13 +216,7 @@ async function shutdownOtherSimulators (currentDevice) { } async function getInstalledBundleIds (device, candidateBundleIds) { - const bundleIds = []; - await B.filter(candidateBundleIds, async (bundleId) => { - if (await device.isAppInstalled(bundleId)) { - bundleIds.push(bundleId); - } - }); - return bundleIds; + return await B.filter(candidateBundleIds, async (bundleId) => await device.isAppInstalled(bundleId)); } export { createSim, getExistingSim, runSimulatorReset, installToSimulator, diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index f45b822e7..e55a95096 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -168,7 +168,7 @@ class WebDriverAgent { */ async uninstall () { try { - const bundleIds = await this.getInstalledWDBundleId(); + const bundleIds = await this.getInstalledWDBundleIds(); if (_.isEmpty(bundleIds)) { log.debug('No WDAs on the device.'); return; @@ -421,7 +421,7 @@ class WebDriverAgent { * * @returns {Array} A list of User level apps' bundle ids. */ - async getInstalledWDBundleId () { + async getInstalledWDBundleIds () { return this.isRealDevice ? await getBundleIdsByBundleName(this.device, WDA_CF_BUNDLE_NAME) : await getInstalledBundleIds(this.device, [WDA_BUNDLE_ID, WDA_BUNDLE_ID_XCODE11]); From cbd37451ba15e9ca9e778e5e80bd1d90816a2d6c Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 30 Aug 2019 15:41:52 +0900 Subject: [PATCH 15/18] move getBundleIdsByBundleName to iosdeploy --- lib/ios-deploy.js | 22 ++++++++++++++++++++++ lib/real-device-management.js | 32 ++------------------------------ lib/wda/webdriveragent.js | 4 ++-- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/lib/ios-deploy.js b/lib/ios-deploy.js index 4be94964d..89fb38f2e 100644 --- a/lib/ios-deploy.js +++ b/lib/ios-deploy.js @@ -4,6 +4,7 @@ import path from 'path'; import { services } from 'appium-ios-device'; import B from 'bluebird'; import log from './logger'; +import _ from 'lodash'; const APPLICATION_INSTALLED_NOTIFICATION = 'com.apple.mobile.application_installed'; const INSTALLATION_STAGING_DIR = 'PublicStaging'; @@ -125,6 +126,27 @@ class IOSDeploy { service.close(); } } + + /** + * @param {string} bundleName The name of CFBundleName in Info.plist + * + * @returns {Array} A list of User level apps' bundle ids which has + * 'CFBundleName' attribute as 'bundleName'. + */ + async getBundleIdsByBundleName (bundleName) { + const service = await services.startInstallationProxyService(this.udid); + try { + const applications = await service.listApplications({applicationType: 'User'}); + return _.reduce(applications, (acc, {CFBundleName}, key) => { + if (CFBundleName === bundleName) { + acc.push(key); + } + return acc; + }, []); + } finally { + service.close(); + } + } } export default IOSDeploy; diff --git a/lib/real-device-management.js b/lib/real-device-management.js index 05f3fac9f..2649b2e25 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -1,7 +1,6 @@ -import { utilities, services } from 'appium-ios-device'; +import { utilities } from 'appium-ios-device'; import IOSDeploy from './ios-deploy'; import log from './logger'; -import _ from 'lodash'; async function getConnectedDevices () { return await utilities.getConnectedDevices(); @@ -66,33 +65,6 @@ function getRealDeviceObj (udid) { return new IOSDeploy(udid); } -/** - * @typedef {Object} RealDevice - * @param {string} udid The udid of the target device - */ - -/** - * @param {RealDevice} device The real device object which has 'udid' attribute - * @param {string} bundleName The name of CFBundleName in Info.plist - * - * @returns {Array} A list of User level apps' bundle ids which has - * 'CFBundleName' attribute as 'bundleName'. - */ -async function getBundleIdsByBundleName (device, bundleName) { - const service = await services.startInstallationProxyService(device.udid); - try { - const applications = await service.listApplications({applicationType: 'User'}); - return _.reduce(applications, (acc, {CFBundleName}, key) => { - if (CFBundleName === bundleName) { - acc.push(key); - } - return acc; - }, []); - } finally { - service.close(); - } -} - export { getConnectedDevices, getOSVersion, runRealDeviceReset, installToRealDevice, - getRealDeviceObj, getBundleIdsByBundleName }; + getRealDeviceObj }; diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index e55a95096..75e51d4b3 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -10,10 +10,10 @@ import { getWDAUpgradeTimestamp, CARTHAGE_ROOT } from './utils'; import { resetXCTestProcesses, getPIDsListeningOnPort, isLocalHost } from '../utils'; import XcodeBuild from './xcodebuild'; import iProxy from './iproxy'; +import iOSDeploy from '../ios-deploy'; import { exec } from 'teen_process'; import AsyncLock from 'async-lock'; import { BOOTSTRAP_PATH, WDA_BUNDLE_ID, WDA_RUNNER_BUNDLE_ID, checkForDependencies } from 'appium-webdriveragent'; -import { getBundleIdsByBundleName } from '../real-device-management'; import { getInstalledBundleIds } from '../simulator-management'; const WDA_LAUNCH_TIMEOUT = 60 * 1000; @@ -423,7 +423,7 @@ class WebDriverAgent { */ async getInstalledWDBundleIds () { return this.isRealDevice - ? await getBundleIdsByBundleName(this.device, WDA_CF_BUNDLE_NAME) + ? await iOSDeploy(this.device.udid).getBundleIdsByBundleName(WDA_CF_BUNDLE_NAME) : await getInstalledBundleIds(this.device, [WDA_BUNDLE_ID, WDA_BUNDLE_ID_XCODE11]); } } From 91c31b2047164d22f4e031234a2488eb6d2d3e3f Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 30 Aug 2019 15:54:30 +0900 Subject: [PATCH 16/18] back to for of syntax, tweak method name --- lib/ios-deploy.js | 2 +- lib/wda/webdriveragent.js | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/ios-deploy.js b/lib/ios-deploy.js index 89fb38f2e..d16febfdc 100644 --- a/lib/ios-deploy.js +++ b/lib/ios-deploy.js @@ -133,7 +133,7 @@ class IOSDeploy { * @returns {Array} A list of User level apps' bundle ids which has * 'CFBundleName' attribute as 'bundleName'. */ - async getBundleIdsByBundleName (bundleName) { + async getUserInstalledBundleIdsByBundleName (bundleName) { const service = await services.startInstallationProxyService(this.udid); try { const applications = await service.listApplications({applicationType: 'User'}); diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index 75e51d4b3..06c76f33e 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -1,4 +1,3 @@ -import B from 'bluebird'; import _ from 'lodash'; import path from 'path'; import url from 'url'; @@ -10,7 +9,6 @@ import { getWDAUpgradeTimestamp, CARTHAGE_ROOT } from './utils'; import { resetXCTestProcesses, getPIDsListeningOnPort, isLocalHost } from '../utils'; import XcodeBuild from './xcodebuild'; import iProxy from './iproxy'; -import iOSDeploy from '../ios-deploy'; import { exec } from 'teen_process'; import AsyncLock from 'async-lock'; import { BOOTSTRAP_PATH, WDA_BUNDLE_ID, WDA_RUNNER_BUNDLE_ID, checkForDependencies } from 'appium-webdriveragent'; @@ -175,9 +173,9 @@ class WebDriverAgent { } log.debug(`Uninstalling WDAs: '${bundleIds}'`); - await B.each(bundleIds, async (bundleId) => { + for (const bundleId of bundleIds) { await this.device.removeApp(bundleId); - }); + } } catch (e) { log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? Original error: ${JSON.stringify(e)}`); } @@ -423,7 +421,7 @@ class WebDriverAgent { */ async getInstalledWDBundleIds () { return this.isRealDevice - ? await iOSDeploy(this.device.udid).getBundleIdsByBundleName(WDA_CF_BUNDLE_NAME) + ? await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME) : await getInstalledBundleIds(this.device, [WDA_BUNDLE_ID, WDA_BUNDLE_ID_XCODE11]); } } From 74c03149c5541d6256f2f9bd5fdf3f97b89d818f Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 1 Sep 2019 13:53:32 +0900 Subject: [PATCH 17/18] call getUserInstalledBundleIdsByBundleName from device --- lib/real-device-management.js | 2 +- lib/simulator-management.js | 7 +------ lib/wda/utils.js | 1 + lib/wda/webdriveragent.js | 17 +---------------- package.json | 2 +- 5 files changed, 5 insertions(+), 24 deletions(-) diff --git a/lib/real-device-management.js b/lib/real-device-management.js index 2649b2e25..facac5e95 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -2,6 +2,7 @@ import { utilities } from 'appium-ios-device'; import IOSDeploy from './ios-deploy'; import log from './logger'; + async function getConnectedDevices () { return await utilities.getConnectedDevices(); } @@ -65,6 +66,5 @@ function getRealDeviceObj (udid) { return new IOSDeploy(udid); } - export { getConnectedDevices, getOSVersion, runRealDeviceReset, installToRealDevice, getRealDeviceObj }; diff --git a/lib/simulator-management.js b/lib/simulator-management.js index 40793a087..45bfe9fb7 100644 --- a/lib/simulator-management.js +++ b/lib/simulator-management.js @@ -1,4 +1,3 @@ -import B from 'bluebird'; import path from 'path'; import { getSimulator } from 'appium-ios-simulator'; import { createDevice, getDevices, terminate, shutdown } from 'node-simctl'; @@ -215,9 +214,5 @@ async function shutdownOtherSimulators (currentDevice) { } } -async function getInstalledBundleIds (device, candidateBundleIds) { - return await B.filter(candidateBundleIds, async (bundleId) => await device.isAppInstalled(bundleId)); -} - export { createSim, getExistingSim, runSimulatorReset, installToSimulator, - shutdownSimulator, shutdownOtherSimulators, getInstalledBundleIds }; + shutdownSimulator, shutdownOtherSimulators }; diff --git a/lib/wda/utils.js b/lib/wda/utils.js index 0302d65dc..2835acf2e 100644 --- a/lib/wda/utils.js +++ b/lib/wda/utils.js @@ -211,6 +211,7 @@ function getXctestrunFileName (deviceInfo, version) { ? `WebDriverAgentRunner_tvOS_appletv${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun` : `WebDriverAgentRunner_iphone${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun`; } + async function killProcess (name, proc) { if (proc && proc.proc) { log.info(`Shutting down ${name} process (pid ${proc.proc.pid})`); diff --git a/lib/wda/webdriveragent.js b/lib/wda/webdriveragent.js index 06c76f33e..e4fc733f7 100644 --- a/lib/wda/webdriveragent.js +++ b/lib/wda/webdriveragent.js @@ -12,13 +12,11 @@ import iProxy from './iproxy'; import { exec } from 'teen_process'; import AsyncLock from 'async-lock'; import { BOOTSTRAP_PATH, WDA_BUNDLE_ID, WDA_RUNNER_BUNDLE_ID, checkForDependencies } from 'appium-webdriveragent'; -import { getInstalledBundleIds } from '../simulator-management'; const WDA_LAUNCH_TIMEOUT = 60 * 1000; const WDA_AGENT_PORT = 8100; const WDA_BASE_URL = 'http://localhost'; const WDA_CF_BUNDLE_NAME = 'WebDriverAgentRunner-Runner'; -const WDA_BUNDLE_ID_XCODE11 = 'com.facebook.WebDriverAgentRunner.xctrunner'; // FIXME: Move to appium-webdriveragent const SHARED_RESOURCES_GUARD = new AsyncLock(); @@ -166,7 +164,7 @@ class WebDriverAgent { */ async uninstall () { try { - const bundleIds = await this.getInstalledWDBundleIds(); + const bundleIds = await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME); if (_.isEmpty(bundleIds)) { log.debug('No WDAs on the device.'); return; @@ -411,19 +409,6 @@ class WebDriverAgent { await this.quit(); await this.uninstall(); } - - /** - * Get WDA bundleIds installed in the target device. - * Over Xcode 11, multiple WDA can be in a device since Xcode 11 - * set their bundleIds as 'xxxxxx.xctrunner'. - * - * @returns {Array} A list of User level apps' bundle ids. - */ - async getInstalledWDBundleIds () { - return this.isRealDevice - ? await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME) - : await getInstalledBundleIds(this.device, [WDA_BUNDLE_ID, WDA_BUNDLE_ID_XCODE11]); - } } export default WebDriverAgent; diff --git a/package.json b/package.json index 45f12b5f6..f6c41331b 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "appium-idb": "^0", "appium-ios-device": "^0.10.2", "appium-ios-driver": "^4.0.0", - "appium-ios-simulator": "^3.11.0", + "appium-ios-simulator": "^3.14.0", "appium-remote-debugger": "^5.1.0", "appium-support": "^2.32.0", "appium-webdriveragent": "^1.1.0", From cc866f9620df7378908a426c02ee62445146b7af Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 1 Sep 2019 14:31:58 +0900 Subject: [PATCH 18/18] add unittests for uninstall --- test/unit/webdriveragent-specs.js | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/unit/webdriveragent-specs.js b/test/unit/webdriveragent-specs.js index 060cd701e..d13a9df51 100644 --- a/test/unit/webdriveragent-specs.js +++ b/test/unit/webdriveragent-specs.js @@ -242,4 +242,59 @@ describe('setupCaching()', function () { wdaStub.calledOnce.should.be.true; wdaStubUninstall.notCalled.should.be.true; }); + + describe('uninstall', function () { + let device; + let wda; + let deviceGetBundleIdsStub; + let deviceRemoveAppStub; + + beforeEach(function () { + device = { + getUserInstalledBundleIdsByBundleName: () => {}, + removeApp: () => {} + }; + wda = new WebDriverAgent('1', {device}); + deviceGetBundleIdsStub = sinon.stub(device, 'getUserInstalledBundleIdsByBundleName'); + deviceRemoveAppStub = sinon.stub(device, 'removeApp'); + }); + + afterEach(function () { + for (const stub of [deviceGetBundleIdsStub, deviceRemoveAppStub]) { + if (stub) { + stub.reset(); + } + } + }); + + it('should not call uninstall', async function () { + deviceGetBundleIdsStub.callsFake(() => []); + + await wda.uninstall(); + deviceGetBundleIdsStub.calledOnce.should.be.true; + deviceRemoveAppStub.notCalled.should.be.true; + }); + + it('should call uninstall once', async function () { + const uninstalledBundIds = []; + deviceGetBundleIdsStub.callsFake(() => ['com.appium.WDA1']); + deviceRemoveAppStub.callsFake((id) => uninstalledBundIds.push(id)); + + await wda.uninstall(); + deviceGetBundleIdsStub.calledOnce.should.be.true; + deviceRemoveAppStub.calledOnce.should.be.true; + uninstalledBundIds.should.eql(['com.appium.WDA1']); + }); + + it('should call uninstall twice', async function () { + const uninstalledBundIds = []; + deviceGetBundleIdsStub.callsFake(() => ['com.appium.WDA1', 'com.appium.WDA2']); + deviceRemoveAppStub.callsFake((id) => uninstalledBundIds.push(id)); + + await wda.uninstall(); + deviceGetBundleIdsStub.calledOnce.should.be.true; + deviceRemoveAppStub.calledTwice.should.be.true; + uninstalledBundIds.should.eql(['com.appium.WDA1', 'com.appium.WDA2']); + }); + }); });