appium-webdriveragent 11.1.4 → 11.1.6

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 (39) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/WebDriverAgent.xcodeproj/project.pbxproj +14 -5
  3. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationApp.xcscheme +1 -1
  4. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationTests_1.xcscheme +1 -1
  5. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationTests_2.xcscheme +1 -1
  6. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationTests_3.xcscheme +1 -1
  7. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentLib.xcscheme +1 -1
  8. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentLib_tvOS.xcscheme +1 -1
  9. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner-nodebug.xcscheme +1 -1
  10. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme +1 -1
  11. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner_tvOS.xcscheme +1 -1
  12. package/WebDriverAgentLib/Info.plist +2 -2
  13. package/build/lib/check-dependencies.d.ts.map +1 -1
  14. package/build/lib/check-dependencies.js +6 -3
  15. package/build/lib/check-dependencies.js.map +1 -1
  16. package/build/lib/logger.js.map +1 -1
  17. package/build/lib/no-session-proxy.d.ts.map +1 -1
  18. package/build/lib/no-session-proxy.js +1 -1
  19. package/build/lib/no-session-proxy.js.map +1 -1
  20. package/build/lib/types.d.ts.map +1 -1
  21. package/build/lib/utils.d.ts.map +1 -1
  22. package/build/lib/utils.js +8 -9
  23. package/build/lib/utils.js.map +1 -1
  24. package/build/lib/webdriveragent.d.ts.map +1 -1
  25. package/build/lib/webdriveragent.js +21 -20
  26. package/build/lib/webdriveragent.js.map +1 -1
  27. package/build/lib/xcodebuild.d.ts.map +1 -1
  28. package/build/lib/xcodebuild.js +16 -19
  29. package/build/lib/xcodebuild.js.map +1 -1
  30. package/build/tsconfig.tsbuildinfo +1 -1
  31. package/lib/check-dependencies.ts +20 -14
  32. package/lib/constants.ts +0 -1
  33. package/lib/logger.ts +1 -1
  34. package/lib/no-session-proxy.ts +5 -7
  35. package/lib/types.ts +6 -1
  36. package/lib/utils.ts +80 -52
  37. package/lib/webdriveragent.ts +189 -134
  38. package/lib/xcodebuild.ts +62 -54
  39. package/package.json +3 -2
@@ -1,27 +1,33 @@
1
- import { waitForCondition } from 'asyncbox';
1
+ import {waitForCondition} from 'asyncbox';
2
2
  import _ from 'lodash';
3
3
  import path from 'node:path';
4
4
  import url from 'node:url';
5
5
  import B from 'bluebird';
6
- import { JWProxy } from '@appium/base-driver';
7
- import { fs, util, plist } from '@appium/support';
8
- import type { AppiumLogger, StringRecord } from '@appium/types';
9
- import { log as defaultLogger } from './logger';
10
- import { NoSessionProxy } from './no-session-proxy';
6
+ import {JWProxy} from '@appium/base-driver';
7
+ import {fs, util, plist} from '@appium/support';
8
+ import type {AppiumLogger, StringRecord} from '@appium/types';
9
+ import {log as defaultLogger} from './logger';
10
+ import {NoSessionProxy} from './no-session-proxy';
11
11
  import {
12
- getWDAUpgradeTimestamp, resetTestProcesses, getPIDsListeningOnPort, BOOTSTRAP_PATH
12
+ getWDAUpgradeTimestamp,
13
+ resetTestProcesses,
14
+ getPIDsListeningOnPort,
15
+ BOOTSTRAP_PATH,
13
16
  } from './utils';
14
17
  import {XcodeBuild} from './xcodebuild';
15
18
  import AsyncLock from 'async-lock';
16
- import { exec } from 'teen_process';
17
- import { bundleWDASim } from './check-dependencies';
19
+ import {exec} from 'teen_process';
20
+ import {bundleWDASim} from './check-dependencies';
18
21
  import {
19
- WDA_RUNNER_BUNDLE_ID, WDA_RUNNER_APP,
20
- WDA_BASE_URL, WDA_UPGRADE_TIMESTAMP_PATH, DEFAULT_TEST_BUNDLE_SUFFIX
22
+ WDA_RUNNER_BUNDLE_ID,
23
+ WDA_RUNNER_APP,
24
+ WDA_BASE_URL,
25
+ WDA_UPGRADE_TIMESTAMP_PATH,
26
+ DEFAULT_TEST_BUNDLE_SUFFIX,
21
27
  } from './constants';
