appium-xcuitest-driver 10.14.0 → 10.14.2

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 (60) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/commands/condition.d.ts +9 -72
  3. package/build/lib/commands/condition.d.ts.map +1 -1
  4. package/build/lib/commands/condition.js +5 -66
  5. package/build/lib/commands/condition.js.map +1 -1
  6. package/build/lib/commands/execute.d.ts +10 -22
  7. package/build/lib/commands/execute.d.ts.map +1 -1
  8. package/build/lib/commands/execute.js +12 -28
  9. package/build/lib/commands/execute.js.map +1 -1
  10. package/build/lib/commands/location.d.ts +8 -11
  11. package/build/lib/commands/location.d.ts.map +1 -1
  12. package/build/lib/commands/location.js +7 -15
  13. package/build/lib/commands/location.js.map +1 -1
  14. package/build/lib/commands/navigation.d.ts +14 -26
  15. package/build/lib/commands/navigation.d.ts.map +1 -1
  16. package/build/lib/commands/navigation.js +10 -18
  17. package/build/lib/commands/navigation.js.map +1 -1
  18. package/build/lib/commands/pcap.d.ts +18 -38
  19. package/build/lib/commands/pcap.d.ts.map +1 -1
  20. package/build/lib/commands/pcap.js +9 -14
  21. package/build/lib/commands/pcap.js.map +1 -1
  22. package/build/lib/commands/record-audio.d.ts +25 -53
  23. package/build/lib/commands/record-audio.d.ts.map +1 -1
  24. package/build/lib/commands/record-audio.js +17 -19
  25. package/build/lib/commands/record-audio.js.map +1 -1
  26. package/build/lib/commands/screenshots.d.ts +15 -9
  27. package/build/lib/commands/screenshots.d.ts.map +1 -1
  28. package/build/lib/commands/screenshots.js +13 -11
  29. package/build/lib/commands/screenshots.js.map +1 -1
  30. package/build/lib/commands/source.d.ts +10 -8
  31. package/build/lib/commands/source.d.ts.map +1 -1
  32. package/build/lib/commands/source.js +11 -14
  33. package/build/lib/commands/source.js.map +1 -1
  34. package/build/lib/commands/types.d.ts +58 -0
  35. package/build/lib/commands/types.d.ts.map +1 -1
  36. package/build/lib/commands/xctest-record-screen.d.ts +17 -47
  37. package/build/lib/commands/xctest-record-screen.d.ts.map +1 -1
  38. package/build/lib/commands/xctest-record-screen.js +28 -59
  39. package/build/lib/commands/xctest-record-screen.js.map +1 -1
  40. package/build/lib/driver.d.ts +1 -1
  41. package/build/lib/driver.d.ts.map +1 -1
  42. package/build/lib/driver.js +1 -1
  43. package/build/lib/driver.js.map +1 -1
  44. package/build/lib/execute-method-map.d.ts.map +1 -1
  45. package/build/lib/execute-method-map.js +0 -6
  46. package/build/lib/execute-method-map.js.map +1 -1
  47. package/lib/commands/{condition.js → condition.ts} +21 -77
  48. package/lib/commands/{execute.js → execute.ts} +41 -37
  49. package/lib/commands/{location.js → location.ts} +19 -22
  50. package/lib/commands/{navigation.js → navigation.ts} +23 -26
  51. package/lib/commands/{pcap.js → pcap.ts} +28 -28
  52. package/lib/commands/{record-audio.js → record-audio.ts} +35 -33
  53. package/lib/commands/{screenshots.js → screenshots.ts} +24 -16
  54. package/lib/commands/{source.js → source.ts} +23 -20
  55. package/lib/commands/types.ts +63 -0
  56. package/lib/commands/{xctest-record-screen.js → xctest-record-screen.ts} +54 -71
  57. package/lib/driver.ts +2 -2
  58. package/lib/execute-method-map.ts +0 -6
  59. package/npm-shrinkwrap.json +2 -2
  60. package/package.json +1 -1
@@ -1,24 +1,25 @@
1
1
  import {INSTRUMENT_CHANNEL, services} from 'appium-ios-device';
2
2
  import _ from 'lodash';
3
3
  import { isIos18OrNewer } from '../utils';
4
+ import type {XCUITestDriver} from '../driver';
5
+ import type {DVTServiceWithConnection} from 'appium-ios-remotexpc';
6
+ import type {Condition} from './types';
4
7
 
