appium-webdriveragent 12.2.2 → 13.1.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.
@@ -1,7 +1,7 @@
1
1
  import {waitForCondition} from 'asyncbox';
2
2
  import path from 'node:path';
3
3
  import {JWProxy} from '@appium/base-driver';
4
- import {fs, util, plist} from '@appium/support';
4
+ import {fs, util} from '@appium/support';
5
5
  import type {AppiumLogger, StringRecord} from '@appium/types';
6
6
  import {log as defaultLogger} from './logger';
7
7
  import {NoSessionProxy} from './no-session-proxy';
@@ -14,21 +14,24 @@ import {
14
14
  import {XcodeBuild} from './xcodebuild';
15
15
  import AsyncLock from 'async-lock';
16
16
  import {exec} from 'teen_process';
17
- import {bundleWDASim} from './check-dependencies';
18
17
  import {
19
18
  WDA_RUNNER_BUNDLE_ID,
20
- WDA_RUNNER_APP,
21
19
  WDA_BASE_URL,
22
20
  WDA_UPGRADE_TIMESTAMP_PATH,
23
21
  DEFAULT_TEST_BUNDLE_SUFFIX,
24
22
  } from './constants';
25
- import {Xctest} from 'appium-ios-device';
26
23
  import {strongbox} from '@appium/strongbox';
27
- import type {WebDriverAgentArgs, AppleDevice} from './types';
24
+ import type {
25
+ WebDriverAgentArgs,
26
+ AppleDevice,
27
+ XcodeBuildSettings,
28
+ RetrieveBuildSettingsOptions,
29
+ } from './types';
30
+ import type {Simctl} from 'node-simctl';
31
+ import type {Devicectl} from 'node-devicectl';
28
32
 
29
33
  const WDA_LAUNCH_TIMEOUT = 60 * 1000;
30
34
  const WDA_AGENT_PORT = 8100;
31
- const WDA_CF_BUNDLE_NAME = 'WebDriverAgentRunner-Runner';
32
35
  const SHARED_RESOURCES_GUARD = new AsyncLock();
33
36
  const RECENT_MODULE_VERSION_ITEM_NAME = 'recentWdaModuleVersion';
34
37
  const URL_PROTOCOL_SEPARATOR = '://';
@@ -53,18 +56,15 @@ export class WebDriverAgent {
53
56
  jwproxy?: JWProxy;
54
57
  proxyReqRes?: any;
55
58
  private readonly log: AppiumLogger;
56
- private readonly wdaBundlePath?: string;
57
59
  private readonly wdaLocalPort?: number;
58
60
  private readonly prebuildWDA?: boolean;
59
61
  private readonly wdaConnectionTimeout?: number;
60
62
  private readonly useXctestrunFile?: boolean;
61
63
  private readonly usePrebuiltWDA?: boolean;
62
- private readonly derivedDataPath?: string;
63
64
  private readonly mjpegServerPort?: number;
64
65
  private readonly wdaLaunchTimeout: number;
65
66
  private readonly usePreinstalledWDA?: boolean;
66
67
  private readonly updatedWDABundleIdSuffix: string;
67
- private xctestApiClient?: Xctest | null;
68
68
  private _xcodebuild?: XcodeBuild | null;
69
69
  private _url?: URL;
70
70
 
@@ -83,7 +83,6 @@ export class WebDriverAgent {
83
83
  this.iosSdkVersion = args.iosSdkVersion;
84
84
  this.host = args.host;
85
85
  this.isRealDevice = !!args.realDevice;
86
- this.wdaBundlePath = args.wdaBundlePath;
87
86
 
88
87
  this.setWDAPaths(args.bootstrapPath, args.agentPath);
89
88
 
@@ -105,14 +104,12 @@ export class WebDriverAgent {
105
104
 
106
105
  this.useXctestrunFile = args.useXctestrunFile;
107
106
  this.usePrebuiltWDA = args.usePrebuiltWDA;
108
- this.derivedDataPath = args.derivedDataPath;
109
107
  this.mjpegServerPort = args.mjpegServerPort;
110
108
 
111
109
  this.updatedWDABundleId = args.updatedWDABundleId;
112
110
 
113
111
  this.wdaLaunchTimeout = args.wdaLaunchTimeout || WDA_LAUNCH_TIMEOUT;
114
112
  this.usePreinstalledWDA = args.usePreinstalledWDA;
115
- this.xctestApiClient = null;
116
113
  this.updatedWDABundleIdSuffix = args.updatedWDABundleIdSuffix ?? DEFAULT_TEST_BUNDLE_SUFFIX;
117
114
 
118
115
  this._xcodebuild = this.canSkipXcodebuild
@@ -366,15 +363,14 @@ export class WebDriverAgent {
366
363
  async quit(): Promise<void> {
367
364
  if (this.usePreinstalledWDA) {
368
365
  this.log.info('Stopping the XCTest session');
369
- if (this.xctestApiClient) {
370
- this.xctestApiClient.stop();
371
- this.xctestApiClient = null;
372
- } else {
373
- try {
366
+ try {
367
+ if (this.device.simctl) {
374
368
  await this.device.simctl.terminateApp(this.bundleIdForXctest);
375
- } catch (e: any) {
376
- this.log.warn(e.message);
369
+ } else if (this.device.devicectl) {
370
+ await this.device.devicectl.terminateApp(this.bundleIdForXctest);
377
371
  }
372
+ } catch (e: any) {
373
+ this.log.warn(e.message);
378
374
  }
379
375
  } else if (!this.args.webDriverAgentUrl) {
380
376
  this.log.info('Shutting down sub-processes');
@@ -383,8 +379,7 @@ export class WebDriverAgent {
383
379
  }
384
380
  } else {
385
381
  this.log.debug(
386
- 'Do not stop xcodebuild nor XCTest session ' +
387
- 'since the WDA session is managed by outside this driver.',
382
+ 'Stopping neither xcodebuild nor XCTest session since WDA lifecycle is not managed by this driver',
388
383
  );
389
384
  }
390
385
 
@@ -402,7 +397,21 @@ export class WebDriverAgent {
402
397
  }
403
398
 
404
399
  /**
405
- * Retrieves the Xcode derived data path for WebDriverAgent.
400
+ * Retrieves Xcode build settings.
401
+ * @param options - Optional scheme, SDK, configuration, or destination
402
+ * @returns Build settings, or `undefined` if xcodebuild is skipped or settings cannot be determined
403
+ */
404
+ async retrieveBuildSettings(
405
+ options?: RetrieveBuildSettingsOptions,
406
+ ): Promise<XcodeBuildSettings | undefined> {
407
+ if (this.canSkipXcodebuild) {
408
+ return;
409
+ }
410
+ return await this.xcodebuild.retrieveBuildSettings(options);
411
+ }
412
+
413
+ /**
414
+ * @deprecated Use {@link retrieveBuildSettings} instead. Will be removed in a future release.
406
415
  * @returns The derived data path, or `undefined` if xcodebuild is skipped
407
416
  */
408
417
  async retrieveDerivedDataPath(): Promise<string | undefined> {
@@ -415,13 +424,14 @@ export class WebDriverAgent {
415
424
  /**
416
425
  * Reuse running WDA if it has the same bundle id with updatedWDABundleId.
417
426
  * Or reuse it if it has the default id without updatedWDABundleId.
418
- * Uninstall it if the method faces an exception for the above situation.
427
+ *
428
+ * @returns The WDA URL used for caching on success, or `undefined` if caching was skipped.
419
429
  */
420
- async setupCaching(): Promise<void> {
430
+ async setupCaching(): Promise<string | undefined> {
421
431
  const status = await this.getStatus(0);
422
432
  if (!status || !status.build) {
423
433
  this.log.debug('WDA is currently not running. There is nothing to cache');
424
- return;
434
+ return undefined;
425
435
  }
426
436
 
427
437
  const {productBundleIdentifier, upgradedAt} = status.build as any;
@@ -432,9 +442,9 @@ export class WebDriverAgent {
432
442
  this.updatedWDABundleId !== productBundleIdentifier
433
443
  ) {
434
444
  this.log.info(
435
- `Will uninstall running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`,
445
+ `Will not reuse running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`,
436
446
  );
437
- return await this.uninstall();
447
+ return undefined;
438
448
  }
439
449
  // for simulator
440
450
  if (
@@ -443,9 +453,9 @@ export class WebDriverAgent {
443
453
  WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier
444
454
  ) {
445
455
  this.log.info(
446
- `Will uninstall running WDA since its bundle id is not equal to the default value ${WDA_RUNNER_BUNDLE_ID}`,
456
+ `Will not reuse running WDA since its bundle id is not equal to the default value ${WDA_RUNNER_BUNDLE_ID}`,
447
457
  );
448
- return await this.uninstall();
458
+ return undefined;
449
459
  }
450
460
 
451
461
  const actualUpgradeTimestamp = await getWDAUpgradeTimestamp();
@@ -457,51 +467,21 @@ export class WebDriverAgent {
457
467
  `${actualUpgradeTimestamp}`.toLowerCase() !== `${upgradedAt}`.toLowerCase()
458
468
  ) {
459
469
  this.log.info(
460
- 'Will uninstall running WDA since it has different version in comparison to the one ' +
470
+ 'Will not reuse running WDA since it has different version in comparison to the one ' +
461
471
  `which is bundled with appium-xcuitest-driver module (${actualUpgradeTimestamp} != ${upgradedAt})`,
462
472
  );
463
- return await this.uninstall();
473
+ return undefined;
464
474
  }
465
475
 
476
+ const cachedUrl = this.url.href;
466
477
  const message = util.hasValue(productBundleIdentifier)
467
- ? `Will reuse previously cached WDA instance at '${this.url.href}' with '${productBundleIdentifier}'`
468
- : `Will reuse previously cached WDA instance at '${this.url.href}'`;
478
+ ? `Will reuse previously cached WDA instance at '${cachedUrl}' with '${productBundleIdentifier}'`
479
+ : `Will reuse previously cached WDA instance at '${cachedUrl}'`;
469
480
  this.log.info(
470
481
  `${message}. Set the wdaLocalPort capability to a value different from ${this.url.port} if this is an undesired behavior.`,
471
482
  );
472
- this.webDriverAgentUrl = this.url.href;
473
- }
474
-
475
- /**
476
- * Quit and uninstall running WDA.
477
- */
478
- async quitAndUninstall(): Promise<void> {
479
- await this.quit();
480
- await this.uninstall();
481
- }
482
-
483
- private async parseBundleId(wdaBundlePath: string): Promise<string> {
484
- const infoPlistPath = path.join(wdaBundlePath, 'Info.plist');
485
- const infoPlist = (await plist.parsePlist(await fs.readFile(infoPlistPath))) as {
486
- CFBundleIdentifier?: string;
487
- };
488
- if (!infoPlist.CFBundleIdentifier) {
489
- throw new Error(`Could not find bundle id in '${infoPlistPath}'`);
490
- }
491
- return infoPlist.CFBundleIdentifier;
492
- }
493
-
494
- private async fetchWDABundle(): Promise<string> {
495
- if (!this.derivedDataPath) {
496
- return await bundleWDASim(this.xcodebuild);
497
- }
498
- const wdaBundlePaths = await fs.glob(`${this.derivedDataPath}/**/*${WDA_RUNNER_APP}/`, {
499
- absolute: true,
500
- });
501
- if (wdaBundlePaths.length === 0) {
502
- throw new Error(`Could not find the WDA bundle in '${this.derivedDataPath}'`);
503
- }
504
- return wdaBundlePaths[0];
483
+ this.webDriverAgentUrl = cachedUrl;
484
+ return cachedUrl;
505
485
  }
506
486
 
507
487
  private setupProxies(sessionId: string): void {
@@ -549,10 +529,6 @@ export class WebDriverAgent {
549
529
  this.log.info(`Using WDA agent: '${this.agentPath}'`);
550
530
  }
551
531
 
552
- private async isRunning(): Promise<boolean> {
553
- return !!(await this.getStatus());
554
- }
555
-
556
532
  /**
557
533
  * Return current running WDA's status like below
558
534
  * {
@@ -626,32 +602,6 @@ export class WebDriverAgent {
626
602
  return status;
627
603
  }
628
604
 
629
- /**
630
- * Uninstall WDAs from the test device.
631
- * Over Xcode 11, multiple WDA can be in the device since Xcode 11 generates different WDA.
632
- * Appium does not expect multiple WDAs are running on a device.
633
- */
634
- private async uninstall(): Promise<void> {
635
- try {
636
- const bundleIds = await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME);
637
- if (bundleIds.length === 0) {
638
- this.log.debug('No WDAs on the device.');
639
- return;
640
- }
641
-
642
- this.log.debug(`Uninstalling WDAs: '${bundleIds}'`);
643
- for (const bundleId of bundleIds) {
644
- await this.device.removeApp(bundleId);
645
- }
646
- } catch (e: any) {
647
- this.log.debug(e);
648
- this.log.warn(
649
- `WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? ` +
650
- `Original error: ${e.message}`,
651
- );
652
- }
653
- }
654
-
655
605
  private async _cleanupProjectIfFresh(): Promise<void> {
656
606
  if (this.canSkipXcodebuild) {
657
607
  return;
@@ -725,9 +675,6 @@ export class WebDriverAgent {
725
675
  * https://github.com/appium/WebDriverAgent/releases
726
676
  * with proper sign for this case.
727
677
  *
728
- * When we implement launching XCTest service via appium-ios-device,
729
- * this implementation can be replaced with it.
730
- *
731
678
  * @param opts launching WDA with devicectl command options.
732
679
  */
733
680
  private async _launchViaDevicectl(
@@ -735,7 +682,10 @@ export class WebDriverAgent {
735
682
  ): Promise<void> {
736
683
  const {env} = opts;
737
684
 
738
- await this.device.devicectl.launchApp(this.bundleIdForXctest, {env, terminateExisting: true});
685
+ await (this.device.devicectl as Devicectl).launchApp(this.bundleIdForXctest, {
686
+ env,
687
+ terminateExisting: true,
688
+ });
739
689
  }
740
690
 
741
691
  /**
@@ -755,19 +705,9 @@ export class WebDriverAgent {
755
705
  }
756
706
  this.log.info('Launching WebDriverAgent on the device without xcodebuild');
757
707
  if (this.isRealDevice) {
758
- // Current method to launch WDA process can be done via 'xcrun devicectl',
759
- // but it has limitation about the WDA preinstalled package.
760
- // https://github.com/appium/appium/issues/19206#issuecomment-2014182674
761
- if (this.platformVersion && util.compareVersions(this.platformVersion, '>=', '17.0')) {
762
- await this._launchViaDevicectl({env: xctestEnv});
763
- } else {
764
- this.xctestApiClient = new Xctest(this.device.udid, this.bundleIdForXctest, null, {
765
- env: xctestEnv,
766
- });
767
- await this.xctestApiClient.start();
768
- }
708
+ await this._launchViaDevicectl({env: xctestEnv});
769
709
  } else {
770
- await this.device.simctl.exec('launch', {
710
+ await (this.device.simctl as Simctl).exec('launch', {
771
711
  args: ['--terminate-running-process', this.device.udid, this.bundleIdForXctest],
772
712
  env: xctestEnv,
773
713
  });
package/lib/xcodebuild.ts CHANGED
@@ -14,7 +14,13 @@ import {
14
14
  } from './utils';
15
15
  import path from 'node:path';
16
16
  import {WDA_RUNNER_BUNDLE_ID} from './constants';
17
- import type {AppleDevice, XcodeBuildArgs} from './types';
17
+ import type {
18
+ AppleDevice,
19
+ RetrieveBuildSettingsOptions,
20
+ XcodeBuildArgs,
21
+ XcodeBuildSettings,
22
+ XcodeShowBuildSettingsEntry,
23
+ } from './types';
18
24
  import type {NoSessionProxy} from './no-session-proxy';
19
25
 
20
26
  const DEFAULT_SIGNING_ID = 'iPhone Developer';
@@ -42,7 +48,6 @@ const REAL_DEVICES_CONFIG_DOCS_LINK =
42
48
  const xcodeLog = logger.getLogger('Xcode');
43
49
 
44
50
  export class XcodeBuild {
45
- xcodebuild?: SubProcess;
46
51
  readonly device: AppleDevice;
47
52
  readonly realDevice: boolean;
48
53
  readonly agentPath: string;
@@ -51,9 +56,9 @@ export class XcodeBuild {
51
56
  readonly platformName?: string;
52
57
  readonly iosSdkVersion?: string;
53
58
  readonly xcodeSigningId: string;
54
- usePrebuiltWDA?: boolean;
55
- derivedDataPath?: string;
56
- agentUrl?: string;
59
+ private xcodebuild?: SubProcess;
60
+ private usePrebuiltWDA?: boolean;
61
+ private derivedDataPath?: string;
57
62
  private readonly log: AppiumLogger;
58
63
  private readonly showXcodeLog?: boolean;
59
64
  private readonly xcodeConfigFile?: string;
@@ -73,7 +78,10 @@ export class XcodeBuild {
73
78
  private readonly resultBundleVersion?: string;
74
79
  private _didBuildFail: boolean;
75
80
  private _didProcessExit: boolean;
76
- private _derivedDataPathPromise?: Promise<string | undefined>;
81
+ private readonly _buildSettingsPromises = new Map<
82
+ string,
83
+ Promise<XcodeBuildSettings | undefined>
84
+ >();
77
85
  private noSessionProxy?: NoSessionProxy;
78
86
  private xctestrunFilePath?: string;
79
87
 
@@ -158,8 +166,23 @@ export class XcodeBuild {
158
166
  }
159
167
 
160
168
  /**
161
- * Retrieves the Xcode derived data path for the build.
162
- * Uses cached value if available, otherwise queries xcodebuild for BUILD_DIR.
169
+ * Retrieves Xcode build settings via `xcodebuild -showBuildSettings -json`.
170
+ * @param options - Optional scheme, SDK, configuration, or destination
171
+ * @returns Build settings for the `build` action, or `undefined` if they cannot be determined
172
+ */
173
+ async retrieveBuildSettings(
174
+ options?: RetrieveBuildSettingsOptions,
175
+ ): Promise<XcodeBuildSettings | undefined> {
176
+ const cacheKey = buildSettingsCacheKey(options);
177
+ let promise = this._buildSettingsPromises.get(cacheKey);
178
+ if (!promise) {
179
+ promise = this.fetchBuildSettings(options);
180
+ this._buildSettingsPromises.set(cacheKey, promise);
181
+ }
182
+ return await promise;
183
+ }
184
+
185
+ /**
163
186
  * @returns The derived data path, or `undefined` if it cannot be determined
164
187
  */
165
188
  async retrieveDerivedDataPath(): Promise<string | undefined> {
@@ -167,33 +190,18 @@ export class XcodeBuild {
167
190
  return this.derivedDataPath;
168
191
  }
169
192
 
170
- // avoid race conditions
171
- if (this._derivedDataPathPromise) {
172
- return await this._derivedDataPathPromise;
193
+ const buildSettings = await this.retrieveBuildSettings();
194
+ const buildDir = buildSettings?.BUILD_DIR;
195
+ if (!buildDir) {
196
+ this.log.warn('Cannot parse WDA BUILD_DIR from build settings');
197
+ return;
173
198
  }
174
199
 
175
- this._derivedDataPathPromise = (async () => {
176
- let stdout: string;
177
- try {
178
- ({stdout} = await exec('xcodebuild', ['-project', this.agentPath, '-showBuildSettings']));
179
- } catch (err: any) {
180
- this.log.warn(`Cannot retrieve WDA build settings. Original error: ${err.message}`);
181
- return;
182
- }
183
-
184
- const pattern = /^\s*BUILD_DIR\s+=\s+(\/.*)/m;
185
- const match = pattern.exec(stdout);
186
- if (!match) {
187
- this.log.warn(`Cannot parse WDA build dir from ${truncateString(stdout, 300)}`);
188
- return;
189
- }
190
- this.log.debug(`Parsed BUILD_DIR configuration value: '${match[1]}'`);
191
- // Derived data root is two levels higher over the build dir
192
- this.derivedDataPath = path.dirname(path.dirname(path.normalize(match[1])));
193
- this.log.debug(`Got derived data root: '${this.derivedDataPath}'`);
194
- return this.derivedDataPath;
195
- })();
196
- return await this._derivedDataPathPromise;
200
+ this.log.debug(`Parsed BUILD_DIR configuration value: '${buildDir}'`);
201
+ // Derived data root is two levels higher over the build dir
202
+ this.derivedDataPath = path.dirname(path.dirname(path.normalize(buildDir)));
203
+ this.log.debug(`Got derived data root: '${this.derivedDataPath}'`);
204
+ return this.derivedDataPath;
197
205
  }
198
206
 
199
207
  /**
@@ -297,6 +305,45 @@ export class XcodeBuild {
297
305
  await killProcess('xcodebuild', this.xcodebuild);
298
306
  }
299
307
 
308
+ private async fetchBuildSettings(
309
+ options?: RetrieveBuildSettingsOptions,
310
+ ): Promise<XcodeBuildSettings | undefined> {
311
+ const schemeLabel = options?.scheme ?? 'default';
312
+ let stdout: string;
313
+ try {
314
+ ({stdout} = await exec('xcodebuild', [
315
+ '-project',
316
+ this.agentPath,
317
+ '-showBuildSettings',
318
+ '-json',
319
+ ...buildSettingsArgsFromOptions(options),
320
+ ]));
321
+ } catch (err: any) {
322
+ this.log.warn(
323
+ `Cannot retrieve WDA build settings for scheme '${schemeLabel}'. Original error: ${err.message}`,
324
+ );
325
+ return;
326
+ }
327
+
328
+ let entries: XcodeShowBuildSettingsEntry[];
329
+ try {
330
+ entries = JSON.parse(stdout) as XcodeShowBuildSettingsEntry[];
331
+ } catch (err: any) {
332
+ this.log.warn(
333
+ `Cannot parse WDA build settings for scheme '${schemeLabel}' from ${truncateString(stdout, 300)}. ` +
334
+ `Original error: ${err.message}`,
335
+ );
336
+ return;
337
+ }
338
+
339
+ const entry = entries.find(({action}) => action === 'build') ?? entries[0];
340
+ if (!entry?.buildSettings) {
341
+ this.log.warn(`Cannot find build settings for scheme '${schemeLabel}'`);
342
+ return;
343
+ }
344
+ return entry.buildSettings;
345
+ }
346
+
300
347
  private getCommand(buildOnly: boolean = false): {cmd: string; args: string[]} {
301
348
  const cmd = 'xcodebuild';
302
349
  const args: string[] = [];
@@ -465,9 +512,6 @@ export class XcodeBuild {
465
512
  (noSessionProxy as any).timeout = 1000;
466
513
  try {
467
514
  currentStatus = (await noSessionProxy.command('/status', 'GET')) as StringRecord;
468
- if (currentStatus?.ios?.ip) {
469
- this.agentUrl = currentStatus.ios.ip as string;
470
- }
471
515
  this.log.debug(`WebDriverAgent information:`);
472
516
  this.log.debug(JSON.stringify(currentStatus, null, 2));
473
517
  } catch (err: any) {
@@ -498,3 +542,27 @@ export class XcodeBuild {
498
542
  return currentStatus;
499
543
  }
500
544
  }
545
+
546
+ function buildSettingsArgsFromOptions(options?: RetrieveBuildSettingsOptions): string[] {
547
+ const args: string[] = [];
548
+ if (!options) {
549
+ return args;
550
+ }
551
+ if (options.scheme) {
552
+ args.push('-scheme', options.scheme);
553
+ }
554
+ if (options.sdk) {
555
+ args.push('-sdk', options.sdk);
556
+ }
557
+ if (options.configuration) {
558
+ args.push('-configuration', options.configuration);
559
+ }
560
+ if (options.destination) {
561
+ args.push('-destination', options.destination);
562
+ }
563
+ return args;
564
+ }
565
+
566
+ function buildSettingsCacheKey(options?: RetrieveBuildSettingsOptions): string {
567
+ return buildSettingsArgsFromOptions(options).join('\0');
568
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "12.2.2",
3
+ "version": "13.1.0",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "main": "./build/lib/index.js",
6
6
  "types": "./build/lib/index.d.ts",
@@ -65,6 +65,7 @@
65
65
  "chai-as-promised": "^8.0.0",
66
66
  "conventional-changelog-conventionalcommits": "^9.0.0",
67
67
  "mocha": "^11.0.1",
68
+ "node-devicectl": "^1.4.0",
68
69
  "node-simctl": "^8.0.0",
69
70
  "prettier": "^3.0.0",
70
71
  "semantic-release": "^25.0.2",
@@ -77,7 +78,6 @@
77
78
  "@appium/base-driver": "^10.3.0",
78
79
  "@appium/strongbox": "^1.0.0-rc.1",
79
80
  "@appium/support": "^7.0.0-rc.1",
80
- "appium-ios-device": "^3.0.0",
81
81
  "appium-ios-simulator": "^8.0.0",
82
82
  "async-lock": "^1.0.0",
83
83
  "asyncbox": "^6.1.0",
@@ -1,7 +0,0 @@
1
- declare module 'appium-ios-device' {
2
- export class Xctest {
3
- constructor(...args: any[]);
4
- start(): Promise<void>;
5
- stop(): void;
6
- }
7
- }