22
28
  import {Xctest} from 'appium-ios-device';
23
29
  import {strongbox} from '@appium/strongbox';
24
- import type { WebDriverAgentArgs, AppleDevice } from './types';
30
+ import type {WebDriverAgentArgs, AppleDevice} from './types';
25
31
 
26
32
  const WDA_LAUNCH_TIMEOUT = 60 * 1000;
27
33
  const WDA_AGENT_PORT = 8100;
@@ -69,7 +75,7 @@ export class WebDriverAgent {
69
75
  * @param args - Configuration arguments for WebDriverAgent
70
76
  * @param log - Optional logger instance
71
77
  */
72
- constructor (args: WebDriverAgentArgs, log: AppiumLogger | null = null) {
78
+ constructor(args: WebDriverAgentArgs, log: AppiumLogger | null = null) {
73
79
  this.args = _.clone(args);
74
80
  this.log = log ?? defaultLogger;
75
81
 
@@ -84,8 +90,8 @@ export class WebDriverAgent {
84
90
  this.setWDAPaths(args.bootstrapPath, args.agentPath);
85
91
 
86
92
  this.wdaLocalPort = args.wdaLocalPort;
87
- this.wdaRemotePort = ((this.isRealDevice ? args.wdaRemotePort : null) ?? args.wdaLocalPort)
88
- || WDA_AGENT_PORT;
93
+ this.wdaRemotePort =
94
+ ((this.isRealDevice ? args.wdaRemotePort : null) ?? args.wdaLocalPort) || WDA_AGENT_PORT;
89
95
  this.wdaBaseUrl = args.wdaBaseUrl || WDA_BASE_URL;
90
96
  this.wdaBindingIP = args.wdaBindingIP;
91
97
  this.prebuildWDA = args.prebuildWDA;
@@ -112,40 +118,44 @@ export class WebDriverAgent {
112
118
  this.updatedWDABundleIdSuffix = args.updatedWDABundleIdSuffix ?? DEFAULT_TEST_BUNDLE_SUFFIX;
113
119
 
114
120
  this._xcodebuild = this.canSkipXcodebuild
115
- ? null
116
- : new XcodeBuild(this.device, {
117
- platformVersion: this.platformVersion,
118
- platformName: this.platformName,
119
- iosSdkVersion: this.iosSdkVersion,
120
- agentPath: this.agentPath,
121
- bootstrapPath: this.bootstrapPath,
122
- realDevice: this.isRealDevice,
123
- showXcodeLog: args.showXcodeLog,
124
- xcodeConfigFile: args.xcodeConfigFile,
125
- xcodeOrgId: args.xcodeOrgId,
126
- xcodeSigningId: args.xcodeSigningId,
127
- keychainPath: args.keychainPath,
128
- keychainPassword: args.keychainPassword,
129
- useSimpleBuildTest: args.useSimpleBuildTest,
130
- usePrebuiltWDA: args.usePrebuiltWDA,
131
- updatedWDABundleId: this.updatedWDABundleId,
132
- launchTimeout: this.wdaLaunchTimeout,
133
- wdaRemotePort: this.wdaRemotePort,
134
- wdaBindingIP: this.wdaBindingIP,
135
- useXctestrunFile: this.useXctestrunFile,
136
- derivedDataPath: args.derivedDataPath,
137
- mjpegServerPort: this.mjpegServerPort,
138
- allowProvisioningDeviceRegistration: args.allowProvisioningDeviceRegistration,
139
- resultBundlePath: args.resultBundlePath,
140
- resultBundleVersion: args.resultBundleVersion,
141
- }, this.log);
121
+ ? null
122
+ : new XcodeBuild(
123
+ this.device,
124
+ {
125
+ platformVersion: this.platformVersion,
126
+ platformName: this.platformName,
127
+ iosSdkVersion: this.iosSdkVersion,
128
+ agentPath: this.agentPath,
129
+ bootstrapPath: this.bootstrapPath,
130
+ realDevice: this.isRealDevice,
131
+ showXcodeLog: args.showXcodeLog,
132
+ xcodeConfigFile: args.xcodeConfigFile,
133
+ xcodeOrgId: args.xcodeOrgId,
134
+ xcodeSigningId: args.xcodeSigningId,
135
+ keychainPath: args.keychainPath,
136
+ keychainPassword: args.keychainPassword,
137
+ useSimpleBuildTest: args.useSimpleBuildTest,
138
+ usePrebuiltWDA: args.usePrebuiltWDA,
139
+ updatedWDABundleId: this.updatedWDABundleId,
140
+ launchTimeout: this.wdaLaunchTimeout,
141
+ wdaRemotePort: this.wdaRemotePort,
142
+ wdaBindingIP: this.wdaBindingIP,
143
+ useXctestrunFile: this.useXctestrunFile,
144
+ derivedDataPath: args.derivedDataPath,
145
+ mjpegServerPort: this.mjpegServerPort,
146
+ allowProvisioningDeviceRegistration: args.allowProvisioningDeviceRegistration,
147
+ resultBundlePath: args.resultBundlePath,
148
+ resultBundleVersion: args.resultBundleVersion,
149
+ },
150
+ this.log,
151
+ );
142
152
  }
143
153
 
144
154
  /**
145
155
  * Return true if the session does not need xcodebuild.
146
156
  * @returns Whether the session needs/has xcodebuild.
147
157
  */
148
- get canSkipXcodebuild (): boolean {
158
+ get canSkipXcodebuild(): boolean {
149
159
  // Use this.args.webDriverAgentUrl to guarantee
150
160
  // the capabilities set gave the `appium:webDriverAgentUrl`.
151
161
  return this.usePreinstalledWDA || !!this.args.webDriverAgentUrl;
@@ -156,7 +166,7 @@ export class WebDriverAgent {
156
166
  * @returns The XcodeBuild instance
157
167
  * @throws Error if xcodebuild is not available
158
168
  */
159
- get xcodebuild (): XcodeBuild {
169
+ get xcodebuild(): XcodeBuild {
160
170
  if (!this._xcodebuild) {
161
171
  throw new Error('xcodebuild is not available');
162
172
  }
@@ -171,7 +181,7 @@ export class WebDriverAgent {
171
181
  *
172
182
  * @returns Bundle ID for Xctest.
173
183
  */
174
- get bundleIdForXctest (): string {
184
+ get bundleIdForXctest(): string {
175
185
  return `${this.updatedWDABundleId ? this.updatedWDABundleId : WDA_RUNNER_BUNDLE_ID}${this.updatedWDABundleIdSuffix}`;
176
186
  }
177
187
 
@@ -179,24 +189,33 @@ export class WebDriverAgent {
179
189
  * Cleans up obsolete cached processes from previous WDA sessions
180
190
  * that are listening on the same port but belong to different devices.
181
191
  */
182
- async cleanupObsoleteProcesses (): Promise<void> {
183
- const obsoletePids = await getPIDsListeningOnPort(this.url.port as string,
184
- (cmdLine) => cmdLine.includes('/WebDriverAgentRunner') &&
185
- !cmdLine.toLowerCase().includes(this.device.udid.toLowerCase()));
192
+ async cleanupObsoleteProcesses(): Promise<void> {
193
+ const obsoletePids = await getPIDsListeningOnPort(
194
+ this.url.port as string,
195
+ (cmdLine) =>
196
+ cmdLine.includes('/WebDriverAgentRunner') &&
197
+ !cmdLine.toLowerCase().includes(this.device.udid.toLowerCase()),
198
+ );
186
199
 
187
200
  if (_.isEmpty(obsoletePids)) {
188
- this.log.debug(`No obsolete cached processes from previous WDA sessions ` +
189
- `listening on port ${this.url.port} have been found`);
201
+ this.log.debug(
202
+ `No obsolete cached processes from previous WDA sessions ` +
203
+ `listening on port ${this.url.port} have been found`,
204
+ );
190
205
  return;
191
206
  }
192
207
 
193
- this.log.info(`Detected ${obsoletePids.length} obsolete cached process${obsoletePids.length === 1 ? '' : 'es'} ` +
194
- `from previous WDA sessions. Cleaning them up`);
208
+ this.log.info(
209
+ `Detected ${obsoletePids.length} obsolete cached process${obsoletePids.length === 1 ? '' : 'es'} ` +
210
+ `from previous WDA sessions. Cleaning them up`,
211
+ );
195
212
  try {
196
213
  await exec('kill', obsoletePids);
197
214
  } catch (e: any) {
198
- this.log.warn(`Failed to kill obsolete cached process${obsoletePids.length === 1 ? '' : 'es'} '${obsoletePids}'. ` +
199
- `Original error: ${e.message}`);
215
+ this.log.warn(
216
+ `Failed to kill obsolete cached process${obsoletePids.length === 1 ? '' : 'es'} '${obsoletePids}'. ` +
217
+ `Original error: ${e.message}`,
218
+ );
200
219
  }
201
220
  }
202
221
 
@@ -204,7 +223,7 @@ export class WebDriverAgent {
204
223
  * Gets the base path for the WebDriverAgent URL.
205
224
  * @returns The base path (empty string if root path)
206
225
  */
207
- get basePath (): string {
226
+ get basePath(): string {
208
227
  if (this.url.path === '/') {
209
228
  return '';
210
229
  }
@@ -232,7 +251,7 @@ export class WebDriverAgent {
232
251
  *
233
252
  * @param sessionId Launch WDA and establish the session with this sessionId
234
253
  */
235
- async launch (sessionId: string): Promise<StringRecord | null> {
254
+ async launch(sessionId: string): Promise<StringRecord | null> {
236
255
  if (this.webDriverAgentUrl) {
237
256
  this.log.info(`Using provided WebdriverAgent at '${this.webDriverAgentUrl}'`);
238
257
  this.url = this.webDriverAgentUrl;
@@ -248,9 +267,11 @@ export class WebDriverAgent {
248
267
 
249
268
  this.setupProxies(sessionId);
250
269
 
251
- if (!this.useXctestrunFile && !await fs.exists(this.agentPath)) {
252
- throw new Error(`Trying to use WebDriverAgent project at '${this.agentPath}' but the ` +
253
- 'file does not exist');
270
+ if (!this.useXctestrunFile && !(await fs.exists(this.agentPath))) {
271
+ throw new Error(
272
+ `Trying to use WebDriverAgent project at '${this.agentPath}' but the ` +
273
+ 'file does not exist',
274
+ );
254
275
  }
255
276
 
256
277
  // useXctestrunFile and usePrebuiltWDA use existing dependencies
@@ -259,8 +280,10 @@ export class WebDriverAgent {
259
280
  this.log.info('Skipped WDA project cleanup according to the provided capabilities');
260
281
  } else {
261
282
  const synchronizationKey = path.normalize(this.bootstrapPath);
262
- await SHARED_RESOURCES_GUARD.acquire(synchronizationKey,
263
- async () => await this._cleanupProjectIfFresh());
283
+ await SHARED_RESOURCES_GUARD.acquire(
284
+ synchronizationKey,
285
+ async () => await this._cleanupProjectIfFresh(),
286
+ );
264
287
  }
265
288
 
266
289
  // We need to provide WDA local port, because it might be occupied
@@ -275,7 +298,7 @@ export class WebDriverAgent {
275
298
  if (this.prebuildWDA) {
276
299
  await this.xcodebuild.prebuild();
277
300
  }
278
- return await this.xcodebuild.start() as StringRecord | null;
301
+ return (await this.xcodebuild.start()) as StringRecord | null;
279
302
  }
280
303
 
281
304
  /**
@@ -283,15 +306,14 @@ export class WebDriverAgent {
283
306
  * that required resource files exist.
284
307
  * @returns `true` if source is fresh (all required files exist), `false` otherwise
285
308
  */
286
- async isSourceFresh (): Promise<boolean> {
287
- const existsPromises = [
288
- 'Resources',
289
- `Resources${path.sep}WebDriverAgent.bundle`,
290
- ].map((subPath) => fs.exists(path.resolve(this.bootstrapPath, subPath)));
309
+ async isSourceFresh(): Promise<boolean> {
310
+ const existsPromises = ['Resources', `Resources${path.sep}WebDriverAgent.bundle`].map(
311
+ (subPath) => fs.exists(path.resolve(this.bootstrapPath, subPath)),
312
+ );
291
313
  return (await B.all(existsPromises)).some((v) => v === false);
292
314
  }
293
315
 
294
- private async parseBundleId (wdaBundlePath: string): Promise<string> {
316
+ private async parseBundleId(wdaBundlePath: string): Promise<string> {
295
317
  const infoPlistPath = path.join(wdaBundlePath, 'Info.plist');
296
318
  const infoPlist = await plist.parsePlist(await fs.readFile(infoPlistPath));
297
319
  if (!infoPlist.CFBundleIdentifier) {
@@ -300,7 +322,7 @@ export class WebDriverAgent {
300
322
  return infoPlist.CFBundleIdentifier as string;
301
323
  }
302
324
 
303
- private async fetchWDABundle (): Promise<string> {
325
+ private async fetchWDABundle(): Promise<string> {
304
326
  if (!this.derivedDataPath) {
305
327
  return await bundleWDASim(this.xcodebuild);
306
328
  }
@@ -313,7 +335,7 @@ export class WebDriverAgent {
313
335
  return wdaBundlePaths[0];
314
336
  }
315
337
 
316
- private setupProxies (sessionId: string): void {
338
+ private setupProxies(sessionId: string): void {
317
339
  const proxyOpts: any = {
318
340
  log: this.log,
319
341
  server: this.url.hostname ?? undefined,
@@ -338,7 +360,7 @@ export class WebDriverAgent {
338
360
  * Stops the WebDriverAgent session and cleans up resources.
339
361
  * Handles both preinstalled WDA and xcodebuild-based sessions.
340
362
  */
341
- async quit (): Promise<void> {
363
+ async quit(): Promise<void> {
342
364
  if (this.usePreinstalledWDA) {
343
365
  this.log.info('Stopping the XCTest session');
344
366
  if (this.xctestApiClient) {
@@ -357,8 +379,10 @@ export class WebDriverAgent {
357
379
  await this.xcodebuild.quit();
358
380
  }
359
381
  } else {
360
- this.log.debug('Do not stop xcodebuild nor XCTest session ' +
361
- 'since the WDA session is managed by outside this driver.');
382
+ this.log.debug(
383
+ 'Do not stop xcodebuild nor XCTest session ' +
384
+ 'since the WDA session is managed by outside this driver.',
385
+ );
362
386
  }
363
387
 
364
388
  if (this.jwproxy) {
@@ -380,7 +404,7 @@ export class WebDriverAgent {
380
404
  * builds it from wdaBaseUrl, wdaBindingIP, and wdaLocalPort.
381
405
  * @returns The parsed URL object
382
406
  */
383
- get url (): url.UrlWithStringQuery {
407
+ get url(): url.UrlWithStringQuery {
384
408
  if (!this._url) {
385
409
  if (this.webDriverAgentUrl) {
386
410
  this._url = url.parse(this.webDriverAgentUrl);
@@ -397,7 +421,7 @@ export class WebDriverAgent {
397
421
  * Sets the WebDriverAgent URL.
398
422
  * @param _url - The URL string to parse and set
399
423
  */
400
- set url (_url: string) {
424
+ set url(_url: string) {
401
425
  this._url = url.parse(_url);
402
426
  }
403
427
 
@@ -405,7 +429,7 @@ export class WebDriverAgent {
405
429
  * Gets whether WebDriverAgent has fully started.
406
430
  * @returns `true` if WDA has started, `false` otherwise
407
431
  */
408
- get fullyStarted (): boolean {
432
+ get fullyStarted(): boolean {
409
433
  return this.started;
410
434
  }
411
435
 
@@ -413,7 +437,7 @@ export class WebDriverAgent {
413
437
  * Sets whether WebDriverAgent has fully started.
414
438
  * @param started - `true` if WDA has started, `false` otherwise
415
439
  */
416
- set fullyStarted (started: boolean) {
440
+ set fullyStarted(started: boolean) {
417
441
  this.started = started ?? false;
418
442
  }
419
443
 
@@ -421,7 +445,7 @@ export class WebDriverAgent {
421
445
  * Retrieves the Xcode derived data path for WebDriverAgent.
422
446
  * @returns The derived data path, or `undefined` if xcodebuild is skipped
423
447
  */
424
- async retrieveDerivedDataPath (): Promise<string | undefined> {
448
+ async retrieveDerivedDataPath(): Promise<string | undefined> {
425
449
  if (this.canSkipXcodebuild) {
426
450
  return;
427
451
  }
@@ -433,53 +457,70 @@ export class WebDriverAgent {
433
457
  * Or reuse it if it has the default id without updatedWDABundleId.
434
458
  * Uninstall it if the method faces an exception for the above situation.
435
459
  */
436
- async setupCaching (): Promise<void> {
460
+ async setupCaching(): Promise<void> {
437
461
  const status = await this.getStatus(0);
438
462
  if (!status || !status.build) {
439
463
  this.log.debug('WDA is currently not running. There is nothing to cache');
440
464
  return;
441
465
  }
442
466
 
443
- const {
444
- productBundleIdentifier,
445
- upgradedAt,
446
- } = status.build as any;
467
+ const {productBundleIdentifier, upgradedAt} = status.build as any;
447
468
  // for real device
448
- if (util.hasValue(productBundleIdentifier) && util.hasValue(this.updatedWDABundleId) && this.updatedWDABundleId !== productBundleIdentifier) {
449
- this.log.info(`Will uninstall running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`);
469
+ if (
470
+ util.hasValue(productBundleIdentifier) &&
471
+ util.hasValue(this.updatedWDABundleId) &&
472
+ this.updatedWDABundleId !== productBundleIdentifier
473
+ ) {
474
+ this.log.info(
475
+ `Will uninstall running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`,
476
+ );
450
477
  return await this.uninstall();
451
478
  }
452
479
  // for simulator
453
- if (util.hasValue(productBundleIdentifier) && !util.hasValue(this.updatedWDABundleId) && WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier) {
454
- this.log.info(`Will uninstall running WDA since its bundle id is not equal to the default value ${WDA_RUNNER_BUNDLE_ID}`);
480
+ if (
481
+ util.hasValue(productBundleIdentifier) &&
482
+ !util.hasValue(this.updatedWDABundleId) &&
483
+ WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier
484
+ ) {
485
+ this.log.info(
486
+ `Will uninstall running WDA since its bundle id is not equal to the default value ${WDA_RUNNER_BUNDLE_ID}`,
487
+ );
455
488
  return await this.uninstall();
456
489
  }
457
490
 
458
491
  const actualUpgradeTimestamp = await getWDAUpgradeTimestamp();
459
492
  this.log.debug(`Upgrade timestamp of the currently bundled WDA: ${actualUpgradeTimestamp}`);
460
493
  this.log.debug(`Upgrade timestamp of the WDA on the device: ${upgradedAt}`);
461
- if (actualUpgradeTimestamp && upgradedAt && _.toLower(`${actualUpgradeTimestamp}`) !== _.toLower(`${upgradedAt}`)) {
462
- this.log.info('Will uninstall running WDA since it has different version in comparison to the one ' +
463
- `which is bundled with appium-xcuitest-driver module (${actualUpgradeTimestamp} != ${upgradedAt})`);
494
+ if (
495
+ actualUpgradeTimestamp &&
496
+ upgradedAt &&
497
+ _.toLower(`${actualUpgradeTimestamp}`) !== _.toLower(`${upgradedAt}`)
498
+ ) {
499
+ this.log.info(
500
+ 'Will uninstall running WDA since it has different version in comparison to the one ' +
501
+ `which is bundled with appium-xcuitest-driver module (${actualUpgradeTimestamp} != ${upgradedAt})`,
502
+ );
464
503
  return await this.uninstall();
465
504
  }
466
505
 
467
506
  const message = util.hasValue(productBundleIdentifier)
468
507
  ? `Will reuse previously cached WDA instance at '${this.url.href}' with '${productBundleIdentifier}'`
469
508
  : `Will reuse previously cached WDA instance at '${this.url.href}'`;
470
- this.log.info(`${message}. Set the wdaLocalPort capability to a value different from ${this.url.port} if this is an undesired behavior.`);
509
+ this.log.info(
510
+ `${message}. Set the wdaLocalPort capability to a value different from ${this.url.port} if this is an undesired behavior.`,
511
+ );
471
512
  this.webDriverAgentUrl = this.url.href;
472
513
  }
473
514
 
474
515
  /**
475
516
  * Quit and uninstall running WDA.
476
517
  */
477
- async quitAndUninstall (): Promise<void> {
518
+ async quitAndUninstall(): Promise<void> {
478
519
  await this.quit();
479
520
  await this.uninstall();
480
521
  }
481
522
 
482
- private setWDAPaths (bootstrapPath?: string, agentPath?: string): void {
523
+ private setWDAPaths(bootstrapPath?: string, agentPath?: string): void {
483
524
  // allow the user to specify a place for WDA. This is undocumented and
484
525
  // only here for the purposes of testing development of WDA
485
526
  this.bootstrapPath = bootstrapPath || BOOTSTRAP_PATH;
@@ -490,7 +531,7 @@ export class WebDriverAgent {
490
531
  this.log.info(`Using WDA agent: '${this.agentPath}'`);
491
532
  }
492
533
 
493
- private async isRunning (): Promise<boolean> {
534
+ private async isRunning(): Promise<boolean> {
494
535
  return !!(await this.getStatus());
495
536
  }
496
537
 
@@ -515,7 +556,7 @@ export class WebDriverAgent {
515
556
  *
516
557
  * @param timeoutMs If zero or negative, returns immediately. Otherwise, waits up to timeoutMs.
517
558
  */
518
- private async getStatus (timeoutMs: number = 0): Promise<StringRecord | null> {
559
+ private async getStatus(timeoutMs: number = 0): Promise<StringRecord | null> {
519
560
  const noSessionProxy = new NoSessionProxy({
520
561
  server: this.url.hostname ?? undefined,
521
562
  port: parseInt(this.url.port ?? '', 10) || undefined,
@@ -523,13 +564,16 @@ export class WebDriverAgent {
523
564
  timeout: 3000,
524
565
  });
525
566
 
526
- const sendGetStatus = async () => await noSessionProxy.command('/status', 'GET') as StringRecord;
567
+ const sendGetStatus = async () =>
568
+ (await noSessionProxy.command('/status', 'GET')) as StringRecord;
527
569
 
528
570
  if (_.isNil(timeoutMs) || timeoutMs <= 0) {
529
571
  try {
530
572
  return await sendGetStatus();
531
573
  } catch (err: any) {
532
- this.log.debug(`WDA is not listening at '${this.url.href}'. Original error:: ${err.message}`);
574
+ this.log.debug(
575
+ `WDA is not listening at '${this.url.href}'. Original error:: ${err.message}`,
576
+ );
533
577
  return null;
534
578
  }
535
579
  }
@@ -537,21 +581,26 @@ export class WebDriverAgent {
537
581
  let lastError: any = null;
538
582
  let status: StringRecord | null = null;
539
583
  try {
540
- await waitForCondition(async () => {
541
- try {
542
- status = await sendGetStatus();
543
- return true;
544
- } catch (err) {
545
- lastError = err;
546
- }
547
- return false;
548
- }, {
549
- waitMs: timeoutMs,
550
- intervalMs: 300,
551
- });
584
+ await waitForCondition(
585
+ async () => {
586
+ try {
587
+ status = await sendGetStatus();
588
+ return true;
589
+ } catch (err) {
590
+ lastError = err;
591
+ }
592
+ return false;
593
+ },
594
+ {
595
+ waitMs: timeoutMs,
596
+ intervalMs: 300,
597
+ },
598
+ );
552
599
  } catch (err: any) {
553
- this.log.debug(`Failed to get the status endpoint in ${timeoutMs} ms. ` +
554
- `The last error while accessing ${this.url.href}: ${lastError}. Original error:: ${err.message}.`);
600
+ this.log.debug(
601
+ `Failed to get the status endpoint in ${timeoutMs} ms. ` +
602
+ `The last error while accessing ${this.url.href}: ${lastError}. Original error:: ${err.message}.`,
603
+ );
555
604
  throw new Error(`WDA was not ready in ${timeoutMs} ms.`);
556
605
  }
557
606
  return status;
@@ -562,7 +611,7 @@ export class WebDriverAgent {
562
611
  * Over Xcode 11, multiple WDA can be in the device since Xcode 11 generates different WDA.
563
612
  * Appium does not expect multiple WDAs are running on a device.
564
613
  */
565
- private async uninstall (): Promise<void> {
614
+ private async uninstall(): Promise<void> {
566
615
  try {
567
616
  const bundleIds = await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME);
568
617
  if (_.isEmpty(bundleIds)) {
@@ -576,17 +625,21 @@ export class WebDriverAgent {
576
625
  }
577
626
  } catch (e: any) {
578
627
  this.log.debug(e);
579
- this.log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? ` +
580
- `Original error: ${e.message}`);
628
+ this.log.warn(
629
+ `WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? ` +
630
+ `Original error: ${e.message}`,
631
+ );
581
632
  }
582
633
  }
583
634
 
584
- private async _cleanupProjectIfFresh (): Promise<void> {
635
+ private async _cleanupProjectIfFresh(): Promise<void> {
585
636
  if (this.canSkipXcodebuild) {
586
637
  return;
587
638
  }
588
639
 
589
- const packageInfo = JSON.parse(await fs.readFile(path.join(BOOTSTRAP_PATH, 'package.json'), 'utf8'));
640
+ const packageInfo = JSON.parse(
641
+ await fs.readFile(path.join(BOOTSTRAP_PATH, 'package.json'), 'utf8'),
642
+ );
590
643
  const box = strongbox(packageInfo.name);
591
644
  let boxItem = box.getItem(RECENT_MODULE_VERSION_ITEM_NAME);
592
645
  if (!boxItem) {
@@ -602,7 +655,9 @@ export class WebDriverAgent {
602
655
  return;
603
656
  }
604
657
  } else {
605
- this.log.info('There is no need to perform the project cleanup. A fresh install has been detected');
658
+ this.log.info(
659
+ 'There is no need to perform the project cleanup. A fresh install has been detected',
660
+ );
606
661
  try {
607
662
  await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, packageInfo.version);
608
663
  } catch (e: any) {
@@ -617,7 +672,9 @@ export class WebDriverAgent {
617
672
  recentModuleVersion = util.coerceVersion(recentModuleVersion, true);
618
673
  } catch (e: any) {
619
674
  this.log.warn(`The persisted module version string has been damaged: ${e.message}`);
620
- this.log.info(`Updating it to '${packageInfo.version}' assuming the project clenup is not needed`);
675
+ this.log.info(
676
+ `Updating it to '${packageInfo.version}' assuming the project clenup is not needed`,
677
+ );
621
678
  await boxItem.write(packageInfo.version);
622
679
  return;
623
680
  }
@@ -625,14 +682,14 @@ export class WebDriverAgent {
625
682
  if (util.compareVersions(recentModuleVersion, '>=', packageInfo.version)) {
626
683
  this.log.info(
627
684
  `WebDriverAgent does not need a cleanup. The project sources are up to date ` +
628
- `(${recentModuleVersion} >= ${packageInfo.version})`
685
+ `(${recentModuleVersion} >= ${packageInfo.version})`,
629
686
  );
630
687
  return;
631
688
  }
632
689
 
633
690
  this.log.info(
634
691
  `Cleaning up the WebDriverAgent project after the module upgrade has happened ` +
635
- `(${recentModuleVersion} < ${packageInfo.version})`
692
+ `(${recentModuleVersion} < ${packageInfo.version})`,
636
693
  );
637
694
  try {
638
695
  await this.xcodebuild.cleanProject();
@@ -653,12 +710,12 @@ export class WebDriverAgent {
653
710
  *
654
711
  * @param opts launching WDA with devicectl command options.
655
712
  */
656
- private async _launchViaDevicectl(opts: {env?: Record<string, string | number>} = {}): Promise<void> {
713
+ private async _launchViaDevicectl(
714
+ opts: {env?: Record<string, string | number>} = {},
715
+ ): Promise<void> {
657
716
  const {env} = opts;
658
717
 
659
- await this.device.devicectl.launchApp(
660
- this.bundleIdForXctest, { env, terminateExisting: true }
661
- );
718
+ await this.device.devicectl.launchApp(this.bundleIdForXctest, {env, terminateExisting: true});
662
719
  }
663
720
 
664
721
  /**
@@ -668,7 +725,7 @@ export class WebDriverAgent {
668
725
  private async launchWithPreinstalledWDA(sessionId: string): Promise<StringRecord | null> {
669
726
  const xctestEnv: Record<string, string | number> = {
670
727
  USE_PORT: this.wdaLocalPort || WDA_AGENT_PORT,
671
- WDA_PRODUCT_BUNDLE_IDENTIFIER: this.bundleIdForXctest
728
+ WDA_PRODUCT_BUNDLE_IDENTIFIER: this.bundleIdForXctest,
672
729
  };
673
730
  if (this.mjpegServerPort) {
674
731
  xctestEnv.MJPEG_SERVER_PORT = this.mjpegServerPort;
@@ -684,16 +741,14 @@ export class WebDriverAgent {
684
741
  if (this.platformVersion && util.compareVersions(this.platformVersion, '>=', '17.0')) {
685
742
  await this._launchViaDevicectl({env: xctestEnv});
686
743
  } else {
687
- this.xctestApiClient = new Xctest(this.device.udid, this.bundleIdForXctest, null, {env: xctestEnv});
744
+ this.xctestApiClient = new Xctest(this.device.udid, this.bundleIdForXctest, null, {
745
+ env: xctestEnv,
746
+ });
688
747
  await this.xctestApiClient.start();
689
748
  }
690
749
  } else {
691
750
  await this.device.simctl.exec('launch', {
692
- args: [
693
- '--terminate-running-process',
694
- this.device.udid,
695
- this.bundleIdForXctest,
696
- ],
751
+ args: ['--terminate-running-process', this.device.udid, this.bundleIdForXctest],
697
752
  env: xctestEnv,
698
753
  });
699
754
  }
@@ -705,8 +760,8 @@ export class WebDriverAgent {
705
760
  } catch {
706
761
  throw new Error(
707
762
  `Failed to start the preinstalled WebDriverAgent in ${this.wdaLaunchTimeout} ms. ` +
708
- `The WebDriverAgent might not be properly built or the device might be locked. ` +
709
- `The 'appium:wdaLaunchTimeout' capability modifies the timeout.`
763
+ `The WebDriverAgent might not be properly built or the device might be locked. ` +
764
+ `The 'appium:wdaLaunchTimeout' capability modifies the timeout.`,
710
765
  );
711
766
  }
712
767
  this.started = true;