@devicelab/maestro-runner-darwin-arm64 1.1.28 → 1.1.30
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/README.md +30 -3
- package/bin/maestro-runner +0 -0
- package/drivers/android/devicelab-android-driver-test.apk +0 -0
- package/drivers/android/devicelab-android-driver.apk +0 -0
- package/drivers/ios/DevicelabIOSRunner/DevicelabIOSRunnerUITests/ATTRIBUTION.md +16 -0
- package/drivers/ios/DevicelabIOSRunner/DevicelabIOSRunnerUITests/RunnerTests+Lifecycle.swift +33 -0
- package/drivers/ios/DevicelabIOSRunner/DevicelabIOSRunnerUITests/RunnerTests+Snapshot.swift +195 -88
- package/drivers/ios/DevicelabIOSRunner/DevicelabIOSRunnerUITests/RunnerTests.swift +3 -0
- package/drivers/ios/WebDriverAgent/CHANGELOG.md +202 -0
- package/drivers/ios/WebDriverAgent/README.md +18 -9
- package/drivers/ios/WebDriverAgent/Scripts/ci/build-real.sh +6 -10
- package/drivers/ios/WebDriverAgent/Scripts/fetch-prebuilt-wda.mjs +3 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgent.xcodeproj/project.pbxproj +119 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCAXClient_iOS+FBSnapshotReqParams.m +8 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +3 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +30 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIApplication+FBTouchAction.h +53 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIApplication+FBTouchAction.m +124 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.h +6 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +100 -23
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBHinge.h +41 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBHinge.m +215 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m +8 -3
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +20 -7
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +110 -50
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBTyping.h +7 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +20 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +14 -11
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Commands/FBCustomCommands.m +86 -10
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Commands/FBElementCommands.m +57 -7
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Commands/FBSessionCommands.m +3 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Info.plist +2 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBHTTPServer.m +39 -16
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBScreenRecordingRequest.m +7 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBSession.h +22 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBSession.m +78 -12
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBTCPSocket.h +5 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBTCPSocket.m +10 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBWebServer.m +4 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBActiveAppDetectionPoint.h +2 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBActiveAppDetectionPoint.m +20 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBConfiguration.h +8 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBConfiguration.m +2 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBHIDOperations.h +41 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBHIDOperations.m +244 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBImageProcessor.m +3 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBMathUtils.h +11 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBMathUtils.m +38 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBMjpegServer.m +5 -3
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBScreen.h +17 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBScreen.m +76 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBScreenshot.h +2 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBScreenshot.m +6 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBSettings.h +2 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBSettings.m +2 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBSettingsHandler.m +48 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +121 -13
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBXPath.m +181 -128
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m +8 -5
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/LRUCache/LRUCacheNode.h +1 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/WebDriverAgentLib.h +1 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationApp/COORDINATE_PROBE.md +3 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationApp/Classes/FBCoordinateProbeViewController.m +18 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationApp/Classes/SceneDelegate.m +33 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationApp/Classes/ViewController.m +26 -7
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBConfigurationTests.m +52 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBDisplayGestureTests.m +541 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBElementSwipingTests.m +95 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBImageProcessorTests.m +34 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBScreenTests.m +392 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +97 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBTypingTest.m +33 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m +126 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +111 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m +97 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/XCUIDeviceRotationTests.m +53 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +113 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests_tvOS/FBTVFocusIntegrationTests.m +21 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests_watchOS/WDAAppLifecycleIntegrationTests.swift +12 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBCustomCommandsTests.m +61 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBElementUtilitiesTests.m +40 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBHTTPServerSessionTests.m +22 -4
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBHTTPServerTests.m +199 -5
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBLRUCacheTests.m +34 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBMathUtilsTests.m +45 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBSessionTests.m +201 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBXPathTests.m +101 -0
- package/drivers/ios/WebDriverAgent/docs/hinge-angle.md +54 -0
- package/drivers/ios/WebDriverAgent/docs/multiple-displays.md +168 -0
- package/drivers/ios/WebDriverAgent/lib/webdriveragent.ts +1 -2
- package/drivers/ios/WebDriverAgent/lib/xcodebuild.ts +58 -10
- package/drivers/ios/WebDriverAgent/package.json +8 -15
- package/drivers/ios/WebDriverAgent/test/functional/helpers/display-settings.ts +49 -0
- package/drivers/ios/WebDriverAgent/test/functional/helpers/simulator.ts +7 -7
- package/drivers/ios/WebDriverAgent/test/functional/webdriveragent-e2e.spec.ts +4 -0
- package/drivers/ios/WebDriverAgent/test/unit/xcodebuild.spec.ts +230 -0
- package/drivers/ios/WebDriverAgent/tsconfig.json +2 -1
- package/drivers/ios/devicelab-ios-agent/README.md +12 -0
- package/drivers/ios/devicelab-ios-agent/device/DevicelabIOSAgent.app/DevicelabIOSAgent +0 -0
- package/drivers/ios/devicelab-ios-agent/device/DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/DevicelabIOSAgentUITests +0 -0
- package/drivers/ios/devicelab-ios-agent/device/manifest.json +3 -3
- package/drivers/ios/devicelab-ios-agent/simulator/DevicelabIOSAgent.app/DevicelabIOSAgent +0 -0
- package/drivers/ios/devicelab-ios-agent/simulator/DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/DevicelabIOSAgentUITests +0 -0
- package/drivers/ios/devicelab-ios-agent/simulator/manifest.json +3 -3
- package/package.json +1 -1
- package/drivers/ios/WebDriverAgent/.editorconfig +0 -11
- package/drivers/ios/WebDriverAgent/.github/ISSUE_TEMPLATE.md +0 -4
- package/drivers/ios/WebDriverAgent/.github/actions/xcode-setup/action.yml +0 -32
- package/drivers/ios/WebDriverAgent/.github/dependabot.yml +0 -22
- package/drivers/ios/WebDriverAgent/.github/workflows/functional-test.yml +0 -103
- package/drivers/ios/WebDriverAgent/.github/workflows/pr-title.yml +0 -10
- package/drivers/ios/WebDriverAgent/.github/workflows/publish.js.yml +0 -112
- package/drivers/ios/WebDriverAgent/.github/workflows/unit-test.yml +0 -32
- package/drivers/ios/WebDriverAgent/.github/workflows/wda-package.yml +0 -114
- package/drivers/ios/WebDriverAgent/.github/workflows/wda-tests.yml +0 -246
- package/drivers/ios/WebDriverAgent/oxfmt.config.mjs +0 -6
- package/drivers/ios/WebDriverAgent/oxlint.config.mjs +0 -6
- package/drivers/ios/WebDriverAgent/release.config.mjs +0 -14
|
@@ -26,6 +26,9 @@ import {
|
|
|
26
26
|
|
|
27
27
|
const DEFAULT_SIGNING_ID = 'iPhone Developer';
|
|
28
28
|
const PREBUILD_DELAY = 0;
|
|
29
|
+
// Bounds the best-effort udid case lookup so a hung 'xcodebuild -showdestinations' cannot stall
|
|
30
|
+
// session startup past wdaLaunchTimeout, which does not cover this step.
|
|
31
|
+
const XCODE_DEVICE_UDID_RESOLUTION_TIMEOUT_MS = 15000;
|
|
29
32
|
|
|
30
33
|
const ERROR_WRITING_ATTACHMENT = 'Error writing attachment data to file';
|
|
31
34
|
const ERROR_COPYING_ATTACHMENT = 'Error copying testing attachment';
|
|
@@ -43,6 +46,7 @@ export class XcodeBuild {
|
|
|
43
46
|
readonly device: AppleDevice;
|
|
44
47
|
readonly realDevice: boolean;
|
|
45
48
|
readonly agentPath: string;
|
|
49
|
+
private _xcodeDeviceUdidPromise?: Promise<string>;
|
|
46
50
|
readonly bootstrapPath: string;
|
|
47
51
|
readonly platformVersion?: string;
|
|
48
52
|
readonly platformName?: string;
|
|
@@ -70,7 +74,6 @@ export class XcodeBuild {
|
|
|
70
74
|
private readonly resultBundlePath?: string;
|
|
71
75
|
private readonly resultBundleVersion?: string;
|
|
72
76
|
private _didBuildFail: boolean;
|
|
73
|
-
private _didProcessExit: boolean;
|
|
74
77
|
private readonly _buildSettingsPromises = new Map<string, Promise<XcodeBuildSettings | undefined>>();
|
|
75
78
|
private noSessionProxy?: NoSessionProxy;
|
|
76
79
|
private xctestrunFilePath?: string;
|
|
@@ -126,7 +129,6 @@ export class XcodeBuild {
|
|
|
126
129
|
this.resultBundleVersion = args.resultBundleVersion;
|
|
127
130
|
|
|
128
131
|
this._didBuildFail = false;
|
|
129
|
-
this._didProcessExit = false;
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
/**
|
|
@@ -138,6 +140,8 @@ export class XcodeBuild {
|
|
|
138
140
|
this.noSessionProxy = noSessionProxy;
|
|
139
141
|
|
|
140
142
|
if (this.useXctestrunFile) {
|
|
143
|
+
// Keep the caller's udid casing: the canonical case is only for '-destination id=';
|
|
144
|
+
// switching it here would orphan an existing .xctestrun file on case-sensitive filesystems.
|
|
141
145
|
const deviceInfo = {
|
|
142
146
|
isRealDevice: !!this.realDevice,
|
|
143
147
|
udid: this.device.udid,
|
|
@@ -244,11 +248,13 @@ export class XcodeBuild {
|
|
|
244
248
|
throw new Error('xcodebuild subprocess was not created');
|
|
245
249
|
}
|
|
246
250
|
const xcodebuild = this.xcodebuild;
|
|
251
|
+
// Exit state belongs to this invocation, including build-only invocations.
|
|
252
|
+
let didProcessExit = false;
|
|
247
253
|
return await new Promise<StringRecord | void>((resolve, reject) => {
|
|
248
254
|
xcodebuild.once('exit', (code, signal) => {
|
|
249
255
|
xcodeLog.error(`xcodebuild exited with code '${code}' and signal '${signal}'`);
|
|
250
256
|
xcodebuild.removeAllListeners();
|
|
251
|
-
|
|
257
|
+
didProcessExit = true;
|
|
252
258
|
if (this._didBuildFail || (!signal && code !== 0)) {
|
|
253
259
|
let errorMessage =
|
|
254
260
|
`xcodebuild failed with code ${code}.` +
|
|
@@ -279,7 +285,7 @@ export class XcodeBuild {
|
|
|
279
285
|
}
|
|
280
286
|
await xcodebuild.start(true);
|
|
281
287
|
if (!buildOnly) {
|
|
282
|
-
const result = await this.waitForStart(timer);
|
|
288
|
+
const result = await this.waitForStart(timer, () => didProcessExit);
|
|
283
289
|
resolve(result ?? undefined);
|
|
284
290
|
}
|
|
285
291
|
} catch (err: any) {
|
|
@@ -358,7 +364,48 @@ export class XcodeBuild {
|
|
|
358
364
|
return entry.buildSettings;
|
|
359
365
|
}
|
|
360
366
|
|
|
361
|
-
|
|
367
|
+
/**
|
|
368
|
+
* Best-effort resolves this real device's udid to the case xcodebuild's own
|
|
369
|
+
* `-showdestinations` listing reports it in, so the `-destination id=` argument this class
|
|
370
|
+
* builds does not depend on whatever case the caller happened to pass in — different Apple
|
|
371
|
+
* tooling doesn't agree on udid letter case. Falls back to `device.udid` unchanged on any
|
|
372
|
+
* failure, timeout, or when no destination matches. A no-op for simulators, whose udid is
|
|
373
|
+
* already canonical by construction.
|
|
374
|
+
*/
|
|
375
|
+
private resolveXcodeDeviceUdid(): Promise<string> {
|
|
376
|
+
if (!this.realDevice) {
|
|
377
|
+
return Promise.resolve(this.device.udid);
|
|
378
|
+
}
|
|
379
|
+
// Cache the in-flight promise itself (not just a "did we start" flag), so concurrent callers
|
|
380
|
+
// await the same resolution instead of one of them racing ahead with a value that isn't
|
|
381
|
+
// resolved yet.
|
|
382
|
+
if (!this._xcodeDeviceUdidPromise) {
|
|
383
|
+
this._xcodeDeviceUdidPromise = this.fetchXcodeDeviceUdid();
|
|
384
|
+
}
|
|
385
|
+
return this._xcodeDeviceUdidPromise;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private async fetchXcodeDeviceUdid(): Promise<string> {
|
|
389
|
+
const runnerScheme = `WebDriverAgentRunner${getPlatformSchemeSuffix(this.platformName || '')}`;
|
|
390
|
+
let stdout: string;
|
|
391
|
+
try {
|
|
392
|
+
({stdout} = await exec('xcodebuild', ['-showdestinations', '-project', this.agentPath, '-scheme', runnerScheme], {
|
|
393
|
+
timeout: XCODE_DEVICE_UDID_RESOLUTION_TIMEOUT_MS,
|
|
394
|
+
}));
|
|
395
|
+
} catch (err: any) {
|
|
396
|
+
this.log.debug(
|
|
397
|
+
`Cannot list xcodebuild destinations to resolve the canonical udid case for '${this.device.udid}'. ` +
|
|
398
|
+
`Will use it as is. Original error: ${err.message}`,
|
|
399
|
+
);
|
|
400
|
+
return this.device.udid;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const udid = this.device.udid.toLowerCase();
|
|
404
|
+
const match = [...stdout.matchAll(/\bid:([0-9A-Fa-f-]+)/g)].find(([, id]) => id.toLowerCase() === udid);
|
|
405
|
+
return match?.[1] ?? this.device.udid;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
private getCommand(buildOnly: boolean, resolvedUdid: string): {cmd: string; args: string[]} {
|
|
362
409
|
const cmd = 'xcodebuild';
|
|
363
410
|
const args: string[] = [];
|
|
364
411
|
|
|
@@ -396,7 +443,7 @@ export class XcodeBuild {
|
|
|
396
443
|
args.push('-derivedDataPath', this.derivedDataPath);
|
|
397
444
|
}
|
|
398
445
|
}
|
|
399
|
-
args.push('-destination', `id=${
|
|
446
|
+
args.push('-destination', `id=${resolvedUdid}`);
|
|
400
447
|
|
|
401
448
|
const versionMatch = this.platformVersion ? new RegExp(/^(\d+)\.(\d+)/).exec(this.platformVersion) : null;
|
|
402
449
|
if (versionMatch) {
|
|
@@ -443,7 +490,8 @@ export class XcodeBuild {
|
|
|
443
490
|
await setRealDeviceSecurity(this.keychainPath, this.keychainPassword);
|
|
444
491
|
}
|
|
445
492
|
|
|
446
|
-
const
|
|
493
|
+
const resolvedUdid = await this.resolveXcodeDeviceUdid();
|
|
494
|
+
const {cmd, args} = this.getCommand(buildOnly, resolvedUdid);
|
|
447
495
|
this.log.debug(
|
|
448
496
|
`Beginning ${buildOnly ? 'build' : 'test'} with command '${cmd} ${args.join(' ')}' ` +
|
|
449
497
|
`in directory '${this.bootstrapPath}'`,
|
|
@@ -505,7 +553,7 @@ export class XcodeBuild {
|
|
|
505
553
|
return xcodebuild;
|
|
506
554
|
}
|
|
507
555
|
|
|
508
|
-
private async waitForStart(timer: timing.Timer): Promise<StringRecord | null> {
|
|
556
|
+
private async waitForStart(timer: timing.Timer, didProcessExit: () => boolean): Promise<StringRecord | null> {
|
|
509
557
|
// try to connect once every 0.5 seconds, until `launchTimeout` is up
|
|
510
558
|
const timeout = this.launchTimeout || 60000; // Default to 60 seconds if not set
|
|
511
559
|
this.log.debug(`Waiting up to ${timeout}ms for WebDriverAgent to start`);
|
|
@@ -517,7 +565,7 @@ export class XcodeBuild {
|
|
|
517
565
|
}
|
|
518
566
|
const noSessionProxy = this.noSessionProxy;
|
|
519
567
|
await retryInterval(retries, 1000, async () => {
|
|
520
|
-
if (
|
|
568
|
+
if (didProcessExit()) {
|
|
521
569
|
// there has been an error elsewhere and we need to short-circuit
|
|
522
570
|
return currentStatus;
|
|
523
571
|
}
|
|
@@ -537,7 +585,7 @@ export class XcodeBuild {
|
|
|
537
585
|
}
|
|
538
586
|
});
|
|
539
587
|
|
|
540
|
-
if (
|
|
588
|
+
if (didProcessExit()) {
|
|
541
589
|
// there has been an error elsewhere and we need to short-circuit
|
|
542
590
|
return currentStatus;
|
|
543
591
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-webdriveragent",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.17.5",
|
|
4
4
|
"description": "Package bundling WebDriverAgent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Appium",
|
|
@@ -9,15 +9,16 @@
|
|
|
9
9
|
"WebDriverAgent",
|
|
10
10
|
"iOS"
|
|
11
11
|
],
|
|
12
|
-
"homepage": "https://github.com/appium/
|
|
12
|
+
"homepage": "https://github.com/appium/appium-ios/tree/main/packages/webdriveragent",
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/appium/
|
|
14
|
+
"url": "https://github.com/appium/appium-ios/issues"
|
|
15
15
|
},
|
|
16
16
|
"license": "Apache-2.0",
|
|
17
17
|
"author": "Appium Contributors",
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": "
|
|
20
|
+
"url": "https://github.com/appium/appium-ios.git",
|
|
21
|
+
"directory": "packages/webdriveragent"
|
|
21
22
|
},
|
|
22
23
|
"files": [
|
|
23
24
|
"lib",
|
|
@@ -48,10 +49,6 @@
|
|
|
48
49
|
"build": "tsc -b",
|
|
49
50
|
"dev": "npm run build -- --watch",
|
|
50
51
|
"clean": "npm run build -- --clean",
|
|
51
|
-
"lint": "oxlint -c oxlint.config.mjs .",
|
|
52
|
-
"lint:fix": "oxlint -c oxlint.config.mjs --fix .",
|
|
53
|
-
"format": "oxfmt -c oxfmt.config.mjs .",
|
|
54
|
-
"format:check": "oxfmt -c oxfmt.config.mjs --check .",
|
|
55
52
|
"prepare": "npm run build",
|
|
56
53
|
"version": "npm run sync-wda-version",
|
|
57
54
|
"test": "node --enable-source-maps --experimental-test-module-mocks --test --test-timeout=60000 \"./build/test/unit/**/*.spec.js\"",
|
|
@@ -67,22 +64,18 @@
|
|
|
67
64
|
"@appium/base-driver": "^10.8.0",
|
|
68
65
|
"@appium/strongbox": "^2.0.0",
|
|
69
66
|
"@appium/support": "^7.2.6",
|
|
70
|
-
"
|
|
71
|
-
"async-lock": "^1.0.0",
|
|
72
|
-
"asyncbox": "^6.4.3",
|
|
67
|
+
"asyncbox": "^6.5.0",
|
|
73
68
|
"axios": "^1.18.0",
|
|
74
69
|
"teen_process": "^4.2.0"
|
|
75
70
|
},
|
|
76
71
|
"devDependencies": {
|
|
72
|
+
"@appium/coresim": "^1.14.0",
|
|
77
73
|
"@appium/oxc-config": "^1.1.0",
|
|
78
|
-
"@appium/semantic-release-config": "^1.1.0",
|
|
79
74
|
"@appium/tsconfig": "^1.2.0",
|
|
80
75
|
"@appium/types": "^1.0.0-rc.1",
|
|
81
|
-
"@types/async-lock": "^1.4.2",
|
|
82
76
|
"@types/node": "^26.0.0",
|
|
83
77
|
"@types/sinon": "^22.0.0",
|
|
84
|
-
"appium-xcode": "^7.
|
|
85
|
-
"node-simctl": "^9.0.0",
|
|
78
|
+
"appium-xcode": "^7.2.4",
|
|
86
79
|
"semver": "^7.3.7",
|
|
87
80
|
"sinon": "^22.0.0"
|
|
88
81
|
},
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
|
|
3
|
+
/** Exercise the currentDisplayId setting against a live WDA session. */
|
|
4
|
+
export async function assertCurrentDisplayIdSetting(baseUrl: string, sessionId: string): Promise<void> {
|
|
5
|
+
const screensResponse = await fetch(`${baseUrl}/wda/screens`);
|
|
6
|
+
assert.equal(screensResponse.status, 200);
|
|
7
|
+
const {value: screens} = (await screensResponse.json()) as {
|
|
8
|
+
value: {displayId: number; isMain: boolean}[];
|
|
9
|
+
};
|
|
10
|
+
const main = screens.find((screen) => screen.isMain);
|
|
11
|
+
assert.ok(main, 'expected a main display');
|
|
12
|
+
const sessionUrl = `${baseUrl}/session/${sessionId}`;
|
|
13
|
+
const setDisplay = async (value: unknown) =>
|
|
14
|
+
await fetch(`${sessionUrl}/appium/settings`, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: {'Content-Type': 'application/json'},
|
|
17
|
+
body: JSON.stringify({settings: {currentDisplayId: value}}),
|
|
18
|
+
});
|
|
19
|
+
const getDisplay = async () => {
|
|
20
|
+
const response = await fetch(`${sessionUrl}/appium/settings`);
|
|
21
|
+
assert.equal(response.status, 200);
|
|
22
|
+
return ((await response.json()) as {value: {currentDisplayId: number}}).value.currentDisplayId;
|
|
23
|
+
};
|
|
24
|
+
const assertScreenshot = async () => {
|
|
25
|
+
const response = await fetch(`${sessionUrl}/screenshot`);
|
|
26
|
+
assert.equal(response.status, 200);
|
|
27
|
+
const {value} = (await response.json()) as {value: string};
|
|
28
|
+
assert.ok(Buffer.from(value, 'base64').length > 0, 'expected screenshot data');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
assert.equal(await getDisplay(), main.displayId);
|
|
32
|
+
assert.equal((await setDisplay(main.displayId)).status, 200);
|
|
33
|
+
assert.equal(await getDisplay(), main.displayId);
|
|
34
|
+
await assertScreenshot();
|
|
35
|
+
|
|
36
|
+
const unknownId = Math.max(...screens.map((screen) => screen.displayId)) + 1;
|
|
37
|
+
for (const value of [true, false, unknownId, 1.5, '1']) {
|
|
38
|
+
const response = await setDisplay(value);
|
|
39
|
+
assert.equal(response.status, 400, `expected invalid argument for ${JSON.stringify(value)}`);
|
|
40
|
+
const {value: body} = (await response.json()) as {value: {error: string}};
|
|
41
|
+
assert.equal(body.error, 'invalid argument');
|
|
42
|
+
assert.equal(await getDisplay(), main.displayId, 'invalid input must not change the display');
|
|
43
|
+
}
|
|
44
|
+
assert.equal(await getDisplay(), main.displayId);
|
|
45
|
+
|
|
46
|
+
assert.equal((await setDisplay(null)).status, 200);
|
|
47
|
+
assert.equal(await getDisplay(), main.displayId);
|
|
48
|
+
await assertScreenshot();
|
|
49
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {NativeSimctl, SimDeviceState} from '@appium/coresim';
|
|
2
2
|
|
|
3
3
|
import type {AppleDevice} from '../../../lib/types.js';
|
|
4
4
|
import {DEVICE_NAME} from '../desired.js';
|
|
@@ -9,7 +9,7 @@ const LOCAL_SIM_BOOT_TIMEOUT_MS = 60 * 1000 * 5;
|
|
|
9
9
|
* Locates the simulator these tests should run against.
|
|
10
10
|
*
|
|
11
11
|
* In CI, the workflow boots and settles a simulator ahead of time (via
|
|
12
|
-
* `futureware-tech/simulator-action`
|
|
12
|
+
* `futureware-tech/simulator-action` with `settle_timeout_seconds`) and passes its
|
|
13
13
|
* UDID through `SIMULATOR_UDID` - these tests must not boot their own there, since CI applies the
|
|
14
14
|
* settle-wait stability fix once per job, not once per test file.
|
|
15
15
|
*
|
|
@@ -28,17 +28,17 @@ export async function getTargetDevice(): Promise<AppleDevice> {
|
|
|
28
28
|
return {udid: process.env.SIMULATOR_UDID};
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const simctl = new
|
|
32
|
-
const allDevices =
|
|
31
|
+
const simctl = new NativeSimctl();
|
|
32
|
+
const allDevices = await simctl.getDevices();
|
|
33
33
|
const device = allDevices.find((d) => d.name === DEVICE_NAME);
|
|
34
34
|
if (!device) {
|
|
35
35
|
const available = [...new Set(allDevices.map((d) => d.name))].sort().join(', ');
|
|
36
36
|
throw new Error(`No simulator named '${DEVICE_NAME}' exists. Available simulators: ${available || '(none)'}`);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
if (device.state !==
|
|
40
|
-
simctl.
|
|
41
|
-
await simctl.
|
|
39
|
+
if (device.state !== SimDeviceState.Booted) {
|
|
40
|
+
await simctl.bootDevice(device.udid);
|
|
41
|
+
await simctl.waitForBoot(device.udid, {timeoutMs: LOCAL_SIM_BOOT_TIMEOUT_MS});
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
return {udid: device.udid};
|
|
@@ -5,6 +5,7 @@ import {describe, before, afterEach, it} from 'node:test';
|
|
|
5
5
|
import type {AppleDevice} from '../../lib/types.js';
|
|
6
6
|
import {WebDriverAgent} from '../../lib/webdriveragent.js';
|
|
7
7
|
import {PLATFORM_NAME, PLATFORM_VERSION} from './desired.js';
|
|
8
|
+
import {assertCurrentDisplayIdSetting} from './helpers/display-settings.js';
|
|
8
9
|
import {getTargetDevice} from './helpers/simulator.js';
|
|
9
10
|
|
|
10
11
|
const WDA_BASE_URL = 'http://localhost:8100';
|
|
@@ -59,6 +60,9 @@ async function assertSessionScopedSourceWorks(): Promise<void> {
|
|
|
59
60
|
assert.equal(sessionSourceResponse.status, 200);
|
|
60
61
|
const sessionSource = (await sessionSourceResponse.json()) as {value: string};
|
|
61
62
|
assert.ok(sessionSource.value.length > 0, 'expected session-scoped /source to return non-empty page source');
|
|
63
|
+
if (PLATFORM_NAME.toLowerCase() === 'ios') {
|
|
64
|
+
await assertCurrentDisplayIdSetting(WDA_BASE_URL, wdaSessionId);
|
|
65
|
+
}
|
|
62
66
|
} finally {
|
|
63
67
|
await fetch(`${WDA_BASE_URL}/session/${wdaSessionId}`, {method: 'DELETE'});
|
|
64
68
|
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import {EventEmitter} from 'node:events';
|
|
3
|
+
import {describe, it, beforeEach, mock} from 'node:test';
|
|
4
|
+
|
|
5
|
+
import * as teenProcess from 'teen_process';
|
|
6
|
+
|
|
7
|
+
import type {XcodeBuildArgs} from '../../lib/types.js';
|
|
8
|
+
import * as utilsIndex from '../../lib/utils/index.js';
|
|
9
|
+
|
|
10
|
+
let currentExec: (...args: any[]) => any = async () => ({stdout: '', stderr: ''});
|
|
11
|
+
|
|
12
|
+
mock.module('teen_process', {
|
|
13
|
+
namedExports: {
|
|
14
|
+
...teenProcess,
|
|
15
|
+
exec: (...args: any[]) => currentExec(...args),
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
let currentSetXctestrunFile: (...args: any[]) => any = async () => '/fake/WebDriverAgentRunner.xctestrun';
|
|
20
|
+
|
|
21
|
+
mock.module('../../lib/utils/index.js', {
|
|
22
|
+
namedExports: {
|
|
23
|
+
...utilsIndex,
|
|
24
|
+
setXctestrunFile: (...args: any[]) => currentSetXctestrunFile(...args),
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const {XcodeBuild} = await import('../../lib/xcodebuild.js');
|
|
29
|
+
|
|
30
|
+
const SHOWDESTINATIONS_OUTPUT = `
|
|
31
|
+
\tDestinations compatible with the "WebDriverAgentRunner" scheme:
|
|
32
|
+
\t\t{ platform:iOS, id:00008030-000A49391460202E, name:iPad von Galyna }
|
|
33
|
+
\t\t{ platform:iOS Simulator, id:BB720847-B182-40BD-BB5A-338951D32ADC, OS:27.0, name:iPad (A16) }
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
function makeXcodeBuild(udid: string, realDevice: boolean): InstanceType<typeof XcodeBuild> {
|
|
37
|
+
const args: XcodeBuildArgs = {
|
|
38
|
+
realDevice,
|
|
39
|
+
agentPath: '/fake/WebDriverAgent.xcodeproj',
|
|
40
|
+
bootstrapPath: '/fake',
|
|
41
|
+
};
|
|
42
|
+
return new XcodeBuild({udid}, args);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('XcodeBuild real-device udid case resolution', function () {
|
|
46
|
+
beforeEach(function () {
|
|
47
|
+
currentExec = async () => ({stdout: SHOWDESTINATIONS_OUTPUT, stderr: ''});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('resolves to the canonical case xcodebuild reports', async function () {
|
|
51
|
+
const xcodebuild = makeXcodeBuild('00008030-000a49391460202e', true);
|
|
52
|
+
const resolved = await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
53
|
+
assert.strictEqual(resolved, '00008030-000A49391460202E');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('falls back to the given udid when no destination matches', async function () {
|
|
57
|
+
const xcodebuild = makeXcodeBuild('unknown-udid', true);
|
|
58
|
+
const resolved = await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
59
|
+
assert.strictEqual(resolved, 'unknown-udid');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("falls back to the given udid when 'xcodebuild -showdestinations' fails", async function () {
|
|
63
|
+
currentExec = async () => {
|
|
64
|
+
throw new Error('boom');
|
|
65
|
+
};
|
|
66
|
+
const xcodebuild = makeXcodeBuild('some-udid', true);
|
|
67
|
+
const resolved = await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
68
|
+
assert.strictEqual(resolved, 'some-udid');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('is a no-op for simulators, whose udid is already canonical', async function () {
|
|
72
|
+
let execCalled = false;
|
|
73
|
+
currentExec = async () => {
|
|
74
|
+
execCalled = true;
|
|
75
|
+
return {stdout: '', stderr: ''};
|
|
76
|
+
};
|
|
77
|
+
const xcodebuild = makeXcodeBuild('sim-udid', false);
|
|
78
|
+
const resolved = await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
79
|
+
assert.strictEqual(execCalled, false);
|
|
80
|
+
assert.strictEqual(resolved, 'sim-udid');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("only shells out to 'xcodebuild -showdestinations' once even if resolution is triggered multiple times", async function () {
|
|
84
|
+
let execCallCount = 0;
|
|
85
|
+
currentExec = async () => {
|
|
86
|
+
execCallCount++;
|
|
87
|
+
return {stdout: SHOWDESTINATIONS_OUTPUT, stderr: ''};
|
|
88
|
+
};
|
|
89
|
+
const xcodebuild = makeXcodeBuild('00008030-000a49391460202e', true);
|
|
90
|
+
await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
91
|
+
await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
92
|
+
assert.strictEqual(execCallCount, 1);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('lets truly concurrent callers await the same in-flight resolution instead of racing ahead', async function () {
|
|
96
|
+
let execCallCount = 0;
|
|
97
|
+
let releaseExec: () => void = () => {};
|
|
98
|
+
const execGate = new Promise<void>((resolve) => {
|
|
99
|
+
releaseExec = resolve;
|
|
100
|
+
});
|
|
101
|
+
currentExec = async () => {
|
|
102
|
+
execCallCount++;
|
|
103
|
+
await execGate;
|
|
104
|
+
return {stdout: SHOWDESTINATIONS_OUTPUT, stderr: ''};
|
|
105
|
+
};
|
|
106
|
+
const xcodebuild = makeXcodeBuild('00008030-000a49391460202e', true);
|
|
107
|
+
|
|
108
|
+
// Both calls start before the (gated) exec() resolves — a naive "already started" boolean
|
|
109
|
+
// would let the second one return immediately with a value that isn't resolved yet.
|
|
110
|
+
const first = (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
111
|
+
const second = (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
112
|
+
releaseExec();
|
|
113
|
+
const [firstResolved, secondResolved] = await Promise.all([first, second]);
|
|
114
|
+
|
|
115
|
+
assert.strictEqual(execCallCount, 1);
|
|
116
|
+
assert.strictEqual(firstResolved, '00008030-000A49391460202E');
|
|
117
|
+
assert.strictEqual(secondResolved, '00008030-000A49391460202E');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("builds the '-destination id=' argument from the resolved udid", async function () {
|
|
121
|
+
const xcodebuild = makeXcodeBuild('00008030-000a49391460202e', true);
|
|
122
|
+
const resolved = await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
123
|
+
const {args} = (xcodebuild as any).getCommand(false, resolved);
|
|
124
|
+
assert.ok(args.includes('id=00008030-000A49391460202E'));
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("bounds 'xcodebuild -showdestinations' with a timeout", async function () {
|
|
128
|
+
let capturedOpts: any;
|
|
129
|
+
currentExec = async (_cmd: string, _args: string[], opts: any) => {
|
|
130
|
+
capturedOpts = opts;
|
|
131
|
+
return {stdout: SHOWDESTINATIONS_OUTPUT, stderr: ''};
|
|
132
|
+
};
|
|
133
|
+
const xcodebuild = makeXcodeBuild('00008030-000a49391460202e', true);
|
|
134
|
+
await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
135
|
+
assert.ok(typeof capturedOpts?.timeout === 'number' && capturedOpts.timeout > 0);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('falls back to the given udid when resolution times out', async function () {
|
|
139
|
+
currentExec = async () => {
|
|
140
|
+
throw new Error("Command 'xcodebuild ...' timed out after 15000ms");
|
|
141
|
+
};
|
|
142
|
+
const xcodebuild = makeXcodeBuild('some-udid', true);
|
|
143
|
+
const resolved = await (xcodebuild as any).resolveXcodeDeviceUdid();
|
|
144
|
+
assert.strictEqual(resolved, 'some-udid');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("keeps the caller's udid casing for the .xctestrun file lookup, unaffected by resolution", async function () {
|
|
148
|
+
let capturedDeviceInfo: any;
|
|
149
|
+
currentSetXctestrunFile = async ({deviceInfo}: any) => {
|
|
150
|
+
capturedDeviceInfo = deviceInfo;
|
|
151
|
+
return '/fake/WebDriverAgentRunner.xctestrun';
|
|
152
|
+
};
|
|
153
|
+
const xcodebuild = new XcodeBuild(
|
|
154
|
+
{udid: '00008030-000a49391460202e'},
|
|
155
|
+
{
|
|
156
|
+
realDevice: true,
|
|
157
|
+
agentPath: '/fake/WebDriverAgent.xcodeproj',
|
|
158
|
+
bootstrapPath: '/fake',
|
|
159
|
+
useXctestrunFile: true,
|
|
160
|
+
},
|
|
161
|
+
);
|
|
162
|
+
await xcodebuild.init({} as any);
|
|
163
|
+
assert.strictEqual(capturedDeviceInfo.udid, '00008030-000a49391460202e');
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('XcodeBuild readiness after a previous process exits', function () {
|
|
168
|
+
function setup() {
|
|
169
|
+
const build = new XcodeBuild(
|
|
170
|
+
{udid: 'sim-udid'},
|
|
171
|
+
{
|
|
172
|
+
realDevice: false,
|
|
173
|
+
agentPath: '/fake',
|
|
174
|
+
bootstrapPath: '/fake',
|
|
175
|
+
prebuildDelay: 0,
|
|
176
|
+
},
|
|
177
|
+
);
|
|
178
|
+
const processes: EventEmitter[] = [];
|
|
179
|
+
let statusCalls = 0;
|
|
180
|
+
const status = {ready: true};
|
|
181
|
+
(build as any).noSessionProxy = {
|
|
182
|
+
timeout: 5000,
|
|
183
|
+
command: async () => {
|
|
184
|
+
statusCalls++;
|
|
185
|
+
return status;
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
(build as any).createSubProcess = async (buildOnly: boolean) => {
|
|
189
|
+
const process = new EventEmitter();
|
|
190
|
+
processes.push(process);
|
|
191
|
+
(process as any).start = async () => {
|
|
192
|
+
if (buildOnly) {
|
|
193
|
+
process.emit('exit', 0, null);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
return process;
|
|
197
|
+
};
|
|
198
|
+
return {build, processes, status, statusCalls: () => statusCalls};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
it('checks status after a successful prebuild', async function () {
|
|
202
|
+
const fixture = setup();
|
|
203
|
+
await fixture.build.prebuild();
|
|
204
|
+
assert.deepStrictEqual(await fixture.build.start(), fixture.status);
|
|
205
|
+
assert.strictEqual(fixture.statusCalls(), 1);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('checks status again when restarting the same instance', async function () {
|
|
209
|
+
const fixture = setup();
|
|
210
|
+
await fixture.build.start();
|
|
211
|
+
fixture.processes[0].emit('exit', 0, null);
|
|
212
|
+
assert.deepStrictEqual(await fixture.build.start(), fixture.status);
|
|
213
|
+
assert.strictEqual(fixture.statusCalls(), 2);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('does not let an old process exit mark the new process as exited', async function () {
|
|
217
|
+
const fixture = setup();
|
|
218
|
+
await fixture.build.start();
|
|
219
|
+
const create = (fixture.build as any).createSubProcess;
|
|
220
|
+
(fixture.build as any).createSubProcess = async (buildOnly: boolean) => {
|
|
221
|
+
const process = await create(buildOnly);
|
|
222
|
+
process.start = async () => {
|
|
223
|
+
fixture.processes[0].emit('exit', 0, null);
|
|
224
|
+
};
|
|
225
|
+
return process;
|
|
226
|
+
};
|
|
227
|
+
assert.deepStrictEqual(await fixture.build.start(), fixture.status);
|
|
228
|
+
assert.strictEqual(fixture.statusCalls(), 2);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
@@ -38,6 +38,16 @@ maestro-runner --platform ios --driver devicelab --team-id <TEAM_ID> \
|
|
|
38
38
|
Regenerate `SigningStub.xcodeproj` from `signing-stub/project.yml` with
|
|
39
39
|
`xcodegen generate`.
|
|
40
40
|
|
|
41
|
+
## Access
|
|
42
|
+
|
|
43
|
+
Each run starts the agent with a random token (`DL_AGENT_TOKEN`, through
|
|
44
|
+
`SIMCTL_CHILD_` or the xctestrun's environment) and sends it on every request
|
|
45
|
+
as `X-DeviceLab-Token`; an agent built with token support answers a request
|
|
46
|
+
without it 401 and runs nothing. The token is saved, readable by the user only,
|
|
47
|
+
in `~/.maestro-runner/cache/devicelab-ios-agent/<udid>/agent.json` so a later
|
|
48
|
+
run can re-attach to a kept agent. The agent listens on 127.0.0.1 only: on a
|
|
49
|
+
simulator that is the Mac, on a device the end of the usbmux forward.
|
|
50
|
+
|
|
41
51
|
Overrides:
|
|
42
52
|
|
|
43
53
|
- `DEVICELAB_IOS_AGENT_DIR` — use an agent build from another directory
|
|
@@ -49,3 +59,5 @@ Overrides:
|
|
|
49
59
|
- `DEVICELAB_IOS_AGENT_BUNDLE_ID` — sign the agent on a device as another
|
|
50
60
|
bundle id (a personal team cannot use the team wildcard App ID, and
|
|
51
61
|
`dev.devicelab.agent` may already be registered elsewhere)
|
|
62
|
+
- `DEVICELAB_IOS_AGENT_BIND=any` — on a device, have the agent listen on every
|
|
63
|
+
interface instead of loopback (the token is still required)
|
|
Binary file
|
|
Binary file
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "ff2be7b",
|
|
3
3
|
"protocol": "1.0",
|
|
4
4
|
"xcode": "Xcode 27.0",
|
|
5
5
|
"runnerBundleId": "dev.devicelab.agent.uitests.xctrunner",
|
|
6
6
|
"hostBundleId": "dev.devicelab.agent",
|
|
7
7
|
"files": {
|
|
8
8
|
"agent.xctestrun": "93df94d1ffdc3f93a8cbe7d9b453096bde1436e8ed7cafd88436dfbc210d3f98",
|
|
9
|
-
"DevicelabIOSAgent.app/DevicelabIOSAgent": "
|
|
9
|
+
"DevicelabIOSAgent.app/DevicelabIOSAgent": "98a49ac56496fd30dfec399c6c20b6070f478ee7b3e2f84ad0df7ebab4574864",
|
|
10
10
|
"DevicelabIOSAgent.app/Info.plist": "cba8d7ca7542f6c6a0bf195b957a692fa5a924f0c4ef3c547edd5100399b8b7c",
|
|
11
11
|
"DevicelabIOSAgent.app/PkgInfo": "82502191c9484b04d685374f9879a0066069c49b8acae7a04b01d38d07e8eca0",
|
|
12
12
|
"DevicelabIOSAgentUITests-Runner.app/DevicelabIOSAgentUITests-Runner": "26d1a9837de9735a1c9dcaef554144297f03d6291c8421aa04d6e8f6c9bc5833",
|
|
13
13
|
"DevicelabIOSAgentUITests-Runner.app/Info.plist": "ffc0b193115180aa4af30f183fe4bf67eb821c79c763f363fdd7b41e82262498",
|
|
14
14
|
"DevicelabIOSAgentUITests-Runner.app/PkgInfo": "82502191c9484b04d685374f9879a0066069c49b8acae7a04b01d38d07e8eca0",
|
|
15
|
-
"DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/DevicelabIOSAgentUITests": "
|
|
15
|
+
"DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/DevicelabIOSAgentUITests": "9a33ba998859cacc4c34d7fda9393aea445ec6f9c60d0dddc055ed35e767153c",
|
|
16
16
|
"DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/Info.plist": "82c7c5c76ae134228a1cbc5235630dc5a63964bf5d3721b660790b08bec534f7"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
Binary file
|
|
Binary file
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "ff2be7b",
|
|
3
3
|
"protocol": "1.0",
|
|
4
4
|
"xcode": "Xcode 27.0",
|
|
5
5
|
"runnerBundleId": "dev.devicelab.agent.uitests.xctrunner",
|
|
6
6
|
"hostBundleId": "dev.devicelab.agent",
|
|
7
7
|
"files": {
|
|
8
8
|
"agent.xctestrun": "45b704ea6a432fef69461223a1de91e381743cb9413e082db7f2966283beea75",
|
|
9
|
-
"DevicelabIOSAgent.app/DevicelabIOSAgent": "
|
|
9
|
+
"DevicelabIOSAgent.app/DevicelabIOSAgent": "6b660b46764d4052dd1fb7323b7dece22c9febdeb530d1149613f3eba2d5ec36",
|
|
10
10
|
"DevicelabIOSAgent.app/Info.plist": "1de91d903f985c153b06d9ce6d2086812e2d8f49e657b17f6e58f4a8733af93e",
|
|
11
11
|
"DevicelabIOSAgent.app/PkgInfo": "82502191c9484b04d685374f9879a0066069c49b8acae7a04b01d38d07e8eca0",
|
|
12
12
|
"DevicelabIOSAgentUITests-Runner.app/DevicelabIOSAgentUITests-Runner": "d776d95c3da519cf802b9e58794802128cd158160db68471c703005522b37337",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
"DevicelabIOSAgentUITests-Runner.app/Frameworks/XCUnit.framework/XCUnit": "ca2ce84e479758c3f2ab3c95964de49938d917b3ed3fa3d98038a6c4ef5ddc33",
|
|
157
157
|
"DevicelabIOSAgentUITests-Runner.app/Info.plist": "db45280229a22ebbda188c44e0b97d8ba049d65c2373a1b11b4c5b61525014a0",
|
|
158
158
|
"DevicelabIOSAgentUITests-Runner.app/PkgInfo": "82502191c9484b04d685374f9879a0066069c49b8acae7a04b01d38d07e8eca0",
|
|
159
|
-
"DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/DevicelabIOSAgentUITests": "
|
|
159
|
+
"DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/DevicelabIOSAgentUITests": "ad228f590c4ed2713fe457128979ec023c933bd9d65dff7c926a129f46930a10",
|
|
160
160
|
"DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/Info.plist": "b4b1ff08ff01133dd8e3664807675a48476c073d5eba8dee0afa29f0c1bf46d5"
|
|
161
161
|
}
|
|
162
162
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devicelab/maestro-runner-darwin-arm64",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.30",
|
|
4
4
|
"description": "maestro-runner binary for darwin arm64. Installed automatically as an optional dependency of maestro-runner.",
|
|
5
5
|
"homepage": "https://open.devicelab.dev/maestro-runner",
|
|
6
6
|
"repository": {
|