appium-xcuitest-driver 7.24.1 → 7.24.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,7 +35,7 @@ const extensions = {
35
35
  */
36
36
  let ctxs = [{id: NATIVE_WIN, view: {}}];
37
37
  this.contexts = [NATIVE_WIN];
38
- for (let view of webviews) {
38
+ for (const view of webviews) {
39
39
  ctxs.push({id: `${WEBVIEW_BASE}${view.id}`, view});
40
40
  this.contexts.push(view.id.toString());
41
41
  }
@@ -75,7 +75,7 @@ const extensions = {
75
75
  if (contextId) {
76
76
  this.log.info(`Picking webview '${contextId}' after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
77
77
  await this.setContext(contextId);
78
- await this.remote.cancelPageLoad();
78
+ await (/** @type {RemoteDebugger} */ (this.remote)).cancelPageLoad();
79
79
  return true;
80
80
  }
81
81
 
@@ -112,13 +112,15 @@ const extensions = {
112
112
 
113
113
  if (!this.remote) {
114
114
  await this.connectToRemoteDebugger();
115
+ // @ts-ignore TS does not understand property mutation
115
116
  if (!this.remote.appIdKey) {
117
+ // @ts-ignore TS does not understand property mutation
116
118
  await this.remote.setConnectionKey();
117
119
  }
118
120
  }
119
121
  const getWebviewPages = async () => {
120
122
  try {
121
- return await this.remote.selectApp(
123
+ return await (/** @type {RemoteDebugger} */ (this.remote)).selectApp(
122
124
  useUrl ? this.getCurrentUrl() : undefined,
123
125
  this.opts.webviewConnectRetries,
124
126
  this.opts.ignoreAboutBlankUrl,
@@ -141,7 +143,9 @@ const extensions = {
141
143
  async connectToRemoteDebugger() {
142
144
  this.remote = await this.getNewRemoteDebugger();
143
145
 
146
+ // @ts-ignore static is fine
144
147
  this.remote.on(RemoteDebugger.EVENT_PAGE_CHANGE, this.onPageChange.bind(this));
148
+ // @ts-ignore static is fine
145
149
  this.remote.on(RemoteDebugger.EVENT_FRAMES_DETACHED, () => {
146
150
  if (isNonEmptyArray(this.curWebFrames)) {
147
151
  const curWebFrames = this.curWebFrames;
@@ -333,7 +337,7 @@ const extensions = {
333
337
 
334
338
  if (needsPageLoad) {
335
339
  this.log.debug('Page load needed. Loading...');
336
- await this.remote.pageLoad();
340
+ await this.remote.waitForDom();
337
341
  }
338
342
 
339
343
  this.log.debug('New page listing is same as old, doing nothing');
@@ -371,7 +375,7 @@ const helpers = {
371
375
  */
372
376
  async stopRemote(closeWindowBeforeDisconnecting = false) {
373
377
  if (!this.remote) {
374
- this.log.errorAndThrow('Tried to leave a web frame but were not in one');
378
+ throw this.log.errorWithException('Tried to leave a web frame but were not in one');
375
379
  }
376
380
 
377
381
  if (closeWindowBeforeDisconnecting) {
@@ -435,6 +439,7 @@ const helpers = {
435
439
  },
436
440
  /**
437
441
  * @this {XCUITestDriver}
442
+ * @returns {Promise<RemoteDebugger>}
438
443
  */
439
444
  async getNewRemoteDebugger() {
440
445
  let socketPath;
@@ -547,7 +552,7 @@ const commands = {
547
552
  const [appIdKey, pageIdKey] = _.map(contextId.split('.'), (id) => parseInt(id, 10));
548
553
  try {
549
554
  this.selectingNewPage = true;
550
- await this.remote.selectPage(appIdKey, pageIdKey, skipReadyCheck);
555
+ await (/** @type {RemoteDebugger} */ (this.remote)).selectPage(appIdKey, pageIdKey, skipReadyCheck);
551
556
  } catch (err) {
552
557
  this.curContext = this.curWindowHandle = oldContext;
553
558
  throw err;
@@ -568,12 +573,12 @@ const commands = {
568
573
  // start safari logging if the logs handlers are active
569
574
  if (name && name !== NATIVE_WIN && this.logs) {
570
575
  if (this.logs.safariConsole) {
571
- await this.remote.startConsole(
576
+ (/** @type {RemoteDebugger} */ (this.remote)).startConsole(
572
577
  this.logs.safariConsole.onConsoleLogEvent.bind(this.logs.safariConsole),
573
578
  );
574
579
  }
575
580
  if (this.logs.safariNetwork) {
576
- await this.remote.startNetwork(
581
+ (/** @type {RemoteDebugger} */ (this.remote)).startNetwork(
577
582
  this.logs.safariNetwork.onNetworkEvent.bind(this.logs.safariNetwork),
578
583
  );
579
584
  }
@@ -135,7 +135,7 @@ export default {
135
135
 
136
136
  args = this.convertElementsForAtoms(args);
137
137
  this.asyncWaitMs = this.asyncWaitMs || 0;
138
- const promise = this.remote.executeAtomAsync(
138
+ const promise = (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).executeAtomAsync(
139
139
  'execute_async_script',
140
140
  [script, args, this.asyncWaitMs],
141
141
  this.curWebFrames,
@@ -162,7 +162,7 @@ const commands = {
162
162
  this.setCurrentUrl(url);
163
163
  // make sure to clear out any leftover web frames
164
164
  this.curWebFrames = [];
165
- await this.remote.navToUrl(url);
165
+ await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).navToUrl(url);
166
166
  return;
167
167
  }
168
168
 
@@ -104,6 +104,7 @@ const commands = {
104
104
  */
105
105
  async performActions(actions) {
106
106
  this.log.debug(`Received the following W3C actions: ${JSON.stringify(actions, null, ' ')}`);
107
+ assertNoWebElements(actions);
107
108
  // This is mandatory, since WDA only supports TOUCH pointer type
108
109
  // and Selenium API uses MOUSE as the default one
109
110
  const preprocessedActions = actions
@@ -564,6 +565,25 @@ const helpers = {
564
565
 
565
566
  export default {...helpers, ...commands};
566
567
 
568
+ /**
569
+ * @param {import('@appium/types').ActionSequence[]} actionSeq
570
+ */
571
+ function assertNoWebElements(actionSeq) {
572
+ const isOriginWebElement = (gesture) =>
573
+ _.isPlainObject(gesture) && 'origin' in gesture && JSON.stringify(gesture.origin).includes(':wdc:');
574
+ const hasWebElements = actionSeq
575
+ .some((action) => (action?.actions || []).some(isOriginWebElement));
576
+ if (hasWebElements) {
577
+ throw new errors.InvalidArgumentError(
578
+ `The XCUITest driver only supports W3C actions execution in the native context. ` +
579
+ `Although, your W3C action contains one or more web elements, ` +
580
+ `which cannot be automatically mapped to the native context. ` +
581
+ `Consider mapping their absolute web coordinates to native context coordinates ` +
582
+ `and passing them to your gesture instead.`
583
+ );
584
+ }
585
+ }
586
+
567
587
  /**
568
588
  * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
569
589
  * @typedef {import('@appium/types').Element} Element
@@ -14,8 +14,8 @@ export default {
14
14
  switch (_.toLower(webScreenshotMode)) {
15
15
  case 'page':
16
16
  case 'viewport':
17
- return await this.remote.captureScreenshot({
18
- coordinateSystem: _.capitalize(webScreenshotMode),
17
+ return await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).captureScreenshot({
18
+ coordinateSystem: /** @type {'Viewport'|'Page'} */ (_.capitalize(webScreenshotMode)),
19
19
  });
20
20
  case 'native':
21
21
  case undefined:
@@ -94,7 +94,7 @@ export default {
94
94
  */
95
95
  async getViewportScreenshot() {
96
96
  if (this.isWebContext()) {
97
- return await this.remote.captureScreenshot();
97
+ return await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).captureScreenshot();
98
98
  }
99
99
 
100
100
  let statusBarHeight = await this.getStatusBarHeight();
@@ -188,7 +188,7 @@ const commands = {
188
188
  throw new errors.NotImplementedError();
189
189
  }
190
190
 
191
- await this.remote.execute('window.location.reload()');
191
+ await (/** @type {RemoteDebugger} */ (this.remote)).execute('window.location.reload()');
192
192
  },
193
193
  /**
194
194
  * @this {XCUITestDriver}
@@ -199,7 +199,7 @@ const commands = {
199
199
  throw new errors.NotImplementedError();
200
200
  }
201
201
 
202
- return await this.remote.execute('window.location.href');
202
+ return await (/** @type {RemoteDebugger} */ (this.remote)).execute('window.location.href');
203
203
  },
204
204
  /**
205
205
  * @this {XCUITestDriver}
@@ -210,7 +210,7 @@ const commands = {
210
210
  throw new errors.NotImplementedError();
211
211
  }
212
212
 
213
- return await this.remote.execute('window.document.title');
213
+ return await (/** @type {RemoteDebugger} */ (this.remote)).execute('window.document.title');
214
214
  },
215
215
  /**
216
216
  * @this {XCUITestDriver}
@@ -222,7 +222,7 @@ const commands = {
222
222
  }
223
223
 
224
224
  // get the cookies from the remote debugger, or an empty object
225
- const {cookies} = await this.remote.getCookies();
225
+ const {cookies} = await (/** @type {RemoteDebugger} */ (this.remote)).getCookies();
226
226
 
227
227
  // the value is URI encoded, so decode it safely
228
228
  return cookies.map((cookie) => {
@@ -306,7 +306,7 @@ const helpers = {
306
306
  */
307
307
  async _deleteCookie(cookie) {
308
308
  const url = `http${cookie.secure ? 's' : ''}://${cookie.domain}${cookie.path}`;
309
- return await this.remote.deleteCookie(cookie.name, url);
309
+ return await (/** @type {RemoteDebugger} */ (this.remote)).deleteCookie(cookie.name, url);
310
310
  },
311
311
  /**
312
312
  * @this {XCUITestDriver}
@@ -351,18 +351,20 @@ const helpers = {
351
351
  */
352
352
  async executeAtom(atom, args, alwaysDefaultFrame = false) {
353
353
  let frames = alwaysDefaultFrame === true ? [] : this.curWebFrames;
354
- let promise = this.remote.executeAtom(atom, args, frames);
354
+ let promise = (/** @type {RemoteDebugger} */ (this.remote)).executeAtom(atom, args, frames);
355
355
  return await this.waitForAtom(promise);
356
356
  },
357
357
  /**
358
358
  * @this {XCUITestDriver}
359
+ * @param {string} atom
360
+ * @param {any[]} args
359
361
  */
360
- async executeAtomAsync(atom, args, responseUrl) {
362
+ async executeAtomAsync(atom, args) {
361
363
  // save the resolve and reject methods of the promise to be waited for
362
364
  let promise = new B((resolve, reject) => {
363
365
  this.asyncPromise = {resolve, reject};
364
366
  });
365
- await this.remote.executeAtomAsync(atom, args, this.curWebFrames, responseUrl);
367
+ await (/** @type {RemoteDebugger} */ (this.remote)).executeAtomAsync(atom, args, this.curWebFrames);
366
368
  return await this.waitForAtom(promise);
367
369
  },
368
370
  /**
@@ -673,7 +675,7 @@ const extensions = {
673
675
  const { offsetX, offsetY, pixelRatioX, pixelRatioY } = this.webviewCalibrationResult;
674
676
  const cmd = '(function () {return {innerWidth: window.innerWidth, innerHeight: window.innerHeight, ' +
675
677
  'outerWidth: window.outerWidth, outerHeight: window.outerHeight}; })()';
676
- const wvDims = await this.remote.execute(cmd);
678
+ const wvDims = await (/** @type {RemoteDebugger} */ (this.remote)).execute(cmd);
677
679
  // https://tripleodeon.com/2011/12/first-understand-your-screen/
678
680
  const shouldApplyPixelRatio = wvDims.innerWidth > wvDims.outerWidth
679
681
  || wvDims.innerHeight > wvDims.outerHeight;
@@ -713,7 +715,7 @@ const extensions = {
713
715
  const realDims = {w: rect.width, h: rect.height};
714
716
 
715
717
  const cmd = '(function () { return {w: window.innerWidth, h: window.innerHeight}; })()';
716
- const wvDims = await this.remote.execute(cmd);
718
+ const wvDims = await (/** @type {RemoteDebugger} */ (this.remote)).execute(cmd);
717
719
 
718
720
  // keep track of implicit wait, and set locally to 0
719
721
  // https://github.com/appium/appium/issues/14988
@@ -854,11 +856,11 @@ const extensions = {
854
856
  * @this {XCUITestDriver}
855
857
  */
856
858
  async mobileWebNav(navType) {
857
- this.remote.allowNavigationWithoutReload = true;
859
+ (/** @type {RemoteDebugger} */ (this.remote)).allowNavigationWithoutReload = true;
858
860
  try {
859
861
  await this.executeAtom('execute_script', [`history.${navType}();`, null]);
860
862
  } finally {
861
- this.remote.allowNavigationWithoutReload = false;
863
+ (/** @type {RemoteDebugger} */ (this.remote)).allowNavigationWithoutReload = false;
862
864
  }
863
865
  },
864
866
 
@@ -1006,3 +1008,7 @@ export default {...helpers, ...extensions, ...commands};
1006
1008
  * @template {string} [S=string]
1007
1009
  * @typedef {import('@appium/types').Element<S>} Element
1008
1010
  */
1011
+
1012
+ /**
1013
+ * @typedef {import('appium-remote-debugger').RemoteDebugger} RemoteDebugger
1014
+ */
package/lib/driver.js CHANGED
@@ -262,6 +262,9 @@ export class XCUITestDriver extends BaseDriver {
262
262
  /** @type {WebDriverAgent} */
263
263
  wda;
264
264
 
265
+ /** @type {import('appium-remote-debugger').RemoteDebugger|null} */
266
+ remote;
267
+
265
268
  /**
266
269
  *
267
270
  * @param {XCUITestDriverOpts} opts
@@ -310,6 +313,7 @@ export class XCUITestDriver extends BaseDriver {
310
313
  this.lifecycleData = {};
311
314
  this._audioRecorder = null;
312
315
  this.appInfosCache = new AppInfosCache(this.log);
316
+ this.remote = null;
313
317
  }
314
318
 
315
319
  async onSettingsUpdate(key, value) {