appium-xcuitest-driver 10.12.1 → 10.13.0

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/commands/context.d.ts +130 -161
  3. package/build/lib/commands/context.d.ts.map +1 -1
  4. package/build/lib/commands/context.js +122 -107
  5. package/build/lib/commands/context.js.map +1 -1
  6. package/build/lib/commands/execute.js +1 -1
  7. package/build/lib/commands/execute.js.map +1 -1
  8. package/build/lib/commands/general.js +1 -1
  9. package/build/lib/commands/general.js.map +1 -1
  10. package/build/lib/commands/gesture.d.ts +103 -119
  11. package/build/lib/commands/gesture.d.ts.map +1 -1
  12. package/build/lib/commands/gesture.js +98 -138
  13. package/build/lib/commands/gesture.js.map +1 -1
  14. package/build/lib/commands/pcap.d.ts +1 -1
  15. package/build/lib/commands/pcap.d.ts.map +1 -1
  16. package/build/lib/commands/performance.d.ts +1 -1
  17. package/build/lib/commands/performance.d.ts.map +1 -1
  18. package/build/lib/commands/record-audio.d.ts +2 -1
  19. package/build/lib/commands/record-audio.d.ts.map +1 -1
  20. package/build/lib/commands/recordscreen.d.ts +2 -1
  21. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  22. package/build/lib/commands/screenshots.d.ts.map +1 -1
  23. package/build/lib/commands/screenshots.js +3 -5
  24. package/build/lib/commands/screenshots.js.map +1 -1
  25. package/build/lib/commands/timeouts.js +1 -1
  26. package/build/lib/commands/timeouts.js.map +1 -1
  27. package/build/lib/commands/web.d.ts +199 -202
  28. package/build/lib/commands/web.d.ts.map +1 -1
  29. package/build/lib/commands/web.js +206 -174
  30. package/build/lib/commands/web.js.map +1 -1
  31. package/build/lib/driver.d.ts +2 -1
  32. package/build/lib/driver.d.ts.map +1 -1
  33. package/build/lib/driver.js +10 -4
  34. package/build/lib/driver.js.map +1 -1
  35. package/build/lib/execute-method-map.d.ts.map +1 -1
  36. package/build/lib/execute-method-map.js +0 -1
  37. package/build/lib/execute-method-map.js.map +1 -1
  38. package/lib/commands/{context.js → context.ts} +172 -145
  39. package/lib/commands/execute.js +1 -1
  40. package/lib/commands/general.js +1 -1
  41. package/lib/commands/{gesture.js → gesture.ts} +225 -183
  42. package/lib/commands/screenshots.js +3 -5
  43. package/lib/commands/timeouts.js +1 -1
  44. package/lib/commands/{web.js → web.ts} +305 -263
  45. package/lib/driver.ts +11 -4
  46. package/lib/execute-method-map.ts +0 -1
  47. package/npm-shrinkwrap.json +14 -89
  48. package/package.json +2 -2
@@ -1,50 +1,30 @@
1
1
  import {errors} from 'appium/driver';
2
2
  import {util} from 'appium/support';
3
3
  import _ from 'lodash';
4
+ import {assertSimulator} from '../utils';
5
+ import type {XCUITestDriver} from '../driver';
6
+ import type {ActionSequence, Element} from '@appium/types';
7
+ import type {Direction} from './types';
4
8
 
5
- const SUPPORTED_GESTURE_DIRECTIONS = ['up', 'down', 'left', 'right'];
9
+ const SUPPORTED_GESTURE_DIRECTIONS = ['up', 'down', 'left', 'right'] as const;
6
10
 
7
11
  /**
12
+ * Shakes the device.
8
13
  *
9
- * @param {any[]} gestures
10
- * @param {string[]|null} keysToInclude
11
- * @returns {string}
12
- */
13
- export function gesturesChainToString(gestures, keysToInclude = ['options']) {
14
- return gestures
15
- .map((item) => {
16
- let otherKeys = _.difference(_.keys(item), ['action']);
17
- otherKeys = _.isArray(keysToInclude) ? _.intersection(otherKeys, keysToInclude) : otherKeys;
18
- if (otherKeys.length) {
19
- return (
20
- `${item.action}` +
21
- `(${_.map(
22
- otherKeys,
23
- (x) => x + '=' + (_.isPlainObject(item[x]) ? JSON.stringify(item[x]) : item[x]),
24
- ).join(', ')})`
25
- );
26
- }
27
- return item.action;
28
- })
29
- .join('-');
30
- }
31
-
32
- /**
33
- * Shake the device
34
- * @this {XCUITestDriver}
35
14
  * @group Simulator Only
15
+ * @throws {Error} If called on a real device
36
16
  */
