doc-detective 4.21.0 → 4.22.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/dist/common/src/schemas/schemas.json +264 -264
- package/dist/common/src/types/generated/config_v3.d.ts +4 -4
- package/dist/common/src/types/generated/context_v3.d.ts +4 -4
- package/dist/common/src/types/generated/report_v3.d.ts +4 -4
- package/dist/common/src/types/generated/resolvedTests_v3.d.ts +8 -8
- package/dist/common/src/types/generated/spec_v3.d.ts +4 -4
- package/dist/common/src/types/generated/startSurface_v3.d.ts +7 -7
- package/dist/common/src/types/generated/step_v3.d.ts +7 -7
- package/dist/common/src/types/generated/test_v3.d.ts +18 -18
- package/dist/core/tests/androidEmulator.d.ts +2 -12
- package/dist/core/tests/androidEmulator.d.ts.map +1 -1
- package/dist/core/tests/androidEmulator.js +5 -17
- package/dist/core/tests/androidEmulator.js.map +1 -1
- package/dist/core/tests/appSurface.d.ts +35 -1
- package/dist/core/tests/appSurface.d.ts.map +1 -1
- package/dist/core/tests/appSurface.js +162 -20
- package/dist/core/tests/appSurface.js.map +1 -1
- package/dist/core/tests/iosSimulator.d.ts +89 -0
- package/dist/core/tests/iosSimulator.d.ts.map +1 -0
- package/dist/core/tests/iosSimulator.js +453 -0
- package/dist/core/tests/iosSimulator.js.map +1 -0
- package/dist/core/tests/mobileDevice.d.ts +15 -0
- package/dist/core/tests/mobileDevice.d.ts.map +1 -0
- package/dist/core/tests/mobileDevice.js +24 -0
- package/dist/core/tests/mobileDevice.js.map +1 -0
- package/dist/core/tests/mobilePlatform.d.ts +1 -2
- package/dist/core/tests/mobilePlatform.d.ts.map +1 -1
- package/dist/core/tests/mobilePlatform.js +15 -14
- package/dist/core/tests/mobilePlatform.js.map +1 -1
- package/dist/core/tests.d.ts.map +1 -1
- package/dist/core/tests.js +152 -45
- package/dist/core/tests.js.map +1 -1
- package/dist/index.cjs +845 -331
- package/dist/runtime/heavyDeps.d.ts +1 -1
- package/dist/runtime/heavyDeps.d.ts.map +1 -1
- package/dist/runtime/heavyDeps.js +1 -0
- package/dist/runtime/heavyDeps.js.map +1 -1
- package/dist/runtime/installCommand.d.ts +1 -1
- package/dist/runtime/installCommand.d.ts.map +1 -1
- package/dist/runtime/installCommand.js +21 -4
- package/dist/runtime/installCommand.js.map +1 -1
- package/dist/runtime/iosInstaller.d.ts +23 -0
- package/dist/runtime/iosInstaller.d.ts.map +1 -0
- package/dist/runtime/iosInstaller.js +104 -0
- package/dist/runtime/iosInstaller.js.map +1 -0
- package/package.json +2 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Native app surfaces phase A3: the `android`/`ios` target platforms. Unlike
|
|
2
2
|
// desktop platforms (where host == target), a mobile platform names the
|
|
3
3
|
// TARGET a context runs against and is gated by host *capability*, not host
|
|
4
|
-
// identity. As of
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// identity. As of A4, native app contexts can pass on both mobile targets
|
|
5
|
+
// when the host is capable. The remaining mobile-target skip reason this
|
|
6
|
+
// module composes is mobile browser testing (A5), which is still gated on both
|
|
7
|
+
// android and ios. The reason composer is pure so it's unit-testable without
|
|
8
|
+
// probing an SDK.
|
|
9
9
|
export { isMobileTargetPlatform, mobileContextSkipReason };
|
|
10
10
|
// Classify a context platform as a mobile target, or null for desktop / junk.
|
|
11
11
|
function isMobileTargetPlatform(platform) {
|
|
@@ -13,18 +13,19 @@ function isMobileTargetPlatform(platform) {
|
|
|
13
13
|
return platform;
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
|
-
// Compose the SKIP reason (and log level) for the mobile-context
|
|
17
|
-
// gated by a
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
|
|
16
|
+
// Compose the SKIP reason (and log level) for the one mobile-context case still
|
|
17
|
+
// gated by a later phase: a mobile-web (browser) step on either target — mobile
|
|
18
|
+
// browsers land in A5. Native app contexts (no browser step) are NOT routed
|
|
19
|
+
// here; they pass through their platform's context preflight (androidContext-
|
|
20
|
+
// Preflight / iosContextPreflight), which capability-gates and runs them. This
|
|
21
|
+
// composer is only ever called for a mobile-browser context, so it branches on
|
|
22
|
+
// the target platform alone.
|
|
23
|
+
function mobileContextSkipReason({ platform, }) {
|
|
23
24
|
const roadmap = "docs/design/native-app-surfaces.md";
|
|
24
25
|
if (platform === "ios") {
|
|
25
26
|
return {
|
|
26
|
-
level: "
|
|
27
|
-
reason: `Skipping context on 'ios':
|
|
27
|
+
level: "warning",
|
|
28
|
+
reason: `Skipping context on 'ios': mobile browser testing on iOS lands in phase A5 of the native app roadmap (${roadmap}). Native iOS app tests run on capable macOS hosts.`,
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
// android + a browser step: mobile-web testing on Android is phase A5.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobilePlatform.js","sourceRoot":"","sources":["../../../src/core/tests/mobilePlatform.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,
|
|
1
|
+
{"version":3,"file":"mobilePlatform.js","sourceRoot":"","sources":["../../../src/core/tests/mobilePlatform.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,0EAA0E;AAC1E,yEAAyE;AACzE,+EAA+E;AAC/E,6EAA6E;AAC7E,kBAAkB;AAElB,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,CAAC;AAI3D,8EAA8E;AAC9E,SAAS,sBAAsB,CAAC,QAAiB;IAC/C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK;QAAE,OAAO,QAAQ,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,6BAA6B;AAC7B,SAAS,uBAAuB,CAAC,EAC/B,QAAQ,GAGT;IACC,MAAM,OAAO,GAAG,oCAAoC,CAAC;IACrD,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACvB,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,MAAM,EAAE,yGAAyG,OAAO,qDAAqD;SAC9K,CAAC;IACJ,CAAC;IACD,uEAAuE;IACvE,OAAO;QACL,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,iHAAiH,OAAO,2DAA2D;KAC5L,CAAC;AACJ,CAAC"}
|
package/dist/core/tests.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tests.d.ts","sourceRoot":"","sources":["../../src/core/tests.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAoDhC,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"tests.d.ts","sourceRoot":"","sources":["../../src/core/tests.ts"],"names":[],"mappings":"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"}
|
package/dist/core/tests.js
CHANGED
|
@@ -38,6 +38,7 @@ import { isMobileTargetPlatform, mobileContextSkipReason, } from "./tests/mobile
|
|
|
38
38
|
import { detectAndroidSdk } from "../runtime/androidSdk.js";
|
|
39
39
|
import { hostAbi, listInstalledSystemImages, installAndroid, } from "../runtime/androidInstaller.js";
|
|
40
40
|
import { buildAcquireDeviceDeps, checkEmulatorAcceleration, hostHasKvm, planDeviceAcquisition, planAndroidToolchain, normalizeDeviceDescriptor, acquireDevice, createDeviceRegistry, teardownDeviceRegistry, } from "./tests/androidEmulator.js";
|
|
41
|
+
import { buildAcquireSimulatorDeps, planSimulatorAcquisition, acquireSimulator, createSimulatorRegistry, teardownSimulatorRegistry, } from "./tests/iosSimulator.js";
|
|
41
42
|
import { runBrowserScript } from "./tests/runBrowserScript.js";
|
|
42
43
|
import { dragAndDropElement } from "./tests/dragAndDrop.js";
|
|
43
44
|
import { createSessionRegistry, registerSession, activeDriver, sweepSessions, } from "./tests/browserSessions.js";
|
|
@@ -409,7 +410,6 @@ async function androidContextPreflight({ config, context, clog, }) {
|
|
|
409
410
|
if (hasBrowserStep) {
|
|
410
411
|
const { level, reason } = mobileContextSkipReason({
|
|
411
412
|
platform: "android",
|
|
412
|
-
hasBrowserStep,
|
|
413
413
|
});
|
|
414
414
|
return { ok: false, level, reason };
|
|
415
415
|
}
|
|
@@ -569,6 +569,62 @@ async function androidContextPreflight({ config, context, clog, }) {
|
|
|
569
569
|
}
|
|
570
570
|
/* c8 ignore stop */
|
|
571
571
|
}
|
|
572
|
+
// iOS context preflight (native app phase A4): mobile-browser contexts are
|
|
573
|
+
// still gated to A5; native app contexts probe host capability/toolchain via
|
|
574
|
+
// appSurfacePreflight, then validate that the context's default simulator can
|
|
575
|
+
// be resolved (booted/created) via simctl. On success return the appium
|
|
576
|
+
// entry/home plus the injected simctl effect bundle for the run's
|
|
577
|
+
// acquireSimulator closure.
|
|
578
|
+
async function iosContextPreflight({ config, context, }) {
|
|
579
|
+
const hasBrowserStep = isBrowserRequired({ test: context });
|
|
580
|
+
if (hasBrowserStep) {
|
|
581
|
+
const { level, reason } = mobileContextSkipReason({
|
|
582
|
+
platform: "ios",
|
|
583
|
+
});
|
|
584
|
+
return { ok: false, level, reason };
|
|
585
|
+
}
|
|
586
|
+
const pre = await appSurfacePreflight({ config, platform: "ios" });
|
|
587
|
+
if (!pre.ok)
|
|
588
|
+
return { ok: false, level: "info", reason: pre.reason };
|
|
589
|
+
/* c8 ignore start */
|
|
590
|
+
// The ok path only runs on a capable macOS host (appSurfacePreflight's
|
|
591
|
+
// probeIosToolchain passed), so the simctl probes below are macOS-only and
|
|
592
|
+
// never execute in the cross-platform unit suite.
|
|
593
|
+
const simulatorDeps = buildAcquireSimulatorDeps((m) => log(config, "debug", m));
|
|
594
|
+
try {
|
|
595
|
+
const desc = normalizeDeviceDescriptor({
|
|
596
|
+
contextDevice: context.device,
|
|
597
|
+
platform: "ios",
|
|
598
|
+
});
|
|
599
|
+
const [devices, runtimes, deviceTypes] = await Promise.all([
|
|
600
|
+
simulatorDeps.listDevices(),
|
|
601
|
+
simulatorDeps.listRuntimes(),
|
|
602
|
+
simulatorDeps.listDeviceTypes(),
|
|
603
|
+
]);
|
|
604
|
+
const plan = planSimulatorAcquisition(desc, {
|
|
605
|
+
devices,
|
|
606
|
+
runtimes,
|
|
607
|
+
deviceTypes,
|
|
608
|
+
});
|
|
609
|
+
if (plan.action === "skip") {
|
|
610
|
+
return { ok: false, level: "info", reason: plan.reason };
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
catch (error) {
|
|
614
|
+
return {
|
|
615
|
+
ok: false,
|
|
616
|
+
level: "info",
|
|
617
|
+
reason: `Skipping context on 'ios': couldn't probe the iOS simulator environment (${error?.message ?? error}). Check Xcode / simctl, or run \`doc-detective install ios --yes\`.`,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
return {
|
|
621
|
+
ok: true,
|
|
622
|
+
appiumEntry: pre.appiumEntry,
|
|
623
|
+
appiumHome: pre.appiumHome,
|
|
624
|
+
simulatorDeps,
|
|
625
|
+
};
|
|
626
|
+
/* c8 ignore stop */
|
|
627
|
+
}
|
|
572
628
|
function getDefaultBrowser({ runnerDetails }) {
|
|
573
629
|
let browser = {};
|
|
574
630
|
const browserNames = ["firefox", "chrome", "safari"];
|
|
@@ -1245,6 +1301,11 @@ async function runSpecs({ resolvedTests }) {
|
|
|
1245
1301
|
// wanting the same device converge on one boot. Swept in the `finally` below —
|
|
1246
1302
|
// only devices Doc Detective booted are killed (launch-ownership).
|
|
1247
1303
|
const deviceRegistry = createDeviceRegistry();
|
|
1304
|
+
// Run-level simulator registry (native app phase A4): booted/created iOS
|
|
1305
|
+
// simulators keyed by resolved name, the simctl analogue of deviceRegistry.
|
|
1306
|
+
// Swept in the `finally` below — only simulators Doc Detective booted are
|
|
1307
|
+
// shut down (launch-ownership).
|
|
1308
|
+
const simulatorRegistry = createSimulatorRegistry();
|
|
1248
1309
|
// Kill every still-registered background process (and its child tree) and
|
|
1249
1310
|
// remove any deferred temp scripts. Awaits the kills so the process tree is
|
|
1250
1311
|
// actually gone before the run returns. Idempotent: closeSurface already
|
|
@@ -1344,6 +1405,7 @@ async function runSpecs({ resolvedTests }) {
|
|
|
1344
1405
|
warmUpResults,
|
|
1345
1406
|
processRegistry,
|
|
1346
1407
|
deviceRegistry,
|
|
1408
|
+
simulatorRegistry,
|
|
1347
1409
|
logPrefix: limit > 1 ? `[${job.test.testId}/${job.context.contextId}]` : "",
|
|
1348
1410
|
});
|
|
1349
1411
|
}
|
|
@@ -1430,6 +1492,7 @@ async function runSpecs({ resolvedTests }) {
|
|
|
1430
1492
|
warmUpResults,
|
|
1431
1493
|
processRegistry,
|
|
1432
1494
|
deviceRegistry,
|
|
1495
|
+
simulatorRegistry,
|
|
1433
1496
|
platform,
|
|
1434
1497
|
markAutoRecord,
|
|
1435
1498
|
limit,
|
|
@@ -1495,6 +1558,16 @@ async function runSpecs({ resolvedTests }) {
|
|
|
1495
1558
|
await killTree(entry.process?.pid);
|
|
1496
1559
|
});
|
|
1497
1560
|
}
|
|
1561
|
+
// Sweep the iOS simulator registry (native app phase A4): shut down only the
|
|
1562
|
+
// simulators Doc Detective booted (bootedByUs), leaving pre-existing booted
|
|
1563
|
+
// ones running. `simctl shutdown` via the injected effect bundle.
|
|
1564
|
+
if (simulatorRegistry.size > 0) {
|
|
1565
|
+
const simDeps = buildAcquireSimulatorDeps();
|
|
1566
|
+
await teardownSimulatorRegistry(simulatorRegistry, async (entry) => {
|
|
1567
|
+
log(config, "debug", `Shutting down simulator "${entry.name}" (${entry.udid}).`);
|
|
1568
|
+
await simDeps.shutdown(entry);
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1498
1571
|
/* c8 ignore stop */
|
|
1499
1572
|
process.off("SIGINT", onSignal);
|
|
1500
1573
|
process.off("SIGTERM", onSignal);
|
|
@@ -1560,7 +1633,7 @@ async function runSpecs({ resolvedTests }) {
|
|
|
1560
1633
|
* NEVER touches the summary — Phase-3 in runSpecs remains the sole tally site;
|
|
1561
1634
|
* here we only push reports.
|
|
1562
1635
|
*/
|
|
1563
|
-
async function runRoutedSpec({ spec, specReport, specGuardSkip, config, runnerDetails, appiumPool, portToDisplay, metaValues, installAttempts, warmUpResults, processRegistry, deviceRegistry, platform, markAutoRecord, limit, resourceRegistry, exclusivityCtx, }) {
|
|
1636
|
+
async function runRoutedSpec({ spec, specReport, specGuardSkip, config, runnerDetails, appiumPool, portToDisplay, metaValues, installAttempts, warmUpResults, processRegistry, deviceRegistry, simulatorRegistry, platform, markAutoRecord, limit, resourceRegistry, exclusivityCtx, }) {
|
|
1564
1637
|
// Set once a `stop:spec` (or deferred `stop:run`) decision halts the spec; the
|
|
1565
1638
|
// remaining tests are recorded SKIPPED with the stop reason and not executed.
|
|
1566
1639
|
let stopRest = false;
|
|
@@ -1723,6 +1796,7 @@ async function runRoutedSpec({ spec, specReport, specGuardSkip, config, runnerDe
|
|
|
1723
1796
|
warmUpResults,
|
|
1724
1797
|
processRegistry,
|
|
1725
1798
|
deviceRegistry,
|
|
1799
|
+
simulatorRegistry,
|
|
1726
1800
|
logPrefix: limit > 1 ? `[${job.test.testId}/${job.context.contextId}]` : "",
|
|
1727
1801
|
});
|
|
1728
1802
|
}
|
|
@@ -2288,7 +2362,7 @@ async function captureAutoScreenshot({ config, driver, spec, test, context, step
|
|
|
2288
2362
|
* report or summary counters — the caller owns aggregation, which keeps this
|
|
2289
2363
|
* function safe to run concurrently with sibling contexts.
|
|
2290
2364
|
*/
|
|
2291
|
-
async function runContext({ config, spec, test, context, runnerDetails, appiumPool, portToDisplay, metaValues, installAttempts, warmUpResults, processRegistry, deviceRegistry, logPrefix = "", }) {
|
|
2365
|
+
async function runContext({ config, spec, test, context, runnerDetails, appiumPool, portToDisplay, metaValues, installAttempts, warmUpResults, processRegistry, deviceRegistry, simulatorRegistry, logPrefix = "", }) {
|
|
2292
2366
|
const platform = runnerDetails.environment.platform;
|
|
2293
2367
|
// `let`, not `const`: an on-demand browser install below re-detects available
|
|
2294
2368
|
// apps and reassigns this snapshot.
|
|
@@ -2354,45 +2428,59 @@ async function runContext({ config, spec, test, context, runnerDetails, appiumPo
|
|
|
2354
2428
|
contextReport.resultDescription = requirementsSkip;
|
|
2355
2429
|
return contextReport;
|
|
2356
2430
|
}
|
|
2357
|
-
if (mobileTarget === "
|
|
2358
|
-
//
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2431
|
+
if (mobileTarget === "android") {
|
|
2432
|
+
// Android (phase A3b): full preflight. SDK detection is lazy (probed
|
|
2433
|
+
// only here, only for android contexts), so a run that never targets
|
|
2434
|
+
// android pays nothing. On skip, land SKIPPED with the actionable reason;
|
|
2435
|
+
// on ok, prime the app session with the device layer and FALL THROUGH to
|
|
2436
|
+
// run the steps.
|
|
2437
|
+
const pre = await androidContextPreflight({ config, context, clog });
|
|
2438
|
+
if (!pre.ok) {
|
|
2439
|
+
clog(pre.level, pre.reason);
|
|
2440
|
+
contextReport.result = "SKIPPED";
|
|
2441
|
+
contextReport.resultDescription = pre.reason;
|
|
2442
|
+
return contextReport;
|
|
2443
|
+
}
|
|
2444
|
+
/* c8 ignore start */
|
|
2445
|
+
// The ok path only runs on a host with a real SDK + emulator (CI legs).
|
|
2446
|
+
appSession = createAppSessionState();
|
|
2447
|
+
appSession.appiumEntry = pre.appiumEntry;
|
|
2448
|
+
appSession.appiumHome = pre.appiumHome;
|
|
2449
|
+
appSession.defaultDevice = context.device;
|
|
2450
|
+
appSession.androidSdkRoot = pre.sdkRoot;
|
|
2451
|
+
appSession.androidDeviceRegistry = deviceRegistry;
|
|
2452
|
+
appSession.androidDeviceDeps = pre.deviceDeps;
|
|
2453
|
+
// resolved device (name) joins the context report the way resolved
|
|
2454
|
+
// browser versions do; the concrete udid is known once a surface boots
|
|
2455
|
+
// it.
|
|
2456
|
+
contextReport.device = context.device ?? { platform: "android" };
|
|
2457
|
+
// Surface any preflight warnings (e.g. a lazy toolchain install) in the
|
|
2458
|
+
// output report — not just the terminal — so a run that quietly
|
|
2459
|
+
// downloaded the multi-GB SDK is auditable after the fact.
|
|
2460
|
+
if (pre.warnings.length)
|
|
2461
|
+
contextReport.warnings = pre.warnings;
|
|
2462
|
+
/* c8 ignore stop */
|
|
2364
2463
|
}
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2464
|
+
else {
|
|
2465
|
+
const pre = await iosContextPreflight({ config, context });
|
|
2466
|
+
if (!pre.ok) {
|
|
2467
|
+
clog(pre.level, pre.reason);
|
|
2468
|
+
contextReport.result = "SKIPPED";
|
|
2469
|
+
contextReport.resultDescription = pre.reason;
|
|
2470
|
+
return contextReport;
|
|
2471
|
+
}
|
|
2472
|
+
/* c8 ignore start */
|
|
2473
|
+
// The ok path only runs on a capable macOS host (CI fixture legs): prime
|
|
2474
|
+
// the app session with the simulator layer and FALL THROUGH to run steps.
|
|
2475
|
+
appSession = createAppSessionState();
|
|
2476
|
+
appSession.appiumEntry = pre.appiumEntry;
|
|
2477
|
+
appSession.appiumHome = pre.appiumHome;
|
|
2478
|
+
appSession.defaultDevice = context.device;
|
|
2479
|
+
appSession.iosSimulatorRegistry = simulatorRegistry;
|
|
2480
|
+
appSession.iosSimulatorDeps = pre.simulatorDeps;
|
|
2481
|
+
contextReport.device = context.device ?? { platform: "ios" };
|
|
2482
|
+
/* c8 ignore stop */
|
|
2377
2483
|
}
|
|
2378
|
-
/* c8 ignore start */
|
|
2379
|
-
// The ok path only runs on a host with a real SDK + emulator (CI legs).
|
|
2380
|
-
appSession = createAppSessionState();
|
|
2381
|
-
appSession.appiumEntry = pre.appiumEntry;
|
|
2382
|
-
appSession.appiumHome = pre.appiumHome;
|
|
2383
|
-
appSession.defaultDevice = context.device;
|
|
2384
|
-
appSession.androidSdkRoot = pre.sdkRoot;
|
|
2385
|
-
appSession.androidDeviceRegistry = deviceRegistry;
|
|
2386
|
-
appSession.androidDeviceDeps = pre.deviceDeps;
|
|
2387
|
-
// resolved device (name) joins the context report the way resolved browser
|
|
2388
|
-
// versions do; the concrete udid is known once a surface boots it.
|
|
2389
|
-
contextReport.device = context.device ?? { platform: "android" };
|
|
2390
|
-
// Surface any preflight warnings (e.g. a lazy toolchain install) in the
|
|
2391
|
-
// output report — not just the terminal — so a run that quietly downloaded
|
|
2392
|
-
// the multi-GB SDK is auditable after the fact.
|
|
2393
|
-
if (pre.warnings.length)
|
|
2394
|
-
contextReport.warnings = pre.warnings;
|
|
2395
|
-
/* c8 ignore stop */
|
|
2396
2484
|
}
|
|
2397
2485
|
// `requires` capability gate: any unmet requirement skips the context with a
|
|
2398
2486
|
// message naming what's missing. Evaluated only on the platform the context
|
|
@@ -3442,9 +3530,12 @@ async function runStep({ config = {}, context = {}, step, driver, metaValues = {
|
|
|
3442
3530
|
return { port: server.port, process: server.process };
|
|
3443
3531
|
},
|
|
3444
3532
|
startDriver: (capabilities, port) => driverStart(capabilities, port, 2, { cacheDir: config?.cacheDir }),
|
|
3445
|
-
//
|
|
3446
|
-
//
|
|
3447
|
-
//
|
|
3533
|
+
// Mobile device acquisition (boot/create-and-boot, or reuse), bound
|
|
3534
|
+
// to the run-level registry stashed on the app session. Android uses
|
|
3535
|
+
// the emulator layer; iOS uses the simctl simulator layer. Both
|
|
3536
|
+
// return the same { entry:{name,udid} } | { skip } shape, so
|
|
3537
|
+
// startAppSurface's mobile branch stays uniform. Only set for a
|
|
3538
|
+
// mobile app session (which only exists on a capable host).
|
|
3448
3539
|
/* c8 ignore start */
|
|
3449
3540
|
acquireDevice: appSession?.androidDeviceDeps
|
|
3450
3541
|
? (desc) => acquireDevice({
|
|
@@ -3453,7 +3544,13 @@ async function runStep({ config = {}, context = {}, step, driver, metaValues = {
|
|
|
3453
3544
|
sdkRoot: appSession.androidSdkRoot,
|
|
3454
3545
|
deps: appSession.androidDeviceDeps,
|
|
3455
3546
|
})
|
|
3456
|
-
:
|
|
3547
|
+
: appSession?.iosSimulatorDeps
|
|
3548
|
+
? (desc) => acquireSimulator({
|
|
3549
|
+
desc,
|
|
3550
|
+
registry: appSession.iosSimulatorRegistry,
|
|
3551
|
+
deps: appSession.iosSimulatorDeps,
|
|
3552
|
+
})
|
|
3553
|
+
: undefined,
|
|
3457
3554
|
/* c8 ignore stop */
|
|
3458
3555
|
},
|
|
3459
3556
|
});
|
|
@@ -3611,6 +3708,16 @@ async function driverStart(capabilities, port, maxAttempts = 4, ctx = {}) {
|
|
|
3611
3708
|
// creation failure and propagates immediately.
|
|
3612
3709
|
const TRANSIENT = /ECONNREFUSED|ECONNRESET|socket hang up|could not proxy command|crashed during startup|cannot connect to|DevToolsActivePort|session not created/i;
|
|
3613
3710
|
const wdio = await loadHeavyDep("webdriverio", { ctx });
|
|
3711
|
+
// The wdio client aborts the POST /session request after connectionRetryTimeout.
|
|
3712
|
+
// A cold native session can take far longer to create than the 2-minute
|
|
3713
|
+
// default: the first XCUITest session builds WebDriverAgent via xcodebuild
|
|
3714
|
+
// (several minutes on a fresh macOS runner), and Mac2 builds WebDriverAgentMac
|
|
3715
|
+
// similarly. Derive the client timeout from whatever slow-startup ceiling the
|
|
3716
|
+
// capabilities declared (wdaLaunchTimeout / wdaConnectionTimeout /
|
|
3717
|
+
// serverStartupTimeout) so the client waits as long as the driver was told to,
|
|
3718
|
+
// never below the 2-minute floor. Browser/Windows/Android sessions carry none
|
|
3719
|
+
// of these caps and keep the 2-minute default unchanged.
|
|
3720
|
+
const startupCeiling = Math.max(120000, Number(capabilities?.["appium:wdaLaunchTimeout"]) || 0, Number(capabilities?.["appium:wdaConnectionTimeout"]) || 0, Number(capabilities?.["appium:serverStartupTimeout"]) || 0);
|
|
3614
3721
|
let lastError;
|
|
3615
3722
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
3616
3723
|
try {
|
|
@@ -3621,7 +3728,7 @@ async function driverStart(capabilities, port, maxAttempts = 4, ctx = {}) {
|
|
|
3621
3728
|
path: "/",
|
|
3622
3729
|
logLevel: "error",
|
|
3623
3730
|
capabilities,
|
|
3624
|
-
connectionRetryTimeout:
|
|
3731
|
+
connectionRetryTimeout: startupCeiling,
|
|
3625
3732
|
waitforTimeout: 120000, // 2 minutes
|
|
3626
3733
|
});
|
|
3627
3734
|
// Per-context mutable state. `recordings` lives here (not on config)
|