webdriveragent-specs.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. import { BOOTSTRAP_PATH } from '../../lib/utils';
  2. import { WebDriverAgent } from '../../lib/webdriveragent';
  3. import * as utils from '../../lib/utils';
  4. import path from 'path';
  5. import _ from 'lodash';
  6. import sinon from 'sinon';
  7. const fakeConstructorArgs = {
  8. device: 'some sim',
  9. platformVersion: '9',
  10. host: 'me',
  11. port: '5000',
  12. realDevice: false
  13. };
  14. const defaultAgentPath = path.resolve(BOOTSTRAP_PATH, 'WebDriverAgent.xcodeproj');
  15. const customBootstrapPath = '/path/to/wda';
  16. const customAgentPath = '/path/to/some/agent/WebDriverAgent.xcodeproj';
  17. const customDerivedDataPath = '/path/to/some/agent/DerivedData/';
  18. describe('Constructor', function () {
  19. let chai;
  20. before(async function() {
  21. chai = await import('chai');
  22. const chaiAsPromised = await import('chai-as-promised');
  23. chai.should();
  24. chai.use(chaiAsPromised.default);
  25. });
  26. it('should have a default wda agent if not specified', function () {
  27. let agent = new WebDriverAgent({}, fakeConstructorArgs);
  28. agent.bootstrapPath.should.eql(BOOTSTRAP_PATH);
  29. agent.agentPath.should.eql(defaultAgentPath);
  30. });
  31. it('should have custom wda bootstrap and default agent if only bootstrap specified', function () {
  32. let agent = new WebDriverAgent({}, _.defaults({
  33. bootstrapPath: customBootstrapPath,
  34. }, fakeConstructorArgs));
  35. agent.bootstrapPath.should.eql(customBootstrapPath);
  36. agent.agentPath.should.eql(path.resolve(customBootstrapPath, 'WebDriverAgent.xcodeproj'));
  37. });
  38. it('should have custom wda bootstrap and agent if both specified', function () {
  39. let agent = new WebDriverAgent({}, _.defaults({
  40. bootstrapPath: customBootstrapPath,
  41. agentPath: customAgentPath,
  42. }, fakeConstructorArgs));
  43. agent.bootstrapPath.should.eql(customBootstrapPath);
  44. agent.agentPath.should.eql(customAgentPath);
  45. });
  46. it('should have custom derivedDataPath if specified', function () {
  47. let agent = new WebDriverAgent({}, _.defaults({
  48. derivedDataPath: customDerivedDataPath
  49. }, fakeConstructorArgs));
  50. agent.xcodebuild.derivedDataPath.should.eql(customDerivedDataPath);
  51. });
  52. });
  53. describe('launch', function () {
  54. it('should use webDriverAgentUrl override and return current status', async function () {
  55. const override = 'http://mockurl:8100/';
  56. const args = Object.assign({}, fakeConstructorArgs);
  57. args.webDriverAgentUrl = override;
  58. const agent = new WebDriverAgent({}, args);
  59. const wdaStub = sinon.stub(agent, 'getStatus');
  60. wdaStub.callsFake(function () {
  61. return {build: 'data'};
  62. });
  63. await agent.launch('sessionId').should.eventually.eql({build: 'data'});
  64. agent.url.href.should.eql(override);
  65. agent.jwproxy.server.should.eql('mockurl');
  66. agent.jwproxy.port.should.eql(8100);
  67. agent.jwproxy.base.should.eql('');
  68. agent.jwproxy.scheme.should.eql('http');
  69. agent.noSessionProxy.server.should.eql('mockurl');
  70. agent.noSessionProxy.port.should.eql(8100);
  71. agent.noSessionProxy.base.should.eql('');
  72. agent.noSessionProxy.scheme.should.eql('http');
  73. wdaStub.reset();
  74. });
  75. });
  76. describe('use wda proxy url', function () {
  77. it('should use webDriverAgentUrl wda proxy url', async function () {
  78. const override = 'http://127.0.0.1:8100/aabbccdd';
  79. const args = Object.assign({}, fakeConstructorArgs);
  80. args.webDriverAgentUrl = override;
  81. const agent = new WebDriverAgent({}, args);
  82. const wdaStub = sinon.stub(agent, 'getStatus');
  83. wdaStub.callsFake(function () {
  84. return {build: 'data'};
  85. });
  86. await agent.launch('sessionId').should.eventually.eql({build: 'data'});
  87. agent.url.port.should.eql('8100');
  88. agent.url.hostname.should.eql('127.0.0.1');
  89. agent.url.path.should.eql('/aabbccdd');
  90. agent.jwproxy.server.should.eql('127.0.0.1');
  91. agent.jwproxy.port.should.eql(8100);
  92. agent.jwproxy.base.should.eql('/aabbccdd');
  93. agent.jwproxy.scheme.should.eql('http');
  94. agent.noSessionProxy.server.should.eql('127.0.0.1');
  95. agent.noSessionProxy.port.should.eql(8100);
  96. agent.noSessionProxy.base.should.eql('/aabbccdd');
  97. agent.noSessionProxy.scheme.should.eql('http');
  98. });
  99. });
  100. describe('get url', function () {
  101. it('should use default WDA listening url', function () {
  102. const args = Object.assign({}, fakeConstructorArgs);
  103. const agent = new WebDriverAgent({}, args);
  104. agent.url.href.should.eql('http://127.0.0.1:8100/');
  105. agent.setupProxies('mysession');
  106. agent.jwproxy.scheme.should.eql('http');
  107. agent.noSessionProxy.scheme.should.eql('http');
  108. });
  109. it('should use default WDA listening url with emply base url', function () {
  110. const wdaLocalPort = '9100';
  111. const wdaBaseUrl = '';
  112. const args = Object.assign({}, fakeConstructorArgs);
  113. args.wdaBaseUrl = wdaBaseUrl;
  114. args.wdaLocalPort = wdaLocalPort;
  115. const agent = new WebDriverAgent({}, args);
  116. agent.url.href.should.eql('http://127.0.0.1:9100/');
  117. agent.setupProxies('mysession');
  118. agent.jwproxy.scheme.should.eql('http');
  119. agent.noSessionProxy.scheme.should.eql('http');
  120. });
  121. it('should use customised WDA listening url', function () {
  122. const wdaLocalPort = '9100';
  123. const wdaBaseUrl = 'http://mockurl';
  124. const args = Object.assign({}, fakeConstructorArgs);
  125. args.wdaBaseUrl = wdaBaseUrl;
  126. args.wdaLocalPort = wdaLocalPort;
  127. const agent = new WebDriverAgent({}, args);
  128. agent.url.href.should.eql('http://mockurl:9100/');
  129. agent.setupProxies('mysession');
  130. agent.jwproxy.scheme.should.eql('http');
  131. agent.noSessionProxy.scheme.should.eql('http');
  132. });
  133. it('should use customised WDA listening url with slash', function () {
  134. const wdaLocalPort = '9100';
  135. const wdaBaseUrl = 'http://mockurl/';
  136. const args = Object.assign({}, fakeConstructorArgs);
  137. args.wdaBaseUrl = wdaBaseUrl;
  138. args.wdaLocalPort = wdaLocalPort;
  139. const agent = new WebDriverAgent({}, args);
  140. agent.url.href.should.eql('http://mockurl:9100/');
  141. agent.setupProxies('mysession');
  142. agent.jwproxy.scheme.should.eql('http');
  143. agent.noSessionProxy.scheme.should.eql('http');
  144. });
  145. it('should use the given webDriverAgentUrl and ignore other params', function () {
  146. const args = Object.assign({}, fakeConstructorArgs);
  147. args.wdaBaseUrl = 'http://mockurl/';
  148. args.wdaLocalPort = '9100';
  149. args.webDriverAgentUrl = 'https://127.0.0.1:8100/';
  150. const agent = new WebDriverAgent({}, args);
  151. agent.url.href.should.eql('https://127.0.0.1:8100/');
  152. });
  153. it('should set scheme to https for https webDriverAgentUrl', function () {
  154. const args = Object.assign({}, fakeConstructorArgs);
  155. args.webDriverAgentUrl = 'https://127.0.0.1:8100/';
  156. const agent = new WebDriverAgent({}, args);
  157. agent.setupProxies('mysession');
  158. agent.jwproxy.scheme.should.eql('https');
  159. agent.noSessionProxy.scheme.should.eql('https');
  160. });
  161. });
  162. describe('setupCaching()', function () {
  163. let wda;
  164. let wdaStub;
  165. let wdaStubUninstall;
  166. const getTimestampStub = sinon.stub(utils, 'getWDAUpgradeTimestamp');
  167. beforeEach(function () {
  168. wda = new WebDriverAgent('1');
  169. wdaStub = sinon.stub(wda, 'getStatus');
  170. wdaStubUninstall = sinon.stub(wda, 'uninstall');
  171. });
  172. afterEach(function () {
  173. for (const stub of [wdaStub, wdaStubUninstall, getTimestampStub]) {
  174. if (stub) {
  175. stub.reset();
  176. }
  177. }
  178. });
  179. it('should not call uninstall since no Running WDA', async function () {
  180. wdaStub.callsFake(function () {
  181. return null;
  182. });
  183. wdaStubUninstall.callsFake(_.noop);
  184. await wda.setupCaching();
  185. wdaStub.calledOnce.should.be.true;
  186. wdaStubUninstall.notCalled.should.be.true;
  187. _.isUndefined(wda.webDriverAgentUrl).should.be.true;
  188. });
  189. it('should not call uninstall since running WDA has only time', async function () {
  190. wdaStub.callsFake(function () {
  191. return {build: { time: 'Jun 24 2018 17:08:21' }};
  192. });
  193. wdaStubUninstall.callsFake(_.noop);
  194. await wda.setupCaching();
  195. wdaStub.calledOnce.should.be.true;
  196. wdaStubUninstall.notCalled.should.be.true;
  197. wda.webDriverAgentUrl.should.equal('http://127.0.0.1:8100/');
  198. });
  199. it('should call uninstall once since bundle id is not default without updatedWDABundleId capability', async function () {
  200. wdaStub.callsFake(function () {
  201. return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }};
  202. });
  203. wdaStubUninstall.callsFake(_.noop);
  204. await wda.setupCaching();
  205. wdaStub.calledOnce.should.be.true;
  206. wdaStubUninstall.calledOnce.should.be.true;
  207. _.isUndefined(wda.webDriverAgentUrl).should.be.true;
  208. });
  209. it('should call uninstall once since bundle id is different with updatedWDABundleId capability', async function () {
  210. wdaStub.callsFake(function () {
  211. return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.different.WebDriverAgent' }};
  212. });
  213. wdaStubUninstall.callsFake(_.noop);
  214. await wda.setupCaching();
  215. wdaStub.calledOnce.should.be.true;
  216. wdaStubUninstall.calledOnce.should.be.true;
  217. _.isUndefined(wda.webDriverAgentUrl).should.be.true;
  218. });
  219. it('should not call uninstall since bundle id is equal to updatedWDABundleId capability', async function () {
  220. wda = new WebDriverAgent('1', { updatedWDABundleId: 'com.example.WebDriverAgent' });
  221. wdaStub = sinon.stub(wda, 'getStatus');
  222. wdaStubUninstall = sinon.stub(wda, 'uninstall');
  223. wdaStub.callsFake(function () {
  224. return {build: { time: 'Jun 24 2018 17:08:21', productBundleIdentifier: 'com.example.WebDriverAgent' }};
  225. });
  226. wdaStubUninstall.callsFake(_.noop);
  227. await wda.setupCaching();
  228. wdaStub.calledOnce.should.be.true;
  229. wdaStubUninstall.notCalled.should.be.true;
  230. wda.webDriverAgentUrl.should.equal('http://127.0.0.1:8100/');
  231. });
  232. it('should call uninstall if current revision differs from the bundled one', async function () {
  233. wdaStub.callsFake(function () {
  234. return {build: { upgradedAt: '1' }};
  235. });
  236. getTimestampStub.callsFake(() => '2');
  237. wdaStubUninstall.callsFake(_.noop);
  238. await wda.setupCaching();
  239. wdaStub.calledOnce.should.be.true;
  240. wdaStubUninstall.calledOnce.should.be.true;
  241. });
  242. it('should not call uninstall if current revision is the same as the bundled one', async function () {
  243. wdaStub.callsFake(function () {
  244. return {build: { upgradedAt: '1' }};
  245. });
  246. getTimestampStub.callsFake(() => '1');
  247. wdaStubUninstall.callsFake(_.noop);
  248. await wda.setupCaching();
  249. wdaStub.calledOnce.should.be.true;
  250. wdaStubUninstall.notCalled.should.be.true;
  251. });
  252. it('should not call uninstall if current revision cannot be retrieved from WDA status', async function () {
  253. wdaStub.callsFake(function () {
  254. return {build: {}};
  255. });
  256. getTimestampStub.callsFake(() => '1');
  257. wdaStubUninstall.callsFake(_.noop);
  258. await wda.setupCaching();
  259. wdaStub.calledOnce.should.be.true;
  260. wdaStubUninstall.notCalled.should.be.true;
  261. });
  262. it('should not call uninstall if current revision cannot be retrieved from the file system', async function () {
  263. wdaStub.callsFake(function () {
  264. return {build: { upgradedAt: '1' }};
  265. });
  266. getTimestampStub.callsFake(() => null);
  267. wdaStubUninstall.callsFake(_.noop);
  268. await wda.setupCaching();
  269. wdaStub.calledOnce.should.be.true;
  270. wdaStubUninstall.notCalled.should.be.true;
  271. });
  272. describe('uninstall', function () {
  273. let device;
  274. let wda;
  275. let deviceGetBundleIdsStub;
  276. let deviceRemoveAppStub;
  277. beforeEach(function () {
  278. device = {
  279. getUserInstalledBundleIdsByBundleName: () => {},
  280. removeApp: () => {}
  281. };
  282. wda = new WebDriverAgent('1', {device});
  283. deviceGetBundleIdsStub = sinon.stub(device, 'getUserInstalledBundleIdsByBundleName');
  284. deviceRemoveAppStub = sinon.stub(device, 'removeApp');
  285. });
  286. afterEach(function () {
  287. for (const stub of [deviceGetBundleIdsStub, deviceRemoveAppStub]) {
  288. if (stub) {
  289. stub.reset();
  290. }
  291. }
  292. });
  293. it('should not call uninstall', async function () {
  294. deviceGetBundleIdsStub.callsFake(() => []);
  295. await wda.uninstall();
  296. deviceGetBundleIdsStub.calledOnce.should.be.true;
  297. deviceRemoveAppStub.notCalled.should.be.true;
  298. });
  299. it('should call uninstall once', async function () {
  300. const uninstalledBundIds = [];
  301. deviceGetBundleIdsStub.callsFake(() => ['com.appium.WDA1']);
  302. deviceRemoveAppStub.callsFake((id) => uninstalledBundIds.push(id));
  303. await wda.uninstall();
  304. deviceGetBundleIdsStub.calledOnce.should.be.true;
  305. deviceRemoveAppStub.calledOnce.should.be.true;
  306. uninstalledBundIds.should.eql(['com.appium.WDA1']);
  307. });
  308. it('should call uninstall twice', async function () {
  309. const uninstalledBundIds = [];
  310. deviceGetBundleIdsStub.callsFake(() => ['com.appium.WDA1', 'com.appium.WDA2']);
  311. deviceRemoveAppStub.callsFake((id) => uninstalledBundIds.push(id));
  312. await wda.uninstall();
  313. deviceGetBundleIdsStub.calledOnce.should.be.true;
  314. deviceRemoveAppStub.calledTwice.should.be.true;
  315. uninstalledBundIds.should.eql(['com.appium.WDA1', 'com.appium.WDA2']);
  316. });
  317. });
  318. });
  319. describe('usePreinstalledWDA related functions', function () {
  320. describe('bundleIdForXctest', function () {
  321. it('should have xctrunner automatically', function () {
  322. const args = Object.assign({}, fakeConstructorArgs);
  323. args.updatedWDABundleId = 'io.appium.wda';
  324. const agent = new WebDriverAgent({}, args);
  325. agent.bundleIdForXctest.should.equal('io.appium.wda.xctrunner');
  326. });
  327. it('should have xctrunner automatically with default bundle id', function () {
  328. const args = Object.assign({}, fakeConstructorArgs);
  329. const agent = new WebDriverAgent({}, args);
  330. agent.bundleIdForXctest.should.equal('com.facebook.WebDriverAgentRunner.xctrunner');
  331. });
  332. it('should allow an empty string as xctrunner suffix', function () {
  333. const args = Object.assign({}, fakeConstructorArgs);
  334. args.updatedWDABundleId = 'io.appium.wda';
  335. args.updatedWDABundleIdSuffix = '';
  336. const agent = new WebDriverAgent({}, args);
  337. agent.bundleIdForXctest.should.equal('io.appium.wda');
  338. });
  339. it('should allow an empty string as xctrunner suffix with default bundle id', function () {
  340. const args = Object.assign({}, fakeConstructorArgs);
  341. args.updatedWDABundleIdSuffix = '';
  342. const agent = new WebDriverAgent({}, args);
  343. agent.bundleIdForXctest.should.equal('com.facebook.WebDriverAgentRunner');
  344. });
  345. it('should have an arbitrary xctrunner suffix', function () {
  346. const args = Object.assign({}, fakeConstructorArgs);
  347. args.updatedWDABundleId = 'io.appium.wda';
  348. args.updatedWDABundleIdSuffix = '.customsuffix';
  349. const agent = new WebDriverAgent({}, args);
  350. agent.bundleIdForXctest.should.equal('io.appium.wda.customsuffix');
  351. });
  352. });
  353. });