5
8
  /**
6
9
  * Get all available ConditionInducer configuration information, which can be used with
7
10
  * {@linkcode XCUITestDriver.enableConditionInducer}
8
- * @returns {Promise<Condition[]>}
9
11
  * @since 4.9.0
10
12
  * @see {@link https://help.apple.com/xcode/mac/current/#/dev308429d42}
11
- * @this {XCUITestDriver}
12
13
  */
13
- export async function listConditionInducers() {
14
+ export async function listConditionInducers(this: XCUITestDriver): Promise<Condition[]> {
14
15
  requireConditionInducerCompatibleDevice.call(this);
15
16
 
16
17
  if (isIos18OrNewer(this.opts)) {
17
18
  const dvtConnection = await startRemoteXPC(this.device.udid);
18
19
  try {
19
20
  const result = await dvtConnection.conditionInducer.list();
20
- return /** @type {Condition[]} */ (result);
21
- } catch (err) {
21
+ return result as Condition[];
22
+ } catch (err: any) {
22
23
  this.log.error(`Failed to list condition inducers via RemoteXPC: ${err.message}`);
23
24
  throw err;
24
25
  } finally {
@@ -50,15 +51,18 @@ export async function listConditionInducers() {
50
51
  * (Note: the socket needs to remain connected during operation)
51
52
  * (Note: Device conditions are available only for real devices running iOS 13.0 and later.)
52
53
  *
53
- * @param {string} conditionID - Determine which condition IDs are available with the {@linkcode XCUITestDriver.listConditionInducers} command
54
- * @param {string} profileID - Determine which profile IDs are available with the {@linkcode XCUITestDriver.listConditionInducers} command
55
- * @returns {Promise<boolean>} `true` if enabling the condition succeeded
54
+ * @param conditionID - Determine which condition IDs are available with the {@linkcode XCUITestDriver.listConditionInducers} command
55
+ * @param profileID - Determine which profile IDs are available with the {@linkcode XCUITestDriver.listConditionInducers} command
56
+ * @returns `true` if enabling the condition succeeded
56
57
  * @throws {Error} If you try to start another Condition and the previous Condition has not stopped
57
58
  * @since 4.9.0
58
59
  * @see {@link https://help.apple.com/xcode/mac/current/#/dev308429d42}
59
- * @this {XCUITestDriver}
60
60
  */
61
- export async function enableConditionInducer(conditionID, profileID) {
61
+ export async function enableConditionInducer(
62
+ this: XCUITestDriver,
63
+ conditionID: string,
64
+ profileID: string,
65
+ ): Promise<boolean> {
62
66
  requireConditionInducerCompatibleDevice.call(this);
63
67
 
64
68
  if (isIos18OrNewer(this.opts)) {
@@ -76,7 +80,7 @@ export async function enableConditionInducer(conditionID, profileID) {
76
80
 
77
81
  this.log.info(`Successfully enabled condition profile: ${profileID}`);
78
82
  return true;
79
- } catch (err) {
83
+ } catch (err: any) {
80
84
  await closeRemoteXPC.call(this);
81
85
  throw this.log.errorWithException(`Condition inducer '${profileID}' cannot be enabled: '${err.message}'`);
82
86
  }
@@ -109,12 +113,11 @@ export async function enableConditionInducer(conditionID, profileID) {
109
113
  * condition inducer will be automatically disabled
110
114
  *
111
115
  * (Note: this is also automatically called upon session cleanup)
112
- * @returns {Promise<boolean>} `true` if disable the condition succeeded
116
+ * @returns `true` if disable the condition succeeded
113
117
  * @since 4.9.0
114
118
  * @see {@link https://help.apple.com/xcode/mac/current/#/dev308429d42}
115
- * @this {XCUITestDriver}
116
119
  */
117
- export async function disableConditionInducer() {
120
+ export async function disableConditionInducer(this: XCUITestDriver): Promise<boolean> {
118
121
  requireConditionInducerCompatibleDevice.call(this);
119
122
 
120
123
  if (isIos18OrNewer(this.opts)) {
@@ -127,7 +130,7 @@ export async function disableConditionInducer() {
127
130
  await this._remoteXPCConditionInducerConnection.conditionInducer.disable();
128
131
  this.log.info('Successfully disabled condition inducer');
129
132
  return true;
130
- } catch (err) {
133
+ } catch (err: any) {
131
134
  this.log.warn(`Failed to disable condition inducer via RemoteXPC: ${err.message}`);
132
135
  return false;
133
136
  } finally {
@@ -158,81 +161,22 @@ export async function disableConditionInducer() {
158
161
  }
159
162
  }
160
163
 
161
- /**
162
- * @this {XCUITestDriver}
163
- * @returns {void}
164
- */
165
- function requireConditionInducerCompatibleDevice() {
164
+ function requireConditionInducerCompatibleDevice(this: XCUITestDriver): void {
166
165
  if (this.isSimulator()) {
167
166
  throw this.log.errorWithException('Condition inducer only works on real devices');
168
167
  }
169
168
  }
170
169
 
171
- /**
172
- * @param {string} udid
173
- * @returns {Promise<DVTServiceWithConnection>}
174
- */
175
- async function startRemoteXPC(udid) {
170
+ async function startRemoteXPC(udid: string): Promise<DVTServiceWithConnection> {
176
171
  const {Services} = await import('appium-ios-remotexpc');
177
172
  return Services.startDVTService(udid);
178
173
  }
179
174
 
180
- /**
181
- * @this {XCUITestDriver}
182
- * @returns {Promise<void>}
183
- */
184
- async function closeRemoteXPC() {
175
+ async function closeRemoteXPC(this: XCUITestDriver): Promise<void> {
185
176
  if (this._remoteXPCConditionInducerConnection) {
186
177
  await this._remoteXPCConditionInducerConnection.remoteXPC.close();
187
178
  this._remoteXPCConditionInducerConnection = null;
188
179
  }
189
180
  }
190
181
 
191
- /**
192
- * @typedef {import('appium-ios-remotexpc', {with: {'resolution-mode': 'import'}}).DVTServiceWithConnection} DVTServiceWithConnection
193
- */
194
-
195
- /**
196
- * @typedef {Object} Profile
197
- * @property {string} name
198
- * @property {string} identifier the property is profileID used in {@linkcode XCUITestDriver.enableConditionInducer}
199
- * @property {string} description Configuration details
200
- */
201
-
202
- /**
203
- * We can use the returned data to determine whether the Condition is enabled and the currently enabled configuration information
204
- * @typedef {Object} Condition
205
- * @property {Profile[]} profiles
206
- * @property {string} identifier the property is conditionID used in {@linkcode XCUITestDriver.enableConditionInducer}
207
- * @property {boolean} profilesSorted
208
- * @property {boolean} isDestructive
209
- * @property {boolean} isInternal
210
- * @property {boolean} isActive `true` if this condition identifier is enabled
211
- * @property {string} activeProfile enabled profiles identifier
212
- * @example {
213
- * "profiles": [
214
- * {
215
- * "name": "100% packet loss",
216
- * "identifier": "SlowNetwork100PctLoss", // MobileEnableConditionInducer profileID
217
- * "description": "Name: 100% Loss Scenario\n
218
- * Downlink Bandwidth: 0 Mbps\n
219
- * Downlink Latency:0 ms\n
220
- * Downlink Packet Loss Ratio: 100%\n
221
- * Uplink Bandwidth: 0 Mbps\n
222
- * Uplink Latency: 0 ms\n
223
- * Uplink Packet Loss Ratio: 100%"
224
- * }
225
- * ],
226
- * "profilesSorted": true,
227
- * "identifier": "SlowNetworkCondition", // MobileEnableConditionInducer conditionID
228
- * "isDestructive": false,
229
- * "isInternal": false,
230
- * "activeProfile": "",
231
- * "name": "Network Link",
232
- * "isActive": false
233
- * }
234
- */
235
182
 
236
- /**
237
- * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
238
- */
@@ -2,14 +2,18 @@ import _ from 'lodash';
2
2
  import {XCUITestDriver} from '../driver';
3
3
  import {errors, errorFromCode, errorFromW3CJsonCode} from 'appium/driver';
4
4
  import {util} from 'appium/support';
5
+ import type {Element, StringRecord} from '@appium/types';
5
6
 
6
7
  /**
7
8
  * Collect the response of an async script execution
8
- * @this {XCUITestDriver}
9
9
  * @deprecated
10
10
  * @privateRemarks It's unclear what this is for. Don't use it.
11
11
  */
12
- export async function receiveAsyncResponse(status, value) {
12
+ export async function receiveAsyncResponse(
13
+ this: XCUITestDriver,
14
+ status: number | null | undefined,
15
+ value: any,
16
+ ): Promise<void> {
13
17
  this.log.debug(`Received async response: ${JSON.stringify(value)}`);
14
18
  if (!util.hasValue(this.asyncPromise)) {
15
19
  this.log.warn(
@@ -33,21 +37,22 @@ export async function receiveAsyncResponse(status, value) {
33
37
  }
34
38
 
35
39
  /**
36
- * @template {ExecuteMethodArgs} [TArgs = unknown[]]
37
- * @template [TReturn = unknown]
38
- * @param {string} script - Either a script to run, or in the case of an Execute Method, the name of the script to execute.
39
- * @param {TArgs} [args]
40
- * @this {XCUITestDriver}
41
- * @returns {Promise<TReturn>}
40
+ * @template TReturn
41
+ * @param script - Either a script to run, or in the case of an Execute Method, the name of the script to execute.
42
+ * @param args
42
43
  */
43
- export async function execute(script, args) {
44
+ export async function execute<TReturn = unknown>(
45
+ this: XCUITestDriver,
46
+ script: string,
47
+ args?: ExecuteMethodArgs,
48
+ ): Promise<TReturn> {
44
49
  // TODO: create a type that converts args to the parameters of the associated method using the `command` prop of `executeMethodMap`
45
50
  script = script.trim().replace(/^mobile:\s*/, 'mobile: ');
46
51
  if (isExecuteMethod(script)) {
47
- const executeMethodArgs = preprocessExecuteMethodArgs(script, args);
52
+ const executeMethodArgs = preprocessExecuteMethodArgs(script, args as ExecuteMethodArgs | undefined);
48
53
  return await this.executeMethod(script, [executeMethodArgs]);
49
54
  } else if (this.isWebContext()) {
50
- const atomsArgs = this.convertElementsForAtoms(/** @type {readonly any[]} */ (args));
55
+ const atomsArgs = this.convertElementsForAtoms(args as readonly any[] | undefined);
51
56
  const result = await this.executeAtom('execute_script', [script, atomsArgs]);
52
57
  return this.cacheWebElements(result);
53
58
  } else {
@@ -56,10 +61,13 @@ export async function execute(script, args) {
56
61
  }
57
62
 
58
63
  /**
59
- * @this {XCUITestDriver}
60
64
  * @group Mobile Web Only
61
65
  */
62
- export async function executeAsync(script, args) {
66
+ export async function executeAsync(
67
+ this: XCUITestDriver,
68
+ script: string,
69
+ args?: readonly any[],
70
+ ): Promise<any> {
63
71
  if (!this.isWebContext()) {
64
72
  throw new errors.NotImplementedError();
65
73
  }
@@ -77,16 +85,17 @@ export async function executeAsync(script, args) {
77
85
 
78
86
  /**
79
87
  * Checks if script expects a particular parameter (either optional or required).
80
- * @template {keyof XCUITestDriver.executeMethodMap} Script
81
- * @param {Script} script - Script name
82
- * @param {string} param - Parameter name
88
+ * @template Script
89
+ * @param script - Script name
90
+ * @param param - Parameter name
83
91
  * @returns {boolean}
84
92
  */
85
- function executeMethodExpectsParam(script, param) {
86
- /** @type {ReadonlyArray<string>|undefined} */
87
- let required;
88
- /** @type {ReadonlyArray<string>|undefined} */
89
- let optional;
93
+ function executeMethodExpectsParam<Script extends keyof typeof XCUITestDriver.executeMethodMap>(
94
+ script: Script,
95
+ param: string,
96
+ ): boolean {
97
+ let required: ReadonlyArray<string> | undefined;
98
+ let optional: ReadonlyArray<string> | undefined;
90
99
  const execMethodDef = XCUITestDriver.executeMethodMap[script];
91
100
  if ('params' in execMethodDef) {
92
101
  if ('required' in execMethodDef.params) {
@@ -101,24 +110,26 @@ function executeMethodExpectsParam(script, param) {
101
110
  }
102
111
 
103
112
  /**
104
- * @param {any} script
113
+ * @param script
105
114
  * @returns {script is keyof XCUITestDriver.executeMethodMap}
106
115
  */
107
- function isExecuteMethod(script) {
116
+ function isExecuteMethod(script: string): script is keyof typeof XCUITestDriver.executeMethodMap {
108
117
  return script in XCUITestDriver.executeMethodMap;
109
118
  }
110
119
 
111
120
  /**
112
121
  * Massages the arguments going into an execute method.
113
- * @param {keyof XCUITestDriver.executeMethodMap} script
114
- * @param {ExecuteMethodArgs} [args]
115
- * @returns {StringRecord<unknown>}
122
+ * @param script
123
+ * @param args
116
124
  */
117
- function preprocessExecuteMethodArgs(script, args) {
125
+ function preprocessExecuteMethodArgs(
126
+ script: keyof typeof XCUITestDriver.executeMethodMap,
127
+ args?: ExecuteMethodArgs,
128
+ ): StringRecord<unknown> {
118
129
  if (_.isArray(args)) {
119
130
  args = _.first(args);
120
131
  }
121
- const executeMethodArgs = /** @type {StringRecord<unknown>} */ (args ?? {});
132
+ const executeMethodArgs = (args ?? {}) as StringRecord<unknown>;
122
133
  /**
123
134
  * Renames the deprecated `element` key to `elementId`. Historically,
124
135
  * all of the pre-Execute-Method-Map execute methods accepted an `element` _or_ and `elementId` param.
@@ -136,18 +147,11 @@ function preprocessExecuteMethodArgs(script, args) {
136
147
  */
137
148
  if ('elementId' in executeMethodArgs && executeMethodExpectsParam(script, 'elementId')) {
138
149
  executeMethodArgs.elementId = util.unwrapElement(
139
- /** @type {import('@appium/types').Element|string} */ (executeMethodArgs.elementId),
150
+ executeMethodArgs.elementId as Element<string> | string,
140
151
  );
141
152
  }
142
153
 
143
154
  return executeMethodArgs;
144
155
  }
145
156
 
146
- /**
147
- * @template [T=any]
148
- * @typedef {import('@appium/types').StringRecord<T>} StringRecord
149
- */
150
-
151
- /**
152
- * @typedef {readonly any[] | readonly [StringRecord] | Readonly<StringRecord>} ExecuteMethodArgs
153
- */
157
+ type ExecuteMethodArgs = readonly any[] | readonly [StringRecord<unknown>] | Readonly<StringRecord<unknown>>;
@@ -3,6 +3,10 @@ import {errors} from 'appium/driver';
3
3
  import {util} from 'appium/support';
4
4
  import {AuthorizationStatus} from './enum';
5
5
  import { isIos17OrNewer } from '../utils';
6
+ import type {XCUITestDriver} from '../driver';
7
+ import type {Location} from '@appium/types';
8
+ import type {LocationWithAltitude, WDALocationInfo} from './types';
9
+ import type {Simulator} from 'appium-ios-simulator';
6
10
 
7
11
  /**
8
12
  * Returns location of the device under test.
@@ -17,12 +21,11 @@ import { isIos17OrNewer } from '../utils';
17
21
  * "mobile:getSimulatedLocation" if the simulated location has been previously set
18
22
  * "mobile:setSimulatedLocation" already.
19
23
  *
20
- * @returns {Promise<import('./types').LocationWithAltitude>}
24
+ * @returns Location with altitude
21
25
  * @throws {Error} If the device under test returns an error message.
22
26
  * i.e.: tvOS returns unsupported error
23
- * @this {XCUITestDriver}
24
27
  */
25
- export async function getGeoLocation() {
28
+ export async function getGeoLocation(this: XCUITestDriver): Promise<LocationWithAltitude> {
26
29
  // Currently we proxy the setGeoLocation to mobile:setSimulatedLocation for iOS 17+.
27
30
  // It would be helpful to address to use "mobile:getSimulatedLocation" for iOS 17+.
28
31
  if (isIos17OrNewer(this.opts)) {
@@ -41,9 +44,7 @@ export async function getGeoLocation() {
41
44
  // '/wda/device/location' returns current device location information,
42
45
  // but '/wda/simulatedLocation' returns `null` values until the WDA process
43
46
  // sets a simulated location. After setting the value, both returns the same values.
44
- const {authorizationStatus, latitude, longitude, altitude} = /** @type {WDALocationInfo} */ (
45
- await this.proxyCommand('/wda/device/location', 'GET')
46
- );
47
+ const {authorizationStatus, latitude, longitude, altitude} = await this.proxyCommand('/wda/device/location', 'GET') as WDALocationInfo;
47
48
 
48
49
  // '3' is 'Always' in the privacy
49
50
  // https://developer.apple.com/documentation/corelocation/clauthorizationstatus
@@ -66,19 +67,21 @@ export async function getGeoLocation() {
66
67
  * iOS 17+ real device environment will be via "mobile:setSimulatedLocation" as
67
68
  * setting simulated location for XCTest session.
68
69
  *
69
- * @param {Partial<Location>} location
70
- * @this {XCUITestDriver}
70
+ * @param location - Location with latitude and longitude
71
71
  */
72
- export async function setGeoLocation(location) {
73
- let {latitude, longitude} = location;
72
+ export async function setGeoLocation(
73
+ this: XCUITestDriver,
74
+ location: Partial<Location>,
75
+ ): Promise<Location> {
76
+ const {latitude, longitude} = location;
74
77
 
75
78
  if (!util.hasValue(latitude) || !util.hasValue(longitude)) {
76
79
  throw new errors.InvalidArgumentError(`Both latitude and longitude should be set`);
77
80
  }
78
81
 
79
82
  if (this.isSimulator()) {
80
- await /** @type {import('appium-ios-simulator').Simulator} */ (this.device).setGeolocation(`${latitude}`, `${longitude}`);
81
- return /** @type {Location} */ ({latitude, longitude, altitude: 0});
83
+ await (this.device as Simulator).setGeolocation(`${latitude}`, `${longitude}`);
84
+ return {latitude, longitude, altitude: 0};
82
85
  }
83
86
 
84
87
  if (isIos17OrNewer(this.opts)) {
@@ -88,7 +91,7 @@ export async function setGeoLocation(location) {
88
91
  const service = await services.startSimulateLocationService(this.opts.udid);
89
92
  try {
90
93
  service.setLocation(latitude, longitude);
91
- } catch (e) {
94
+ } catch (e: any) {
92
95
  throw this.log.errorWithException(
93
96
  `Can't set the location on device '${this.opts.udid}'. Original error: ${e.message}`,
94
97
  );
@@ -97,7 +100,7 @@ export async function setGeoLocation(location) {
97
100
  }
98
101
  }
99
102
 
100
- return /** @type {Location} */ ({latitude, longitude, altitude: 0});
103
+ return {latitude, longitude, altitude: 0};
101
104
  }
102
105
 
103
106
  /**
@@ -105,9 +108,8 @@ export async function setGeoLocation(location) {
105
108
  *
106
109
  * @throws {Error} If the device is simulator and iOS version is below 17,
107
110
  * or 'resetLocation' raises an error.
108
- * @this {XCUITestDriver}
109
111
  */
110
- export async function mobileResetLocationService() {
112
+ export async function mobileResetLocationService(this: XCUITestDriver): Promise<void> {
111
113
  if (isIos17OrNewer(this.opts)) {
112
114
  this.log.info(`Proxying to mobile:resetSimulatedLocation method for iOS 17+`);
113
115
  await this.mobileResetSimulatedLocation();
@@ -121,7 +123,7 @@ export async function mobileResetLocationService() {
121
123
  const service = await services.startSimulateLocationService(this.opts.udid);
122
124
  try {
123
125
  service.resetLocation();
124
- } catch (err) {
126
+ } catch (err: any) {
125
127
  throw this.log.errorWithException(
126
128
  `Failed to reset the location on the device on device '${this.opts.udid}'. ` +
127
129
  `Original error: ${err.message}`,
@@ -131,8 +133,3 @@ export async function mobileResetLocationService() {
131
133
  }
132
134
  }
133
135
 
134
- /**
135
- * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
136
- * @typedef {import('./types').WDALocationInfo} WDALocationInfo
137
- * @typedef {import('@appium/types').Location} Location
138
- */
@@ -1,15 +1,17 @@
1
1
  import {errors} from 'appium/driver';
2
2
  import {waitForCondition} from 'asyncbox';
3
3
  import { isTvOs } from '../utils';
4
+ import type {XCUITestDriver} from '../driver';
5
+ import type {Element} from '@appium/types';
4
6
 
5
7
  // these two constitute the wait after closing a window
6
8
  const CLOSE_WINDOW_TIMEOUT = 5000;
7
9
  const CLOSE_WINDOW_INTERVAL = 100;
8
10
 
9
11
  /**
10
- * @this {XCUITestDriver}
12
+ * Navigate back in the browser history or native app navigation.
11
13
  */
12
- export async function back() {
14
+ export async function back(this: XCUITestDriver): Promise<void> {
13
15
  if (!this.isWebContext()) {
14
16
  await this.nativeBack();
15
17
  } else {
@@ -18,18 +20,22 @@ export async function back() {
18
20
  }
19
21
 
20
22
  /**
21
- * @this {XCUITestDriver}
23
+ * Navigate forward in the browser history.
22
24
  */
23
- export async function forward() {
25
+ export async function forward(this: XCUITestDriver): Promise<void> {
24
26
  if (!this.isWebContext()) {
27
+ // No-op for native context
28
+ return;
25
29
  }
26
30
  await this.mobileWebNav('forward');
27
31
  }
28
32
 
29
33
  /**
30
- * @this {XCUITestDriver}
34
+ * Closes the current window in a web context.
35
+ *
36
+ * @returns Promise that resolves when the window is closed
31
37
  */
32
- export async function closeWindow() {
38
+ export async function closeWindow(this: XCUITestDriver): Promise<any> {
33
39
  if (!this.isWebContext()) {
34
40
  throw new errors.NotImplementedError();
35
41
  }
@@ -59,14 +65,16 @@ export async function closeWindow() {
59
65
  *
60
66
  * (Note: the version of Xcode must be 14.3+ and iOS must be 16.4+)
61
67
  *
62
- * @param {string} url - the URL to be opened, e.g. `myscheme://yolo`
63
- * @param {string} [bundleId] - the application to open the given URL with. If not provided, then
68
+ * @param url - the URL to be opened, e.g. `myscheme://yolo`
69
+ * @param bundleId - the application to open the given URL with. If not provided, then
64
70
  * the application assigned by the operating system to handle URLs of the appropriate type
65
- * @returns {Promise<void>}
66
71
  * @since 4.17
67
- * @this {XCUITestDriver}
68
72
  */
69
- export async function mobileDeepLink(url, bundleId) {
73
+ export async function mobileDeepLink(
74
+ this: XCUITestDriver,
75
+ url: string,
76
+ bundleId?: string,
77
+ ): Promise<void> {
70
78
  return await this.proxyCommand('/url', 'POST', {
71
79
  url,
72
80
  bundleId,
@@ -74,9 +82,9 @@ export async function mobileDeepLink(url, bundleId) {
74
82
  }
75
83
 
76
84
  /**
77
- * @this {XCUITestDriver}
85
+ * Navigate back in native app navigation by finding and clicking the back button.
78
86
  */
79
- export async function nativeBack() {
87
+ export async function nativeBack(this: XCUITestDriver): Promise<void> {
80
88
  if (isTvOs(this.opts.platformName)) {
81
89
  this.log.debug(`Sending Menu button as back behavior in tvOS`);
82
90
  return await this.mobilePressButton('Menu');
@@ -88,7 +96,7 @@ export async function nativeBack() {
88
96
  'XCUIElementTypeNavigationBar',
89
97
  false,
90
98
  );
91
- let dstButton;
99
+ let dstButton: Element<string>;
92
100
  const backButtons = await this.findNativeElementOrElements(
93
101
  '-ios predicate string',
94
102
  'type == "XCUIElementTypeButton" AND label == "Back"',
@@ -113,19 +121,8 @@ export async function nativeBack() {
113
121
  }
114
122
 
115
123
  await this.nativeClick(dstButton);
116
- } catch (err) {
124
+ } catch (err: any) {
117
125
  this.log.error(`Unable to find navigation bar and back button: ${err.message}`);
118
126
  }
119
127
  }
120
128
 
121
- /**
122
- * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
123
- */
124
-
125
- /**
126
- * @typedef {Object} DeepLinkOptions
127
- * @property {string} url The URL to be opened. This parameter is manadatory
128
- * @property {string?} bundleId The bundle identifier of an application to open the
129
- * given url with. If not provided then the default application for the given url scheme
130
- * is going to be used.
131
- */
@@ -2,27 +2,29 @@ import { Pyidevice } from '../device/clients/py-ios-device-client';
2
2
  import {fs, tempDir, util} from 'appium/support';
3
3
  import {encodeBase64OrUpload} from '../utils';
4
4
  import {errors} from 'appium/driver';
5
+ import type {XCUITestDriver} from '../driver';
6
+ import type {SubProcess} from 'teen_process';
5
7
 
6
8
  const MAX_CAPTURE_TIME_SEC = 60 * 60 * 12;
7
9
  const DEFAULT_EXT = '.pcap';
8
10
 
9
11
  export class TrafficCapture {
10
- /** @type {import('teen_process').SubProcess|null} */
11
- mainProcess;
12
- constructor(udid, log, resultPath) {
12
+ private mainProcess: SubProcess | null = null;
13
+ private readonly udid: string;
14
+ private readonly log: any;
15
+ private readonly resultPath: string;
16
+
17
+ constructor(udid: string, log: any, resultPath: string) {
13
18
  this.udid = udid;
14
19
  this.log = log;
15
20
  this.resultPath = resultPath;
16
- this.mainProcess = null;
17
21
  }
18
22
 
19
- async start(timeoutSeconds) {
20
- this.mainProcess = /** @type {import('teen_process').SubProcess} */ (
21
- await new Pyidevice({
22
- udid: this.udid,
23
- log: this.log,
24
- }).collectPcap(this.resultPath)
25
- );
23
+ async start(timeoutSeconds: number): Promise<void> {
24
+ this.mainProcess = await new Pyidevice({
25
+ udid: this.udid,
26
+ log: this.log,
27
+ }).collectPcap(this.resultPath);
26
28
  this.mainProcess.on('line-stderr', (line) => this.log.info(`[Pcap] ${line}`));
27
29
  this.log.info(
28
30
  `Starting network traffic capture session on the device '${this.udid}'. ` +
@@ -37,17 +39,17 @@ export class TrafficCapture {
37
39
  });
38
40
  }
39
41
 
40
- isCapturing() {
42
+ isCapturing(): boolean {
41
43
  return !!this.mainProcess?.isRunning;
42
44
  }
43
45
 
44
- async interrupt(force = false) {
46
+ async interrupt(force = false): Promise<boolean> {
45
47
  if (this.isCapturing()) {
46
48
  const interruptPromise = this.mainProcess?.stop(force ? 'SIGTERM' : 'SIGINT');
47
49
  this.mainProcess = null;
48
50
  try {
49
51
  await interruptPromise;
50
- } catch (e) {
52
+ } catch (e: any) {
51
53
  this.log.warn(
52
54
  `Cannot ${force ? 'terminate' : 'interrupt'} the traffic capture session. ` +
53
55
  `Original error: ${e.message}`,
@@ -59,12 +61,12 @@ export class TrafficCapture {
59
61
  return true;
60
62
  }
61
63
 
62
- async finish() {
64
+ async finish(): Promise<string> {
63
65
  await this.interrupt();
64
66
  return this.resultPath;
65
67
  }
66
68
 
67
- async cleanup() {
69
+ async cleanup(): Promise<void> {
68
70
  if (await fs.exists(this.resultPath)) {
69
71
  await fs.rimraf(this.resultPath);
70
72
  }
@@ -74,13 +76,15 @@ export class TrafficCapture {
74
76
  /**
75
77
  * Records the given network traffic capture into a .pcap file.
76
78
  *
77
- * @param {number} timeLimitSec - The maximum recording time, in seconds. The maximum value is `43200` (12 hours).
78
- * @param {boolean} forceRestart - Whether to restart traffic capture process forcefully when startPcap is called (`true`) or ignore the call until the current traffic capture is completed (`false`, the default value).
79
+ * @param timeLimitSec - The maximum recording time, in seconds. The maximum value is `43200` (12 hours).
80
+ * @param forceRestart - Whether to restart traffic capture process forcefully when startPcap is called (`true`) or ignore the call until the current traffic capture is completed (`false`, the default value).
79
81
  * @throws {Error} If network traffic capture has failed to start.
80
- * @returns {Promise<void>}
81
- * @this {XCUITestDriver}
82
82
  */
83
- export async function mobileStartPcap(timeLimitSec = 180, forceRestart = false) {
83
+ export async function mobileStartPcap(
84
+ this: XCUITestDriver,
85
+ timeLimitSec = 180,
86
+ forceRestart = false,
87
+ ): Promise<void> {
84
88
  if (this.isSimulator()) {
85
89
  throw this.log.errorWithException('Network traffic capture only works on real devices');
86
90
  }
@@ -135,17 +139,16 @@ export async function mobileStartPcap(timeLimitSec = 180, forceRestart = false)
135
139
  * If no previously recorded file is found and no active traffic capture processes are running, then the method returns an empty string.
136
140
  *
137
141
  * @remarks Network capture files can be viewed in [Wireshark](https://www.wireshark.org/) and other similar applications.
138
- * @returns {Promise<string>} Base64-encoded content of the recorded pcap file or an empty string if no traffic capture has been started before.
142
+ * @returns Base64-encoded content of the recorded pcap file or an empty string if no traffic capture has been started before.
139
143
  * @throws {Error} If there was an error while getting the capture file.
140
- * @this {XCUITestDriver}
141
144
  */
142
- export async function mobileStopPcap() {
145
+ export async function mobileStopPcap(this: XCUITestDriver): Promise<string> {
143
146
  if (!this._trafficCapture) {
144
147
  this.log.info('Network traffic collector has not been started. There is nothing to stop');
145
148
  return '';
146
149
  }
147
150
 
148
- let resultPath;
151
+ let resultPath: string;
149
152
  try {
150
153
  resultPath = await this._trafficCapture.finish();
151
154
  if (!(await fs.exists(resultPath))) {
@@ -163,6 +166,3 @@ export async function mobileStopPcap() {
163
166
  return await encodeBase64OrUpload(resultPath);
164
167
  }
165
168
 
166
- /**
167
- * @typedef {import('../driver').XCUITestDriver} XCUITestDriver
168
- */