37
- export async function mobileShake() {
38
- if (!this.isSimulator()) {
39
- throw new errors.UnknownError('Shake is not supported on real devices');
40
- }
41
- await /** @type {import('appium-ios-simulator').Simulator} */ (this.device).shake();
17
+ export async function mobileShake(this: XCUITestDriver): Promise<void> {
18
+ await assertSimulator.call(this, 'Shake device').shake();
42
19
  }
43
20
 
44
21
  /**
45
- * @this {XCUITestDriver}
22
+ * Clicks on an element.
23
+ *
24
+ * In web context, uses native web tap if configured, otherwise uses atom-based clicking.
25
+ * In native context, delegates to native click.
46
26
  */
47
- export async function click(el) {
27
+ export async function click(this: XCUITestDriver, el: Element | string): Promise<void> {
48
28
  if (!this.isWebContext()) {
49
29
  // there are multiple commands that map here, so manually proxy
50
30
  return await this.nativeClick(el);
@@ -64,7 +44,7 @@ export async function click(el) {
64
44
  // the behaviour of selenium.
65
45
  try {
66
46
  return await this.executeAtom('click', [atomsElement]);
67
- } catch (err) {
47
+ } catch (err: any) {
68
48
  if (err.error === errors.UnexpectedAlertOpenError.error()) {
69
49
  return;
70
50
  }
@@ -74,18 +54,23 @@ export async function click(el) {
74
54
  }
75
55
 
76
56
  /**
77
- * @this {XCUITestDriver}
57
+ * Releases all actions.
58
+ *
59
+ * On this platform, this is a no-op.
78
60
  */
79
- export async function releaseActions() {
80
- this.log.warn('On this platform, releaseActions is a no-op');
61
+ export async function releaseActions(this: XCUITestDriver): Promise<void> {
62
+ this.log.info('On this platform, releaseActions is a no-op');
81
63
  }
82
64
 
83
65
  /**
84
- * @param {import('@appium/types').ActionSequence[]} actions
85
- * @returns {Promise<void>}
86
- * @this {XCUITestDriver}
66
+ * Performs a sequence of W3C actions.
67
+ *
68
+ * Automatically converts MOUSE pointer type to TOUCH and filters out zero-duration pauses.
69
+ *
70
+ * @param actions - Array of action sequences to perform
71
+ * @throws {errors.InvalidArgumentError} If actions contain web elements
87
72
  */
88
- export async function performActions(actions) {
73
+ export async function performActions(this: XCUITestDriver, actions: ActionSequence[]): Promise<void> {
89
74
  this.log.debug(`Received the following W3C actions: ${JSON.stringify(actions, null, ' ')}`);
90
75
  assertNoWebElements(actions);
91
76
  // This is mandatory, since WDA only supports TOUCH pointer type
@@ -114,13 +99,14 @@ export async function performActions(actions) {
114
99
  }
115
100
 
116
101
  /**
117
- * @param {import('@appium/types').Element|string} el
118
- * @this {XCUITestDriver}
102
+ * Performs a native click on an element.
103
+ *
104
+ * @param el - Element to click
119
105
  * @group Native Only
120
106
  */
121
- export async function nativeClick(el) {
107
+ export async function nativeClick(this: XCUITestDriver, el: Element | string): Promise<void> {
122
108
  el = util.unwrapElement(el);
123
- let endpoint = `/element/${el}/click`;
109
+ const endpoint = `/element/${el}/click`;
124
110
  return await this.proxyCommand(endpoint, 'POST', {});
125
111
  }
126
112
 
@@ -132,17 +118,15 @@ export async function nativeClick(el) {
132
118
  * This API uses native XCTest calls, so it is performant. The same native call is implicitly performed by a `click` command if the destination element is outside the current viewport.
133
119
  *
134
120
  * @since 4.7.0
135
- * @throws If the scrolling action cannot be performed
121
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to scroll to. The destination element must be located in a scrollable container and must be hittable. If the element is already present in the current viewport then no action is performed.
122
+ * @throws {errors.InvalidArgumentError} If elementId is not provided
136
123
  * @privateRemarks See https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Commands/FBElementCommands.m for details on WDA gestures API
137
- * @param {Element|string} elementId - The internal element identifier (as hexadecimal hash string) to scroll to. The destination element must be located in a scrollable container and must be hittable. If the element is already present in the current viewport then no action is performed.
138
- * @returns {Promise<void>}
139
- * @this {XCUITestDriver}
140
124
  */
141
- export async function mobileScrollToElement(elementId) {
125
+ export async function mobileScrollToElement(this: XCUITestDriver, elementId: Element | string): Promise<void> {
142
126
  if (!elementId) {
143
127
  throw new errors.InvalidArgumentError('Element id must be provided');
144
128
  }
145
- return await this.proxyCommand(`/wda/element/${elementId}/scrollTo`, 'POST', {});
129
+ return await this.proxyCommand(`/wda/element/${util.unwrapElement(elementId)}/scrollTo`, 'POST', {});
146
130
  }
147
131
 
148
132
  /**
@@ -159,36 +143,32 @@ export async function mobileScrollToElement(elementId) {
159
143
  * - If it is necessary to perform many scroll gestures on parent container to reach the necessary child element (tens of them), then the method call may fail. *
160
144
  * - The implementation of this extension relies on several undocumented XCTest features, which might not always be reliable.
161
145
  *
162
- * @param {string} [name] - The internal element identifier (as hexadecimal hash string) to scroll on (e.g. the container). The Application element will be used if this argument is not provided.
163
- * @param {import('./types').Direction} [direction] - The main difference between this command and a `mobile: swipe` command using the same direction is that `mobile: scroll` will attempt to move the current viewport exactly to the next or previous page (the term "page" means the content, which fits into a single device screen).
164
- * @param {string} [predicateString] - The `NSPredicate` locator of the child element, to which the scrolling should be performed. Has no effect if `elementId` is not a container.
165
- * @param {boolean} [toVisible] - If `true`, scrolls to the first visible `elementId` in the parent container. Has no effect if `elementId` is unset.
166
- * @param {number} [distance] - A ratio of the screen height; `1.0` means a full-screen-worth of scrolling.
167
- * @param {Element|string} [elementId] - Element ID or Element used in various strategies.
168
- * @returns {Promise<void>}
169
- * @this {XCUITestDriver}
146
+ * @param name - The internal element identifier (as hexadecimal hash string) to scroll on (e.g. the container). The Application element will be used if this argument is not provided.
147
+ * @param direction - The main difference between this command and a `mobile: swipe` command using the same direction is that `mobile: scroll` will attempt to move the current viewport exactly to the next or previous page (the term "page" means the content, which fits into a single device screen).
148
+ * @param predicateString - The `NSPredicate` locator of the child element, to which the scrolling should be performed. Has no effect if `elementId` is not a container.
149
+ * @param toVisible - If `true`, scrolls to the first visible `elementId` in the parent container. Has no effect if `elementId` is unset.
150
+ * @param distance - A ratio of the screen height; `1.0` means a full-screen-worth of scrolling.
151
+ * @param elementId - Element ID or Element used in various strategies.
152
+ * @throws {errors.InvalidArgumentError} If no valid strategy is provided or if direction is invalid
170
153
  * @example
171
154
  * ```python
172
155
  * driver.execute_script('mobile: scroll', {'direction': 'down'})
173
156
  * ```
174
157
  */
175
- export async function mobileScroll(name, direction, predicateString, toVisible, distance, elementId) {
176
- /**
177
- * @todo This should be defined in WDA instead.
178
- * @typedef WdaScrollParams
179
- * @property {string} [name]
180
- * @property {import('./types').Direction} [direction]
181
- * @property {string} [predicateString]
182
- * @property {boolean} [toVisible]
183
- * @property {number} [distance]
184
- */
185
-
186
- /** @type {WdaScrollParams} */
187
- const params = {};
158
+ export async function mobileScroll(
159
+ this: XCUITestDriver,
160
+ name?: string,
161
+ direction?: Direction,
162
+ predicateString?: string,
163
+ toVisible?: boolean,
164
+ distance?: number,
165
+ elementId?: Element | string,
166
+ ): Promise<void> {
167
+ const params: WdaScrollParams = {};
188
168
  if (name) {
189
169
  params.name = name;
190
170
  } else if (direction) {
191
- if (!SUPPORTED_GESTURE_DIRECTIONS.includes(_.toLower(direction))) {
171
+ if (!SUPPORTED_GESTURE_DIRECTIONS.includes(_.toLower(direction) as any)) {
192
172
  throw new errors.InvalidArgumentError(
193
173
  `'direction' must be one of: ${SUPPORTED_GESTURE_DIRECTIONS}`,
194
174
  );
@@ -214,18 +194,25 @@ export async function mobileScroll(name, direction, predicateString, toVisible,
214
194
  }
215
195
 
216
196
  /**
217
- * @param {import('./types').Direction} direction
218
- * @param {number} [velocity]
219
- * @param {Element|string} [elementId]
220
- * @this {XCUITestDriver}
197
+ * Performs a swipe gesture in the specified direction.
198
+ *
199
+ * @param direction - Direction to swipe ('up', 'down', 'left', or 'right')
200
+ * @param velocity - Optional velocity of the swipe
201
+ * @param elementId - Optional element to swipe on. If not provided, swipes on the application element
202
+ * @throws {errors.InvalidArgumentError} If direction is invalid
221
203
  */
222
- export async function mobileSwipe(direction, velocity, elementId) {
223
- if (!SUPPORTED_GESTURE_DIRECTIONS.includes(_.toLower(direction))) {
204
+ export async function mobileSwipe(
205
+ this: XCUITestDriver,
206
+ direction: Direction,
207
+ velocity?: number,
208
+ elementId?: Element | string,
209
+ ): Promise<void> {
210
+ if (!SUPPORTED_GESTURE_DIRECTIONS.includes(_.toLower(direction) as any)) {
224
211
  throw new errors.InvalidArgumentError(
225
212
  `'direction' must be one of: ${SUPPORTED_GESTURE_DIRECTIONS}`,
226
213
  );
227
214
  }
228
- const params = {direction};
215
+ const params: {direction: Direction; velocity?: number} = {direction};
229
216
  if (!_.isNil(velocity)) {
230
217
  params.velocity = velocity;
231
218
  }
@@ -236,11 +223,9 @@ export async function mobileSwipe(direction, velocity, elementId) {
236
223
  /**
237
224
  * Performs a pinch gesture on the given element or on the Application element.
238
225
  *
239
- * @param {number} scale - Pinch scale (float value). A value between `0` and `1` performs a "pinch close" (or "zoom out"); a value greater than `1` performs a "pinch open" ("zoom in").
240
- * @param {number} velocity - The velocity of the pinch in scale factor per second (float value).
241
- * @param {Element|string} [elementId] The internal element identifier (as hexadecimal hash string) to pinch on. The Application element will be used if this parameter is not provided.
242
- * @returns {Promise<void>}
243
- * @this {XCUITestDriver}
226
+ * @param scale - Pinch scale (float value). A value between `0` and `1` performs a "pinch close" (or "zoom out"); a value greater than `1` performs a "pinch open" ("zoom in").
227
+ * @param velocity - The velocity of the pinch in scale factor per second (float value).
228
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to pinch on. The Application element will be used if this parameter is not provided.
244
229
  * @see https://developer.apple.com/documentation/xctest/xcuielement/1618669-pinchwithscale?language=objc
245
230
  * @example
246
231
  *
@@ -248,7 +233,12 @@ export async function mobileSwipe(direction, velocity, elementId) {
248
233
  * execute_script 'mobile: pinch', scale: 0.5, velocity: 1.1, element: element.ref
249
234
  * ```
250
235
  */
251
- export async function mobilePinch(scale, velocity, elementId) {
236
+ export async function mobilePinch(
237
+ this: XCUITestDriver,
238
+ scale: number,
239
+ velocity: number,
240
+ elementId?: Element | string,
241
+ ): Promise<void> {
252
242
  const params = {
253
243
  scale: requireFloat(scale, 'scale'),
254
244
  velocity: requireFloat(velocity, 'velocity'),
@@ -260,18 +250,21 @@ export async function mobilePinch(scale, velocity, elementId) {
260
250
  /**
261
251
  * Performs double tap gesture on the given element or on the screen.
262
252
  *
263
- * @param {Element|string} [elementId] - The internal element identifier (as hexadecimal hash string) to double tap on. The Application element will be used if this parameter is not provided.
264
- * @param {number} [x] - The _x_ coordinate (float value) to double tap on.
265
- * @param {number} [y] - The _y_ coordinate (float value) to double tap on.
266
- * @returns {Promise<void>}
267
- * @this {XCUITestDriver}
253
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to double tap on. The Application element will be used if this parameter is not provided.
254
+ * @param x - The _x_ coordinate (float value) to double tap on.
255
+ * @param y - The _y_ coordinate (float value) to double tap on.
268
256
  * @example
269
257
  * ```javascript
270
258
  * // using WebdriverIO
271
259
  * await driver.execute('mobile: doubleTap', {element: element.value.ELEMENT});
272
260
  * ```
273
261
  */
274
- export async function mobileDoubleTap(elementId, x, y) {
262
+ export async function mobileDoubleTap(
263
+ this: XCUITestDriver,
264
+ elementId?: Element | string,
265
+ x?: number,
266
+ y?: number,
267
+ ): Promise<void> {
275
268
  const endpoint = elementId ? `/wda/element/${util.unwrapElement(elementId)}/doubleTap` : '/wda/doubleTap';
276
269
  await this.proxyCommand(endpoint, 'POST', {x, y});
277
270
  }
@@ -279,9 +272,7 @@ export async function mobileDoubleTap(elementId, x, y) {
279
272
  /**
280
273
  * Performs two finger tap gesture on the given element or on the application element.
281
274
  *
282
- * @param {Element|string} [elementId] - The internal element identifier (as hexadecimal hash string) to double tap on. The Application element will be used if this parameter is not provided.
283
- * @returns {Promise<void>}
284
- * @this {XCUITestDriver}
275
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to double tap on. The Application element will be used if this parameter is not provided.
285
276
  * @see https://developer.apple.com/documentation/xctest/xcuielement/1618675-twofingertap?language=objc
286
277
  * @example
287
278
  * ```csharp
@@ -290,7 +281,7 @@ export async function mobileDoubleTap(elementId, x, y) {
290
281
  * ((IJavaScriptExecutor)driver).ExecuteScript("mobile: twoFingerTap", tfTap);
291
282
  * ```
292
283
  */
293
- export async function mobileTwoFingerTap(elementId) {
284
+ export async function mobileTwoFingerTap(this: XCUITestDriver, elementId?: Element | string): Promise<void> {
294
285
  const endpoint = elementId ? `/wda/element/${util.unwrapElement(elementId)}/twoFingerTap` : '/wda/twoFingerTap';
295
286
  await this.proxyCommand(endpoint, 'POST');
296
287
  }
@@ -298,11 +289,10 @@ export async function mobileTwoFingerTap(elementId) {
298
289
  /**
299
290
  * Performs a "long press" gesture on the given element or on the screen.
300
291
  *
301
- * @param {number} duration - The duration (in seconds) of the gesture.
302
- * @param {number} [y] - The _y_ coordinate (float value) to hold on.
303
- * @param {number} [x] - The _x_ coordinate (float value) to hold on.
304
- * @param {Element|string} [elementId] - The internal element identifier (as hexadecimal hash string) to double tap on. The Application element will be used if this parameter is not provided.
305
- * @this {XCUITestDriver}
292
+ * @param duration - The duration (in seconds) of the gesture.
293
+ * @param x - The _x_ coordinate (float value) to hold on.
294
+ * @param y - The _y_ coordinate (float value) to hold on.
295
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to hold on. The Application element will be used if this parameter is not provided.
306
296
  * @see https://developer.apple.com/documentation/xctest/xcuielement/1618663-pressforduration?language=objc
307
297
  * @example
308
298
  * ```csharp
@@ -312,7 +302,13 @@ export async function mobileTwoFingerTap(elementId) {
312
302
  * ((IJavaScriptExecutor)driver).ExecuteScript("mobile: touchAndHold", tfLongTap);
313
303
  * ```
314
304
  */
315
- export async function mobileTouchAndHold(duration, x, y, elementId) {
305
+ export async function mobileTouchAndHold(
306
+ this: XCUITestDriver,
307
+ duration: number,
308
+ x?: number,
309
+ y?: number,
310
+ elementId?: Element | string,
311
+ ): Promise<void> {
316
312
  const endpoint = elementId ? `/wda/element/${util.unwrapElement(elementId)}/touchAndHold` : '/wda/touchAndHold';
317
313
  await this.proxyCommand(endpoint, 'POST', {
318
314
  duration: requireFloat(duration, 'duration'),
@@ -323,13 +319,16 @@ export async function mobileTouchAndHold(duration, x, y, elementId) {
323
319
  /**
324
320
  * Performs tap gesture by coordinates on the given element or on the screen.
325
321
  *
326
- * @param {number} x - The _x_ coordinate (float value) to tap on. If `elementId` is provided, this is computed relative to the element; otherwise it is computed relative to the active Application element.
327
- * @param {number} y - The _y_ coordinate (float value) to tap on. If `elementId` is provided, this is computed relative to the element; otherwise it is computed relative to the active Application element.
328
- * @param {string|Element} [elementId] - The internal element identifier (as hexadecimal hash string) to tap on. The Application element will be used if this parameter is not provided.
329
- * @this {XCUITestDriver}
330
- * @returns {Promise<void>}
322
+ * @param x - The _x_ coordinate (float value) to tap on. If `elementId` is provided, this is computed relative to the element; otherwise it is computed relative to the active Application element.
323
+ * @param y - The _y_ coordinate (float value) to tap on. If `elementId` is provided, this is computed relative to the element; otherwise it is computed relative to the active Application element.
324
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to tap on. The Application element will be used if this parameter is not provided.
331
325
  */
332
- export async function mobileTap(x, y, elementId) {
326
+ export async function mobileTap(
327
+ this: XCUITestDriver,
328
+ x: number,
329
+ y: number,
330
+ elementId?: string | Element,
331
+ ): Promise<void> {
333
332
  const endpoint = elementId ? `/wda/element/${util.unwrapElement(elementId)}/tap` : '/wda/tap';
334
333
  await this.proxyCommand(endpoint, 'POST', {x, y});
335
334
  }
@@ -337,15 +336,13 @@ export async function mobileTap(x, y, elementId) {
337
336
  /**
338
337
  * Performs drag and drop gesture by coordinates on the given element or on the screen.
339
338
  *
340
- * @param {number} duration - The duration (in seconds) of the gesture. Must be between `0.5` and `60.0`, inclusive.
341
- * @param {number} fromX - The _x_ coordinate (float value) of the starting drag point.
342
- * @param {number} fromY - The _y_ coordinate (float value) of the starting drag point.
343
- * @param {number} toX - The _x_ coordinate (float value) of the ending drag point.
344
- * @param {number} toY - The _y_ coordinate (float value) of the ending drag point.
345
- * @param {string|Element} [elementId] - The internal element identifier (as hexadecimal hash string) to drag. If provided, all coordinates will be calculated relative to this element; otherwise they will be calculated relative to the active Application element.
346
- * @returns {Promise<void>}
339
+ * @param duration - The duration (in seconds) of the gesture. Must be between `0.5` and `60.0`, inclusive.
340
+ * @param fromX - The _x_ coordinate (float value) of the starting drag point.
341
+ * @param fromY - The _y_ coordinate (float value) of the starting drag point.
342
+ * @param toX - The _x_ coordinate (float value) of the ending drag point.
343
+ * @param toY - The _y_ coordinate (float value) of the ending drag point.
344
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to drag. If provided, all coordinates will be calculated relative to this element; otherwise they will be calculated relative to the active Application element.
347
345
  * @see https://developer.apple.com/documentation/xctest/xcuielement/1500989-clickforduration?language=objc
348
- * @this {XCUITestDriver}
349
346
  * @example
350
347
  * ```java
351
348
  * JavascriptExecutor js = (JavascriptExecutor) driver;
@@ -359,7 +356,15 @@ export async function mobileTap(x, y, elementId) {
359
356
  * js.executeScript("mobile: dragFromToForDuration", params);
360
357
  * ```
361
358
  */
362
- export async function mobileDragFromToForDuration(duration, fromX, fromY, toX, toY, elementId) {
359
+ export async function mobileDragFromToForDuration(
360
+ this: XCUITestDriver,
361
+ duration: number,
362
+ fromX: number,
363
+ fromY: number,
364
+ toX: number,
365
+ toY: number,
366
+ elementId?: string | Element,
367
+ ): Promise<void> {
363
368
  const params = {
364
369
  duration: requireFloat(duration, 'duration'),
365
370
  fromX: requireFloat(fromX, 'fromX'),
@@ -377,32 +382,41 @@ export async function mobileDragFromToForDuration(duration, fromX, fromY, toX, t
377
382
  /**
378
383
  * Initiates a press-and-hold gesture, drags to another coordinate or an element with a given velocity, and holds for a given duration.
379
384
  *
380
- * @param {number} pressDuration - The duration (in seconds) of the press-and-hold gesture at the starting point. Must be between `0.5` and `60.0`, inclusive.
381
- * @param {number} holdDuration - The duration (in seconds) of the hold gesture at the ending point (after dragging). Must be between `0.5` and `60.0`, inclusive.
382
- * @param {number} velocity - The speed (in pixels-per-second) which to move from the initial position to the end position.
383
- * @param {string|Element} [fromElementId] - The internal element identifier (as hexadecimal hash string) to drag from. Absolute screen coordinates are expected if this argument is not provided.
384
- * @param {string|Element} [toElementId] - The internal element identifier (as hexadecimal hash string) to drag to. Absolute screen coordinates are expected if this argument is not provided.
385
- * @param {number} [fromX] - The _x_ coordinate (float value) of the starting drag point.
386
- * @param {number} [fromY] - The _y_ coordinate (float value) of the starting drag point.
387
- * @param {number} [toX] - The _x_ coordinate (float value) of the ending drag point.
388
- * @param {number} [toY] - The _y_ coordinate (float value) of the ending drag point.
389
- * @returns {Promise<void>}
385
+ * @param pressDuration - The duration (in seconds) of the press-and-hold gesture at the starting point. Must be between `0.5` and `60.0`, inclusive.
386
+ * @param holdDuration - The duration (in seconds) of the hold gesture at the ending point (after dragging). Must be between `0.5` and `60.0`, inclusive.
387
+ * @param velocity - The speed (in pixels-per-second) which to move from the initial position to the end position.
388
+ * @param fromElementId - The internal element identifier (as hexadecimal hash string) to drag from. Absolute screen coordinates are expected if this argument is not provided.
389
+ * @param toElementId - The internal element identifier (as hexadecimal hash string) to drag to. Absolute screen coordinates are expected if this argument is not provided.
390
+ * @param fromX - The _x_ coordinate (float value) of the starting drag point.
391
+ * @param fromY - The _y_ coordinate (float value) of the starting drag point.
392
+ * @param toX - The _x_ coordinate (float value) of the ending drag point.
393
+ * @param toY - The _y_ coordinate (float value) of the ending drag point.
394
+ * @throws {errors.InvalidArgumentError} If toElementId is missing when fromElementId is provided, or if coordinates are missing when fromElementId is not provided
390
395
  * @see https://developer.apple.com/documentation/xctest/xcuielement/3551693-pressforduration?language=objc
391
396
  * @see https://developer.apple.com/documentation/xctest/xcuicoordinate/3551692-pressforduration?language=objc
392
- * @this {XCUITestDriver}
393
397
  */
394
398
  export async function mobileDragFromToWithVelocity(
395
- pressDuration,
396
- holdDuration,
397
- velocity,
398
- fromElementId,
399
- toElementId,
400
- fromX,
401
- fromY,
402
- toX,
403
- toY,
404
- ) {
405
- const params = {
399
+ this: XCUITestDriver,
400
+ pressDuration: number,
401
+ holdDuration: number,
402
+ velocity: number,
403
+ fromElementId?: Element | string,
404
+ toElementId?: Element | string,
405
+ fromX?: number,
406
+ fromY?: number,
407
+ toX?: number,
408
+ toY?: number,
409
+ ): Promise<void> {
410
+ const params: {
411
+ pressDuration: number;
412
+ holdDuration: number;
413
+ velocity: number;
414
+ toElement?: string;
415
+ fromX?: number;
416
+ fromY?: number;
417
+ toX?: number;
418
+ toY?: number;
419
+ } = {
406
420
  pressDuration: requireFloat(pressDuration, 'pressDuration'),
407
421
  holdDuration: requireFloat(holdDuration, 'holdDuration'),
408
422
  velocity: requireFloat(velocity, 'velocity'),
@@ -422,6 +436,11 @@ export async function mobileDragFromToWithVelocity(
422
436
  params,
423
437
  );
424
438
  }
439
+ if (fromX === undefined || fromY === undefined || toX === undefined || toY === undefined) {
440
+ throw new errors.InvalidArgumentError(
441
+ 'When fromElementId is not provided, fromX, fromY, toX, and toY must all be provided',
442
+ );
443
+ }
425
444
  params.fromX = requireFloat(fromX, 'fromX');
426
445
  params.fromY = requireFloat(fromY, 'fromY');
427
446
  params.toX = requireFloat(toX, 'toX');
@@ -433,12 +452,9 @@ export async function mobileDragFromToWithVelocity(
433
452
  * Sends one or more taps with one or more touch points.
434
453
  *
435
454
  * @since 1.17.1
436
- * @param {number} [numberOfTaps=1] - Number of taps to perform.
437
- * @param {number} [numberOfTouches=1] - Number of touch points to use.
438
- * @param {string|Element} [elementId] - The internal element identifier (as hexadecimal hash string) to perform one or more taps.
439
- * The Application element will be used if this parameter is not provided.
440
- * @returns {Promise<void>}
441
- * @this {XCUITestDriver}
455
+ * @param numberOfTaps - Number of taps to perform.
456
+ * @param numberOfTouches - Number of touch points to use.
457
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to perform one or more taps. The Application element will be used if this parameter is not provided.
442
458
  * @see https://developer.apple.com/documentation/xctest/xcuielement/1618671-tapwithnumberoftaps?language=objc
443
459
  * @example
444
460
  * ```ruby
@@ -447,7 +463,12 @@ export async function mobileDragFromToWithVelocity(
447
463
  * @driver.execute_script 'mobile: tapWithNumberOfTaps', {element: e.ref, numberOfTaps: 2, numberOfTouches: 1}
448
464
  * ```
449
465
  */
450
- export async function mobileTapWithNumberOfTaps(numberOfTouches = 1, numberOfTaps = 1, elementId = undefined) {
466
+ export async function mobileTapWithNumberOfTaps(
467
+ this: XCUITestDriver,
468
+ numberOfTouches: number = 1,
469
+ numberOfTaps: number = 1,
470
+ elementId: Element | string | undefined = undefined,
471
+ ): Promise<void> {
451
472
  const endpoint = elementId
452
473
  ? `/wda/element/${util.unwrapElement(elementId)}/tapWithNumberOfTaps`
453
474
  : '/wda/tapWithNumberOfTaps';
@@ -461,16 +482,21 @@ export async function mobileTapWithNumberOfTaps(numberOfTouches = 1, numberOfTap
461
482
  * Performs a "force press" on the given element or coordinates.
462
483
  *
463
484
  * @throws If the target device does not support the "force press" gesture.
464
- * @param {number} [x] - The _x_ coordinate of the gesture. If `elementId` is set, this is calculated relative to its position; otherwise it's calculated relative to the active Application.
465
- * @param {number} [y] - The _y_ coordinate of the gesture. If `elementId` is set, this is calculated relative to its position; otherwise it's calculated relative to the active Application.
466
- * @param {number} [duration] - The duration (in seconds) of the force press. If this is provided, `pressure` must also be provided.
467
- * @param {number} [pressure] - A float value defining the pressure of the force press. If this is provided, `duration` must also be provided.
468
- * @param {string|Element} [elementId] - The internal element identifier (as hexadecimal hash string) to perform one or more taps.
469
- * The Application element will be used if this parameter is not provided.
470
- * @returns {Promise<void>}
471
- * @this {XCUITestDriver}
485
+ * @param x - The _x_ coordinate of the gesture. If `elementId` is set, this is calculated relative to its position; otherwise it's calculated relative to the active Application.
486
+ * @param y - The _y_ coordinate of the gesture. If `elementId` is set, this is calculated relative to its position; otherwise it's calculated relative to the active Application.
487
+ * @param duration - The duration (in seconds) of the force press. If this is provided, `pressure` must also be provided.
488
+ * @param pressure - A float value defining the pressure of the force press. If this is provided, `duration` must also be provided.
489
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to perform one or more taps. The Application element will be used if this parameter is not provided.
490
+ * @throws {Error} If the target device does not support the "force press" gesture
472
491
  */
473
- export async function mobileForcePress(x, y, duration, pressure, elementId) {
492
+ export async function mobileForcePress(
493
+ this: XCUITestDriver,
494
+ x?: number,
495
+ y?: number,
496
+ duration?: number,
497
+ pressure?: number,
498
+ elementId?: Element | string,
499
+ ): Promise<void> {
474
500
  const endpoint = elementId ? `/wda/element/${util.unwrapElement(elementId)}/forceTouch` : `/wda/forceTouch`;
475
501
  return await this.proxyCommand(endpoint, 'POST', {x, y, duration, pressure});
476
502
  }
@@ -481,12 +507,12 @@ export async function mobileForcePress(x, y, duration, pressure, elementId) {
481
507
  * This might be useful if these values are populated dynamically; you don't know which one to select, or the value selection using the `sendKeys` API does not work (for whatever reason).
482
508
  *
483
509
  * @throws Upon failure to change the current picker value.
484
- * @param {string|Element} elementId - `PickerWheel`'s internal element ID as hexadecimal hash string. Value selection will be performed on this element. This element must be of type `XCUIElementTypePickerWheel`.
485
- * @param {'next'|'previous'} order - Either `next` to select the value _next_ to the current from the target picker wheel, or `previous` to select the _previous_ value.
486
- * @param {number} [offset=0.2] - The value in range `[0.01, 0.5]`. It defines how far from picker wheel's center the click should happen. The actual distance is calculated by multiplying this value to the actual picker wheel height. Too small an offset value may not change the picker wheel value at all, and too high a value may cause the wheel to switch two or more values at once. Usually the optimal value is located in range `[0.15, 0.3]`.
487
- * @param {string?} [value=undefined] - If provided WDA will try to automatically scroll in the given direction until the actual picker value reaches the expected one or the amount of scrolling attempts is exceeded.
488
- * @param {number} [maxAttempts=25] - The maximum number of scrolling attempts to reach `value` before an error will be thrown. Only makes sense in combination with `value`.
489
- * @this {XCUITestDriver}
510
+ * @param elementId - `PickerWheel`'s internal element ID as hexadecimal hash string. Value selection will be performed on this element. This element must be of type `XCUIElementTypePickerWheel`.
511
+ * @param order - Either `next` to select the value _next_ to the current from the target picker wheel, or `previous` to select the _previous_ value.
512
+ * @param offset - The value in range `[0.01, 0.5]`. It defines how far from picker wheel's center the click should happen. The actual distance is calculated by multiplying this value to the actual picker wheel height. Too small an offset value may not change the picker wheel value at all, and too high a value may cause the wheel to switch two or more values at once. Usually the optimal value is located in range `[0.15, 0.3]`.
513
+ * @param value - If provided WDA will try to automatically scroll in the given direction until the actual picker value reaches the expected one or the amount of scrolling attempts is exceeded.
514
+ * @param maxAttempts - The maximum number of scrolling attempts to reach `value` before an error will be thrown. Only makes sense in combination with `value`.
515
+ * @throws {errors.InvalidArgumentError} If elementId is not provided or if order is invalid
490
516
  * @example
491
517
  * ```java
492
518
  * JavascriptExecutor js = (JavascriptExecutor) driver;
@@ -497,7 +523,14 @@ export async function mobileForcePress(x, y, duration, pressure, elementId) {
497
523
  * js.executeScript("mobile: selectPickerWheelValue", params);
498
524
  * ```
499
525
  */
500
- export async function mobileSelectPickerWheelValue(elementId, order, offset, value, maxAttempts) {
526
+ export async function mobileSelectPickerWheelValue(
527
+ this: XCUITestDriver,
528
+ elementId: Element | string,
529
+ order: string,
530
+ offset?: number,
531
+ value?: string,
532
+ maxAttempts?: number,
533
+ ): Promise<void> {
501
534
  if (!elementId) {
502
535
  throw new errors.InvalidArgumentError(
503
536
  'elementId is expected to be set for selectPickerWheelValue method',
@@ -509,7 +542,7 @@ export async function mobileSelectPickerWheelValue(elementId, order, offset, val
509
542
  `'${order}' is given instead`,
510
543
  );
511
544
  }
512
- const params = {order};
545
+ const params: {order: string; offset?: number; value?: string; maxAttempts?: number} = {order};
513
546
  if (offset) {
514
547
  params.offset = requireFloat(offset, 'offset');
515
548
  }
@@ -526,12 +559,10 @@ export async function mobileSelectPickerWheelValue(elementId, order, offset, val
526
559
  * Performs a rotate gesture on the given element.
527
560
  *
528
561
  * @see https://developer.apple.com/documentation/xctest/xcuielement/1618665-rotate?language=objc
529
- * @param {number} rotation - The rotation gesture (in radians)
530
- * @param {number} velocity - The velocity (in radians-per-second) of the gesture.
531
- * @param {string|Element} [elementId] - The internal element identifier (as hexadecimal hash string) to perform the gesture on.
562
+ * @param rotation - The rotation gesture (in radians)
563
+ * @param velocity - The velocity (in radians-per-second) of the gesture.
564
+ * @param elementId - The internal element identifier (as hexadecimal hash string) to perform the gesture on.
532
565
  * The Application element will be used if this parameter is not provided.
533
- * @returns {Promise<void>}
534
- * @this {XCUITestDriver}
535
566
  * @example
536
567
  * ```java
537
568
  * JavascriptExecutor js = (JavascriptExecutor) driver;
@@ -544,20 +575,28 @@ export async function mobileSelectPickerWheelValue(elementId, order, offset, val
544
575
  * ));
545
576
  * ```
546
577
  */
547
- export async function mobileRotateElement(rotation, velocity, elementId) {
578
+ export async function mobileRotateElement(
579
+ this: XCUITestDriver,
580
+ rotation: number,
581
+ velocity: number,
582
+ elementId?: Element | string,
583
+ ): Promise<void> {
548
584
  const params = {
549
585
  rotation: requireFloat(rotation, 'rotation'),
550
586
  velocity: requireFloat(velocity, 'velocity'),
551
587
  };
552
588
  const endpoint = elementId ? `/wda/element/${util.unwrapElement(elementId)}/rotate` : '/wda/rotate';
553
- return await this.proxyCommand(endpoint, 'POST', params);
589
+ await this.proxyCommand(endpoint, 'POST', params);
554
590
  }
555
591
 
556
592
  /**
557
- * @param {import('@appium/types').ActionSequence[]} actionSeq
593
+ * Asserts that the action sequence does not contain web elements.
594
+ *
595
+ * @param actionSeq - Action sequence to check
596
+ * @throws {errors.InvalidArgumentError} If web elements are found in the action sequence
558
597
  */
559
- function assertNoWebElements(actionSeq) {
560
- const isOriginWebElement = (gesture) =>
598
+ function assertNoWebElements(actionSeq: ActionSequence[]): void {
599
+ const isOriginWebElement = (gesture: any) =>
561
600
  _.isPlainObject(gesture) && 'origin' in gesture && JSON.stringify(gesture.origin).includes(':wdc:');
562
601
  const hasWebElements = actionSeq
563
602
  .some((action) => (action?.actions || []).some(isOriginWebElement));
@@ -575,12 +614,12 @@ function assertNoWebElements(actionSeq) {
575
614
  /**
576
615
  * Converts the given value to a float number.
577
616
  *
578
- * @throws If `value` is `NaN`
579
- * @param {any} value
580
- * @param {string} paramName
581
- * @returns {number}
617
+ * @param value - Value to convert
618
+ * @param paramName - Name of the parameter (for error messages)
619
+ * @returns The float value
620
+ * @throws {errors.InvalidArgumentError} If `value` is `NaN`
582
621
  */
583
- function requireFloat(value, paramName) {
622
+ function requireFloat(value: any, paramName: string): number {
584
623
  const num = parseFloat(String(value));
585
624
  if (Number.isNaN(num)) {
586
625
  throw new errors.InvalidArgumentError(
@@ -590,7 +629,10 @@ function requireFloat(value, paramName) {
590
629
  return num;
591
630
  }
592
631
 
593
- /**
594
- * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
595
- * @typedef {import('@appium/types').Element} Element
596
- */
632
+ interface WdaScrollParams {
633
+ name?: string;
634
+ direction?: Direction;
635
+ predicateString?: string;
636
+ toVisible?: boolean;
637
+ distance?: number;
638
+ }