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.
- package/CHANGELOG.md +20 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +6 -0
- package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme +18 -0
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentRunner/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- package/WebDriverAgentRunner/Assets.xcassets/AppIcon.appiconset/icon-1024.png +0 -0
- package/WebDriverAgentRunner/Assets.xcassets/Contents.json +6 -0
- package/build/lib/index.d.ts +1 -1
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +2 -1
- package/build/lib/index.js.map +1 -1
- package/build/lib/types.d.ts +23 -3
- package/build/lib/types.d.ts.map +1 -1
- package/build/lib/webdriveragent.d.ts +11 -23
- package/build/lib/webdriveragent.d.ts.map +1 -1
- package/build/lib/webdriveragent.js +39 -100
- package/build/lib/webdriveragent.js.map +1 -1
- package/build/lib/xcodebuild.d.ts +12 -9
- package/build/lib/xcodebuild.d.ts.map +1 -1
- package/build/lib/xcodebuild.js +80 -33
- package/build/lib/xcodebuild.js.map +1 -1
- package/lib/index.ts +1 -1
- package/lib/types.ts +33 -3
- package/lib/webdriveragent.ts +52 -112
- package/lib/xcodebuild.ts +104 -36
- package/package.json +2 -2
- package/lib/appium-ios-device.d.ts +0 -7
package/lib/webdriveragent.ts
CHANGED
|
@@ -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
|
|
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 {
|
|
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
|
-
|
|
370
|
-
this.
|
|
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
|
-
}
|
|
376
|
-
this.
|
|
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
|
-
'
|
|
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
|
|
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
|
-
*
|
|
427
|
+
*
|
|
428
|
+
* @returns The WDA URL used for caching on success, or `undefined` if caching was skipped.
|
|
419
429
|
*/
|
|
420
|
-
async setupCaching(): Promise<
|
|
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
|
|
445
|
+
`Will not reuse running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`,
|
|
436
446
|
);
|
|
437
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 '${
|
|
468
|
-
: `Will reuse previously cached WDA instance at '${
|
|
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 =
|
|
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, {
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
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
|
|
162
|
-
*
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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": "
|
|
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",
|