doc-detective 4.28.0 → 4.29.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/cli.js +13 -4
- package/dist/cli.js.map +1 -1
- package/dist/common/src/detectTests.d.ts +9 -0
- package/dist/common/src/detectTests.d.ts.map +1 -1
- package/dist/common/src/detectTests.js +22 -9
- package/dist/common/src/detectTests.js.map +1 -1
- package/dist/common/src/schemas/schemas.json +85 -1
- package/dist/common/src/types/generated/report_v3.d.ts +34 -0
- package/dist/common/src/types/generated/report_v3.d.ts.map +1 -1
- package/dist/core/detectTests.d.ts.map +1 -1
- package/dist/core/detectTests.js +37 -13
- package/dist/core/detectTests.js.map +1 -1
- package/dist/core/expressions.d.ts.map +1 -1
- package/dist/core/expressions.js +24 -1
- package/dist/core/expressions.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/resolveTests.js +23 -12
- package/dist/core/resolveTests.js.map +1 -1
- package/dist/core/telem.d.ts +2 -1
- package/dist/core/telem.d.ts.map +1 -1
- package/dist/core/telem.js +26 -2
- package/dist/core/telem.js.map +1 -1
- package/dist/core/tests/androidEmulator.d.ts.map +1 -1
- package/dist/core/tests/androidEmulator.js +13 -0
- package/dist/core/tests/androidEmulator.js.map +1 -1
- package/dist/core/tests/appSurface.d.ts +23 -0
- package/dist/core/tests/appSurface.d.ts.map +1 -1
- package/dist/core/tests/appSurface.js +3 -1
- package/dist/core/tests/appSurface.js.map +1 -1
- package/dist/core/tests/iosSimulator.d.ts.map +1 -1
- package/dist/core/tests/iosSimulator.js +13 -0
- package/dist/core/tests/iosSimulator.js.map +1 -1
- package/dist/core/tests/mobileBrowser.d.ts +1 -0
- package/dist/core/tests/mobileBrowser.d.ts.map +1 -1
- package/dist/core/tests/mobileBrowser.js +8 -0
- package/dist/core/tests/mobileBrowser.js.map +1 -1
- package/dist/core/tests.d.ts +83 -2
- package/dist/core/tests.d.ts.map +1 -1
- package/dist/core/tests.js +572 -70
- package/dist/core/tests.js.map +1 -1
- package/dist/core/utils.d.ts +3 -2
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/core/utils.js +37 -29
- package/dist/core/utils.js.map +1 -1
- package/dist/core/warmPhase.d.ts +161 -0
- package/dist/core/warmPhase.d.ts.map +1 -0
- package/dist/core/warmPhase.js +341 -0
- package/dist/core/warmPhase.js.map +1 -0
- package/dist/index.cjs +776 -90
- package/dist/utils.d.ts +2 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -3
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -383844,6 +383844,71 @@ var init_schemas = __esm({
|
|
|
383844
383844
|
}
|
|
383845
383845
|
]
|
|
383846
383846
|
}
|
|
383847
|
+
},
|
|
383848
|
+
warm: {
|
|
383849
|
+
type: "object",
|
|
383850
|
+
description: "Results of the run's inline warm phase \u2014 the always-on, best-effort provisioning pass (dependency installs, device boots, session probes) performed between test resolution and test execution. A failed task never gates the run; the per-context paths retry or skip with their normal semantics. Absent when the run ended before the phase (for example, when no specs matched). System-populated.",
|
|
383851
|
+
readOnly: true,
|
|
383852
|
+
additionalProperties: false,
|
|
383853
|
+
required: [
|
|
383854
|
+
"durationMs",
|
|
383855
|
+
"tasks"
|
|
383856
|
+
],
|
|
383857
|
+
properties: {
|
|
383858
|
+
durationMs: {
|
|
383859
|
+
type: "number",
|
|
383860
|
+
description: "Wall-clock duration of the warm phase in milliseconds. Tasks overlap, so this is less than the sum of the per-task durations."
|
|
383861
|
+
},
|
|
383862
|
+
tasks: {
|
|
383863
|
+
type: "array",
|
|
383864
|
+
description: "One entry per executed warm task.",
|
|
383865
|
+
items: {
|
|
383866
|
+
type: "object",
|
|
383867
|
+
additionalProperties: false,
|
|
383868
|
+
required: [
|
|
383869
|
+
"name",
|
|
383870
|
+
"kind",
|
|
383871
|
+
"outcome",
|
|
383872
|
+
"durationMs"
|
|
383873
|
+
],
|
|
383874
|
+
properties: {
|
|
383875
|
+
name: {
|
|
383876
|
+
type: "string",
|
|
383877
|
+
description: "Task identity, e.g. `browser-install:chrome` or `device-boot:android:<default>:<latest>`."
|
|
383878
|
+
},
|
|
383879
|
+
kind: {
|
|
383880
|
+
type: "string",
|
|
383881
|
+
enum: [
|
|
383882
|
+
"driver-install",
|
|
383883
|
+
"browser-install",
|
|
383884
|
+
"device-boot",
|
|
383885
|
+
"wda-check",
|
|
383886
|
+
"session-probe",
|
|
383887
|
+
"chromedriver-prefetch"
|
|
383888
|
+
],
|
|
383889
|
+
description: "What the task pre-pays: a native app driver install, a browser install, a simulator/emulator boot, the managed WebDriverAgent availability check, the concurrent-run driver session probe, or the android mobile-web chromedriver download."
|
|
383890
|
+
},
|
|
383891
|
+
outcome: {
|
|
383892
|
+
type: "string",
|
|
383893
|
+
enum: [
|
|
383894
|
+
"warmed",
|
|
383895
|
+
"skipped",
|
|
383896
|
+
"failed"
|
|
383897
|
+
],
|
|
383898
|
+
description: "`warmed` \u2014 the work was performed (for device boots, the boot was initiated); `skipped` \u2014 nothing to do or the environment isn't ready (the consuming context handles it as usual); `failed` \u2014 the attempt failed (logged as a warning; never fails the run)."
|
|
383899
|
+
},
|
|
383900
|
+
durationMs: {
|
|
383901
|
+
type: "number",
|
|
383902
|
+
description: "Wall-clock duration of this task in milliseconds."
|
|
383903
|
+
},
|
|
383904
|
+
note: {
|
|
383905
|
+
type: "string",
|
|
383906
|
+
description: "Human-readable detail about the outcome."
|
|
383907
|
+
}
|
|
383908
|
+
}
|
|
383909
|
+
}
|
|
383910
|
+
}
|
|
383911
|
+
}
|
|
383847
383912
|
}
|
|
383848
383913
|
},
|
|
383849
383914
|
required: [
|
|
@@ -383865,7 +383930,26 @@ var init_schemas = __esm({
|
|
|
383865
383930
|
}
|
|
383866
383931
|
]
|
|
383867
383932
|
}
|
|
383868
|
-
]
|
|
383933
|
+
],
|
|
383934
|
+
warm: {
|
|
383935
|
+
durationMs: 4211,
|
|
383936
|
+
tasks: [
|
|
383937
|
+
{
|
|
383938
|
+
name: "browser-install:chrome",
|
|
383939
|
+
kind: "browser-install",
|
|
383940
|
+
outcome: "skipped",
|
|
383941
|
+
durationMs: 2,
|
|
383942
|
+
note: "'chrome' is already available"
|
|
383943
|
+
},
|
|
383944
|
+
{
|
|
383945
|
+
name: "session-probe",
|
|
383946
|
+
kind: "session-probe",
|
|
383947
|
+
outcome: "warmed",
|
|
383948
|
+
durationMs: 4205,
|
|
383949
|
+
note: "1 combination ok"
|
|
383950
|
+
}
|
|
383951
|
+
]
|
|
383952
|
+
}
|
|
383869
383953
|
},
|
|
383870
383954
|
{
|
|
383871
383955
|
specs: [
|
|
@@ -633977,21 +634061,23 @@ async function loadEnvs(envsFile) {
|
|
|
633977
634061
|
return { status: "FAIL", description: "Invalid file." };
|
|
633978
634062
|
}
|
|
633979
634063
|
}
|
|
634064
|
+
function logLevelEnabled(config, level) {
|
|
634065
|
+
if (config.logLevel === "error" && level === "error")
|
|
634066
|
+
return true;
|
|
634067
|
+
if (config.logLevel === "warning" && (level === "error" || level === "warning"))
|
|
634068
|
+
return true;
|
|
634069
|
+
if (config.logLevel === "info" && (level === "error" || level === "warning" || level === "info"))
|
|
634070
|
+
return true;
|
|
634071
|
+
if (config.logLevel === "debug" && (level === "error" || level === "warning" || level === "info" || level === "debug"))
|
|
634072
|
+
return true;
|
|
634073
|
+
return false;
|
|
634074
|
+
}
|
|
633980
634075
|
async function log(config, level, message) {
|
|
633981
634076
|
if (message === void 0) {
|
|
633982
634077
|
message = config;
|
|
633983
634078
|
config = {};
|
|
633984
634079
|
}
|
|
633985
|
-
|
|
633986
|
-
if (config.logLevel === "error" && level === "error") {
|
|
633987
|
-
logLevelMatch = true;
|
|
633988
|
-
} else if (config.logLevel === "warning" && (level === "error" || level === "warning")) {
|
|
633989
|
-
logLevelMatch = true;
|
|
633990
|
-
} else if (config.logLevel === "info" && (level === "error" || level === "warning" || level === "info")) {
|
|
633991
|
-
logLevelMatch = true;
|
|
633992
|
-
} else if (config.logLevel === "debug" && (level === "error" || level === "warning" || level === "info" || level === "debug")) {
|
|
633993
|
-
logLevelMatch = true;
|
|
633994
|
-
}
|
|
634080
|
+
const logLevelMatch = logLevelEnabled(config, level);
|
|
633995
634081
|
if (logLevelMatch) {
|
|
633996
634082
|
if (typeof message === "string") {
|
|
633997
634083
|
let logMessage = `(${level.toUpperCase()}) ${message}`;
|
|
@@ -634076,8 +634162,7 @@ function replaceEnvs(stringOrObject) {
|
|
|
634076
634162
|
stringOrObject[key] = replaceEnvs(stringOrObject[key]);
|
|
634077
634163
|
});
|
|
634078
634164
|
} else if (typeof stringOrObject === "string") {
|
|
634079
|
-
const
|
|
634080
|
-
const matches = stringOrObject.match(variableRegex);
|
|
634165
|
+
const matches = stringOrObject.match(ENV_VAR_REGEX);
|
|
634081
634166
|
if (!matches)
|
|
634082
634167
|
return stringOrObject;
|
|
634083
634168
|
matches.forEach((match) => {
|
|
@@ -634321,7 +634406,7 @@ function llevenshteinDistance(s, t) {
|
|
|
634321
634406
|
}
|
|
634322
634407
|
return arr[t.length][s.length];
|
|
634323
634408
|
}
|
|
634324
|
-
var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, posixBashProbe;
|
|
634409
|
+
var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, ENV_VAR_REGEX, posixBashProbe;
|
|
634325
634410
|
var init_utils = __esm({
|
|
634326
634411
|
"dist/core/utils.js"() {
|
|
634327
634412
|
"use strict";
|
|
@@ -634363,6 +634448,7 @@ var init_utils = __esm({
|
|
|
634363
634448
|
maxBodyLength: 50 * 1024 * 1024,
|
|
634364
634449
|
maxRedirects: 5
|
|
634365
634450
|
};
|
|
634451
|
+
ENV_VAR_REGEX = /\$[a-zA-Z0-9_]+(?![a-zA-Z0-9_$])/g;
|
|
634366
634452
|
}
|
|
634367
634453
|
});
|
|
634368
634454
|
|
|
@@ -636496,17 +636582,24 @@ function detectFileTypeFromContent(content) {
|
|
|
636496
636582
|
}
|
|
636497
636583
|
|
|
636498
636584
|
// dist/common/src/detectTests.js
|
|
636585
|
+
var compiledRegExpCache = /* @__PURE__ */ new Map();
|
|
636499
636586
|
function safeRegExp(pattern, flags) {
|
|
636500
636587
|
if (typeof pattern !== "string" || pattern.length === 0)
|
|
636501
636588
|
return null;
|
|
636502
636589
|
if (pattern.length > 1500)
|
|
636503
636590
|
return null;
|
|
636504
|
-
const
|
|
636591
|
+
const cacheKey = pattern + " " + flags;
|
|
636592
|
+
const cached = compiledRegExpCache.get(cacheKey);
|
|
636593
|
+
if (cached !== void 0)
|
|
636594
|
+
return cached;
|
|
636595
|
+
let compiled;
|
|
636505
636596
|
try {
|
|
636506
|
-
|
|
636597
|
+
compiled = new RegExp(pattern, flags);
|
|
636507
636598
|
} catch {
|
|
636508
|
-
|
|
636599
|
+
compiled = null;
|
|
636509
636600
|
}
|
|
636601
|
+
compiledRegExpCache.set(cacheKey, compiled);
|
|
636602
|
+
return compiled;
|
|
636510
636603
|
}
|
|
636511
636604
|
var HASH_EXCLUDED_KEYS = /* @__PURE__ */ new Set([
|
|
636512
636605
|
"location",
|
|
@@ -638219,12 +638312,16 @@ function generateSpecId(filePath) {
|
|
|
638219
638312
|
const normalizedPath = relativePath.split(import_node_path11.default.sep).join("/").replace(/^\.\//, "").replace(/[^a-zA-Z0-9._\-\/]/g, "_");
|
|
638220
638313
|
return normalizedPath;
|
|
638221
638314
|
}
|
|
638222
|
-
|
|
638223
|
-
|
|
638224
|
-
|
|
638225
|
-
|
|
638226
|
-
allowedExtensions = allowedExtensions.concat(fileType.extensions);
|
|
638315
|
+
function buildAllowedExtensions(config) {
|
|
638316
|
+
const allowed = /* @__PURE__ */ new Set(["json", "yaml", "yml"]);
|
|
638317
|
+
(config.fileTypes || []).forEach((fileType) => {
|
|
638318
|
+
fileType.extensions.forEach((ext) => allowed.add(ext));
|
|
638227
638319
|
});
|
|
638320
|
+
return allowed;
|
|
638321
|
+
}
|
|
638322
|
+
async function isValidSourceFile({ config, files, source, allowedExtensions }) {
|
|
638323
|
+
log(config, "debug", `validation: ${source}`);
|
|
638324
|
+
const allowed = allowedExtensions;
|
|
638228
638325
|
if (files.indexOf(source) >= 0)
|
|
638229
638326
|
return false;
|
|
638230
638327
|
if (import_node_path11.default.extname(source) === ".json" || import_node_path11.default.extname(source) === ".yaml" || import_node_path11.default.extname(source) === ".yml") {
|
|
@@ -638271,7 +638368,7 @@ async function isValidSourceFile({ config, files, source }) {
|
|
|
638271
638368
|
}
|
|
638272
638369
|
}
|
|
638273
638370
|
const extension = import_node_path11.default.extname(source).substring(1);
|
|
638274
|
-
if (!
|
|
638371
|
+
if (!allowed.has(extension)) {
|
|
638275
638372
|
log(config, "debug", `${source} extension isn't specified in a \`config.fileTypes\` object. Skipping.`);
|
|
638276
638373
|
return false;
|
|
638277
638374
|
}
|
|
@@ -638323,6 +638420,7 @@ async function qualifyFiles({ config }) {
|
|
|
638323
638420
|
return [];
|
|
638324
638421
|
}
|
|
638325
638422
|
const ignoredDitaMaps = [];
|
|
638423
|
+
const allowedExtensions = buildAllowedExtensions(config);
|
|
638326
638424
|
if (!config._herettoPathMapping) {
|
|
638327
638425
|
config._herettoPathMapping = {};
|
|
638328
638426
|
}
|
|
@@ -638390,8 +638488,9 @@ async function qualifyFiles({ config }) {
|
|
|
638390
638488
|
let isFile = false;
|
|
638391
638489
|
let isDir = false;
|
|
638392
638490
|
try {
|
|
638393
|
-
|
|
638394
|
-
|
|
638491
|
+
const stat = import_node_fs13.default.statSync(source);
|
|
638492
|
+
isFile = stat.isFile();
|
|
638493
|
+
isDir = stat.isDirectory();
|
|
638395
638494
|
} catch {
|
|
638396
638495
|
log(config, "warning", `Cannot access path: ${source}. Skipping.`);
|
|
638397
638496
|
continue;
|
|
@@ -638406,7 +638505,7 @@ async function qualifyFiles({ config }) {
|
|
|
638406
638505
|
continue;
|
|
638407
638506
|
}
|
|
638408
638507
|
const resolved = import_node_path11.default.resolve(source);
|
|
638409
|
-
if (isFile && await isValidSourceFile({ config, files, source: resolved })) {
|
|
638508
|
+
if (isFile && await isValidSourceFile({ config, files, allowedExtensions, source: resolved })) {
|
|
638410
638509
|
files.push(resolved);
|
|
638411
638510
|
if (!phaseByFile.has(resolved))
|
|
638412
638511
|
phaseByFile.set(resolved, phase);
|
|
@@ -638419,9 +638518,10 @@ async function qualifyFiles({ config }) {
|
|
|
638419
638518
|
const content = import_node_path11.default.resolve(dir + "/" + object);
|
|
638420
638519
|
if (content.includes("node_modules"))
|
|
638421
638520
|
continue;
|
|
638422
|
-
const
|
|
638423
|
-
const
|
|
638424
|
-
|
|
638521
|
+
const stat = import_node_fs13.default.statSync(content);
|
|
638522
|
+
const isFile2 = stat.isFile();
|
|
638523
|
+
const isDir2 = stat.isDirectory();
|
|
638524
|
+
if (isFile2 && await isValidSourceFile({ config, files, allowedExtensions, source: content })) {
|
|
638425
638525
|
const resolved2 = import_node_path11.default.resolve(content);
|
|
638426
638526
|
files.push(resolved2);
|
|
638427
638527
|
if (!phaseByFile.has(resolved2))
|
|
@@ -638785,12 +638885,14 @@ function resolveContexts({ contexts, test, config }) {
|
|
|
638785
638885
|
if (resolvedContexts.length === 0) {
|
|
638786
638886
|
resolvedContexts.push({});
|
|
638787
638887
|
}
|
|
638788
|
-
|
|
638888
|
+
if (logLevelEnabled(config, "debug"))
|
|
638889
|
+
log(config, "debug", `Resolved contexts for test ${test.testId}:
|
|
638789
638890
|
${JSON.stringify(resolvedContexts, null, 2)}`);
|
|
638790
638891
|
return resolvedContexts;
|
|
638791
638892
|
}
|
|
638792
638893
|
async function fetchOpenApiDocuments({ config, documentArray }) {
|
|
638793
|
-
|
|
638894
|
+
if (logLevelEnabled(config, "debug"))
|
|
638895
|
+
log(config, "debug", `Fetching OpenAPI documents:
|
|
638794
638896
|
${JSON.stringify(documentArray, null, 2)}`);
|
|
638795
638897
|
const openApiDocuments = [];
|
|
638796
638898
|
if (config?.integrations?.openApi?.length > 0)
|
|
@@ -638811,7 +638913,8 @@ ${JSON.stringify(documentArray, null, 2)}`);
|
|
|
638811
638913
|
openApiDocuments.push(definition);
|
|
638812
638914
|
}
|
|
638813
638915
|
}
|
|
638814
|
-
|
|
638916
|
+
if (logLevelEnabled(config, "debug"))
|
|
638917
|
+
log(config, "debug", `Fetched OpenAPI documents:
|
|
638815
638918
|
${JSON.stringify(openApiDocuments, null, 2)}`);
|
|
638816
638919
|
return openApiDocuments;
|
|
638817
638920
|
}
|
|
@@ -638831,7 +638934,8 @@ async function resolveContext({ config, test, context, usedContextIds, openApi }
|
|
|
638831
638934
|
context.contextId = context.contextId ? uniqueId(context.contextId, usedContextIds) : deriveContextId({ context, usedIds: usedContextIds });
|
|
638832
638935
|
const contextId = context.contextId;
|
|
638833
638936
|
usedContextIds.add(contextId);
|
|
638834
|
-
|
|
638937
|
+
if (logLevelEnabled(config, "debug"))
|
|
638938
|
+
log(config, "debug", `RESOLVING CONTEXT ID ${contextId}:
|
|
638835
638939
|
${JSON.stringify(context, null, 2)}`);
|
|
638836
638940
|
const resolvedContext = {
|
|
638837
638941
|
...context,
|
|
@@ -638844,13 +638948,15 @@ ${JSON.stringify(context, null, 2)}`);
|
|
|
638844
638948
|
steps: [...test.steps],
|
|
638845
638949
|
contextId
|
|
638846
638950
|
};
|
|
638847
|
-
|
|
638951
|
+
if (logLevelEnabled(config, "debug"))
|
|
638952
|
+
log(config, "debug", `RESOLVED CONTEXT ${contextId}:
|
|
638848
638953
|
${JSON.stringify(resolvedContext, null, 2)}`);
|
|
638849
638954
|
return resolvedContext;
|
|
638850
638955
|
}
|
|
638851
638956
|
async function resolveTest({ config, spec, test }) {
|
|
638852
638957
|
const testId = test.testId || `${spec.specId}~${contentHash(test)}`;
|
|
638853
|
-
|
|
638958
|
+
if (logLevelEnabled(config, "debug"))
|
|
638959
|
+
log(config, "debug", `RESOLVING TEST ID ${testId}:
|
|
638854
638960
|
${JSON.stringify(test, null, 2)}`);
|
|
638855
638961
|
const resolvedTest = {
|
|
638856
638962
|
...test,
|
|
@@ -638880,13 +638986,15 @@ ${JSON.stringify(test, null, 2)}`);
|
|
|
638880
638986
|
});
|
|
638881
638987
|
resolvedTest.contexts.push(resolvedContext);
|
|
638882
638988
|
}
|
|
638883
|
-
|
|
638989
|
+
if (logLevelEnabled(config, "debug"))
|
|
638990
|
+
log(config, "debug", `RESOLVED TEST ${testId}:
|
|
638884
638991
|
${JSON.stringify(resolvedTest, null, 2)}`);
|
|
638885
638992
|
return resolvedTest;
|
|
638886
638993
|
}
|
|
638887
638994
|
async function resolveSpec({ config, spec }) {
|
|
638888
638995
|
const specId = spec.specId || (spec.contentPath ? generateSpecId(spec.contentPath) : import_node_crypto5.default.randomUUID());
|
|
638889
|
-
|
|
638996
|
+
if (logLevelEnabled(config, "debug"))
|
|
638997
|
+
log(config, "debug", `RESOLVING SPEC ID ${specId}:
|
|
638890
638998
|
${JSON.stringify(spec, null, 2)}`);
|
|
638891
638999
|
const resolvedSpec = {
|
|
638892
639000
|
...spec,
|
|
@@ -638906,12 +639014,14 @@ ${JSON.stringify(spec, null, 2)}`);
|
|
|
638906
639014
|
});
|
|
638907
639015
|
resolvedSpec.tests.push(resolvedTest);
|
|
638908
639016
|
}
|
|
638909
|
-
|
|
639017
|
+
if (logLevelEnabled(config, "debug"))
|
|
639018
|
+
log(config, "debug", `RESOLVED SPEC ${specId}:
|
|
638910
639019
|
${JSON.stringify(resolvedSpec, null, 2)}`);
|
|
638911
639020
|
return resolvedSpec;
|
|
638912
639021
|
}
|
|
638913
639022
|
async function resolveTests({ config, detectedTests }) {
|
|
638914
|
-
|
|
639023
|
+
if (logLevelEnabled(config, "debug"))
|
|
639024
|
+
log(config, "debug", `RESOLVING DETECTED TEST SPECS:
|
|
638915
639025
|
${JSON.stringify(detectedTests, null, 2)}`);
|
|
638916
639026
|
const resolvedTests = {
|
|
638917
639027
|
resolvedTestsId: import_node_crypto5.default.randomUUID(),
|
|
@@ -638923,7 +639033,8 @@ ${JSON.stringify(detectedTests, null, 2)}`);
|
|
|
638923
639033
|
const resolvedSpec = await resolveSpec({ config, spec });
|
|
638924
639034
|
resolvedTests.specs.push(resolvedSpec);
|
|
638925
639035
|
}
|
|
638926
|
-
|
|
639036
|
+
if (logLevelEnabled(config, "debug"))
|
|
639037
|
+
log(config, "debug", `RESOLVED TEST SPECS:
|
|
638927
639038
|
${JSON.stringify(resolvedTests, null, 2)}`);
|
|
638928
639039
|
return resolvedTests;
|
|
638929
639040
|
}
|
|
@@ -641084,6 +641195,13 @@ async function teardownDeviceRegistry(registry, kill4) {
|
|
|
641084
641195
|
for (const entry of registry.values()) {
|
|
641085
641196
|
if (!entry.bootedByUs)
|
|
641086
641197
|
continue;
|
|
641198
|
+
if (entry.ready) {
|
|
641199
|
+
try {
|
|
641200
|
+
await entry.ready;
|
|
641201
|
+
} catch {
|
|
641202
|
+
continue;
|
|
641203
|
+
}
|
|
641204
|
+
}
|
|
641087
641205
|
try {
|
|
641088
641206
|
await kill4(entry);
|
|
641089
641207
|
} catch {
|
|
@@ -643777,6 +643895,7 @@ function containsOperators(expression, allowOperators = false) {
|
|
|
643777
643895
|
}
|
|
643778
643896
|
return false;
|
|
643779
643897
|
}
|
|
643898
|
+
var compiledEvaluatorCache = /* @__PURE__ */ new Map();
|
|
643780
643899
|
async function evaluateExpression(expression, context) {
|
|
643781
643900
|
try {
|
|
643782
643901
|
expression = preprocessExpression(expression);
|
|
@@ -643850,7 +643969,13 @@ async function evaluateExpression(expression, context) {
|
|
|
643850
643969
|
}
|
|
643851
643970
|
})
|
|
643852
643971
|
};
|
|
643853
|
-
const
|
|
643972
|
+
const argNames = Object.keys(evalContext);
|
|
643973
|
+
const cacheKey = `${argNames.join(",")}\0${expression}`;
|
|
643974
|
+
let evaluator = compiledEvaluatorCache.get(cacheKey);
|
|
643975
|
+
if (!evaluator) {
|
|
643976
|
+
evaluator = new Function(...argNames, `return ${expression};`);
|
|
643977
|
+
compiledEvaluatorCache.set(cacheKey, evaluator);
|
|
643978
|
+
}
|
|
643854
643979
|
return evaluator(...Object.values(evalContext));
|
|
643855
643980
|
} catch (error) {
|
|
643856
643981
|
log(`Error evaluating expression '${expression}': ${error.message}`, "error");
|
|
@@ -648672,6 +648797,10 @@ function mobileBrowserConfigError(browser) {
|
|
|
648672
648797
|
}
|
|
648673
648798
|
return null;
|
|
648674
648799
|
}
|
|
648800
|
+
var CHROMEDRIVER_AUTODOWNLOAD_ARGS = [
|
|
648801
|
+
"--allow-insecure",
|
|
648802
|
+
"uiautomator2:chromedriver_autodownload"
|
|
648803
|
+
];
|
|
648675
648804
|
function mobileBrowserGate({ platform, browser, hasBrowserStep, hasAppStep }) {
|
|
648676
648805
|
if (!hasBrowserStep)
|
|
648677
648806
|
return { action: "proceed", browserName: null };
|
|
@@ -648732,6 +648861,216 @@ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout, loc
|
|
|
648732
648861
|
return capabilities;
|
|
648733
648862
|
}
|
|
648734
648863
|
|
|
648864
|
+
// dist/core/warmPhase.js
|
|
648865
|
+
init_utils();
|
|
648866
|
+
var WARM_POOL_LIMIT = 4;
|
|
648867
|
+
var RUNTIME_INSTALL_RESOURCE = "runtime-install";
|
|
648868
|
+
function deviceIdentity(platform, desc) {
|
|
648869
|
+
if (desc?.name)
|
|
648870
|
+
return `${platform}:name:${desc.name}`;
|
|
648871
|
+
return `${platform}:default:${desc?.deviceType ?? "<any>"}:${desc?.osVersion ?? "<latest>"}`;
|
|
648872
|
+
}
|
|
648873
|
+
function deviceResourceTag(platform, desc) {
|
|
648874
|
+
return `warm-device:${deviceIdentity(platform, desc)}`;
|
|
648875
|
+
}
|
|
648876
|
+
function wrapInitiationEffects(deps, keys, signal) {
|
|
648877
|
+
const wrapped = { ...deps };
|
|
648878
|
+
for (const key of keys) {
|
|
648879
|
+
const original = deps[key];
|
|
648880
|
+
if (typeof original !== "function")
|
|
648881
|
+
continue;
|
|
648882
|
+
wrapped[key] = (...args) => {
|
|
648883
|
+
const result = original(...args);
|
|
648884
|
+
signal();
|
|
648885
|
+
return result;
|
|
648886
|
+
};
|
|
648887
|
+
}
|
|
648888
|
+
return wrapped;
|
|
648889
|
+
}
|
|
648890
|
+
function planWarmTasks({ sizingJobs, runnerDetails, limit, hasAppiumPool, deps }) {
|
|
648891
|
+
const hostPlatform = runnerDetails?.environment?.platform;
|
|
648892
|
+
const tasks = [];
|
|
648893
|
+
const seen = /* @__PURE__ */ new Set();
|
|
648894
|
+
const addTask = (task) => {
|
|
648895
|
+
if (seen.has(task.name))
|
|
648896
|
+
return;
|
|
648897
|
+
seen.add(task.name);
|
|
648898
|
+
tasks.push(task);
|
|
648899
|
+
};
|
|
648900
|
+
let probeEligible = false;
|
|
648901
|
+
let defaultBrowser;
|
|
648902
|
+
const getDefaultBrowser2 = () => defaultBrowser ??= deps.getDefaultBrowser({ runnerDetails });
|
|
648903
|
+
const bootPlannedFor = /* @__PURE__ */ new Set();
|
|
648904
|
+
for (const job of sizingJobs ?? []) {
|
|
648905
|
+
const context = job?.context;
|
|
648906
|
+
if (!context)
|
|
648907
|
+
continue;
|
|
648908
|
+
if (deps.contextRequirementsSkipMessage({ context }))
|
|
648909
|
+
continue;
|
|
648910
|
+
const effPlatform = context.platform || hostPlatform;
|
|
648911
|
+
const mobileTarget = deps.isMobileTargetPlatform(effPlatform);
|
|
648912
|
+
if (mobileTarget) {
|
|
648913
|
+
if (mobileTarget === "ios" && hostPlatform !== "mac")
|
|
648914
|
+
continue;
|
|
648915
|
+
const hasAppStep = deps.isAppDriverRequired({ test: context });
|
|
648916
|
+
const gate = deps.mobileBrowserGate({
|
|
648917
|
+
platform: mobileTarget,
|
|
648918
|
+
browser: context.browser,
|
|
648919
|
+
hasBrowserStep: deps.isBrowserRequired({ test: context }),
|
|
648920
|
+
hasAppStep
|
|
648921
|
+
});
|
|
648922
|
+
if (gate.action !== "proceed")
|
|
648923
|
+
continue;
|
|
648924
|
+
const isMobileWeb = typeof gate.browserName === "string";
|
|
648925
|
+
if (!isMobileWeb && !hasAppStep)
|
|
648926
|
+
continue;
|
|
648927
|
+
const driverPackage = deps.appDriverPlatforms[mobileTarget]?.driverPackage;
|
|
648928
|
+
if (driverPackage) {
|
|
648929
|
+
addTask({
|
|
648930
|
+
name: `driver-install:${driverPackage}`,
|
|
648931
|
+
kind: "driver-install",
|
|
648932
|
+
exclusiveResources: [RUNTIME_INSTALL_RESOURCE],
|
|
648933
|
+
payload: { driverPackage, platform: mobileTarget }
|
|
648934
|
+
});
|
|
648935
|
+
}
|
|
648936
|
+
for (const stepDevice of deps.collectDeviceDescriptors(context)) {
|
|
648937
|
+
const desc = deps.normalizeDeviceDescriptor({
|
|
648938
|
+
contextDevice: context.device,
|
|
648939
|
+
stepDevice,
|
|
648940
|
+
platform: mobileTarget
|
|
648941
|
+
});
|
|
648942
|
+
const identity = deviceIdentity(mobileTarget, desc);
|
|
648943
|
+
const tag = deviceResourceTag(mobileTarget, desc);
|
|
648944
|
+
if (!bootPlannedFor.has(mobileTarget)) {
|
|
648945
|
+
bootPlannedFor.add(mobileTarget);
|
|
648946
|
+
addTask({
|
|
648947
|
+
name: `device-boot:${identity}`,
|
|
648948
|
+
kind: "device-boot",
|
|
648949
|
+
exclusiveResources: [tag],
|
|
648950
|
+
payload: { platform: mobileTarget, desc }
|
|
648951
|
+
});
|
|
648952
|
+
}
|
|
648953
|
+
if (mobileTarget === "android" && isMobileWeb) {
|
|
648954
|
+
addTask({
|
|
648955
|
+
name: `chromedriver-prefetch:${identity}`,
|
|
648956
|
+
kind: "chromedriver-prefetch",
|
|
648957
|
+
exclusiveResources: [tag],
|
|
648958
|
+
payload: { platform: mobileTarget, desc }
|
|
648959
|
+
});
|
|
648960
|
+
}
|
|
648961
|
+
}
|
|
648962
|
+
if (mobileTarget === "ios") {
|
|
648963
|
+
addTask({
|
|
648964
|
+
name: "wda-check",
|
|
648965
|
+
kind: "wda-check",
|
|
648966
|
+
// Read-only (plus the last-used stamp) — contends with nothing.
|
|
648967
|
+
exclusiveResources: [],
|
|
648968
|
+
payload: {}
|
|
648969
|
+
});
|
|
648970
|
+
}
|
|
648971
|
+
continue;
|
|
648972
|
+
}
|
|
648973
|
+
if (deps.isBrowserRequired({ test: context })) {
|
|
648974
|
+
const effBrowser = context.browser ?? getDefaultBrowser2();
|
|
648975
|
+
const browserName = effBrowser?.name;
|
|
648976
|
+
if (browserName && effPlatform === hostPlatform) {
|
|
648977
|
+
probeEligible = true;
|
|
648978
|
+
if (deps.requiredBrowserAssets(browserName).length > 0) {
|
|
648979
|
+
addTask({
|
|
648980
|
+
name: `browser-install:${browserName.toLowerCase()}`,
|
|
648981
|
+
kind: "browser-install",
|
|
648982
|
+
exclusiveResources: [RUNTIME_INSTALL_RESOURCE],
|
|
648983
|
+
payload: { browserName }
|
|
648984
|
+
});
|
|
648985
|
+
}
|
|
648986
|
+
}
|
|
648987
|
+
}
|
|
648988
|
+
if ((effPlatform === "windows" || effPlatform === "mac") && effPlatform === hostPlatform && deps.isAppDriverRequired({ test: context })) {
|
|
648989
|
+
const driverPackage = deps.appDriverPlatforms[effPlatform]?.driverPackage;
|
|
648990
|
+
if (driverPackage) {
|
|
648991
|
+
addTask({
|
|
648992
|
+
name: `driver-install:${driverPackage}`,
|
|
648993
|
+
kind: "driver-install",
|
|
648994
|
+
exclusiveResources: [RUNTIME_INSTALL_RESOURCE],
|
|
648995
|
+
payload: { driverPackage, platform: effPlatform }
|
|
648996
|
+
});
|
|
648997
|
+
}
|
|
648998
|
+
}
|
|
648999
|
+
}
|
|
649000
|
+
if (limit > 1 && hasAppiumPool && probeEligible) {
|
|
649001
|
+
addTask({
|
|
649002
|
+
name: "session-probe",
|
|
649003
|
+
kind: "session-probe",
|
|
649004
|
+
// Its install half mutates the shared caches, exactly like the
|
|
649005
|
+
// dedicated install tasks (usually a memo hit by the time it runs).
|
|
649006
|
+
exclusiveResources: [RUNTIME_INSTALL_RESOURCE],
|
|
649007
|
+
payload: {}
|
|
649008
|
+
});
|
|
649009
|
+
}
|
|
649010
|
+
return tasks;
|
|
649011
|
+
}
|
|
649012
|
+
async function executeWarmTasks({ tasks, registry, runTask, log: log3, now = Date.now }) {
|
|
649013
|
+
const results = [];
|
|
649014
|
+
const start = now();
|
|
649015
|
+
await runResourceAware(tasks, WARM_POOL_LIMIT, registry, async (task) => {
|
|
649016
|
+
const taskStart = now();
|
|
649017
|
+
try {
|
|
649018
|
+
const { outcome, note } = await runTask(task);
|
|
649019
|
+
results.push({
|
|
649020
|
+
name: task.name,
|
|
649021
|
+
kind: task.kind,
|
|
649022
|
+
outcome,
|
|
649023
|
+
durationMs: now() - taskStart,
|
|
649024
|
+
...note ? { note } : {}
|
|
649025
|
+
});
|
|
649026
|
+
if (outcome === "failed") {
|
|
649027
|
+
log3("warning", `Warm task '${task.name}' failed (continuing)${note ? `: ${note}` : "."}`);
|
|
649028
|
+
} else {
|
|
649029
|
+
log3("debug", `Warm task '${task.name}': ${outcome}${note ? ` (${note})` : ""}.`);
|
|
649030
|
+
}
|
|
649031
|
+
} catch (error) {
|
|
649032
|
+
const note = error?.message ?? String(error);
|
|
649033
|
+
results.push({
|
|
649034
|
+
name: task.name,
|
|
649035
|
+
kind: task.kind,
|
|
649036
|
+
outcome: "failed",
|
|
649037
|
+
durationMs: now() - taskStart,
|
|
649038
|
+
note
|
|
649039
|
+
});
|
|
649040
|
+
log3("warning", `Warm task '${task.name}' failed (continuing): ${note}`);
|
|
649041
|
+
}
|
|
649042
|
+
});
|
|
649043
|
+
return { durationMs: now() - start, tasks: results };
|
|
649044
|
+
}
|
|
649045
|
+
function raceBootInitiation({ startAcquire, onError }) {
|
|
649046
|
+
let initiatedResolve;
|
|
649047
|
+
const initiated = new Promise((resolve) => {
|
|
649048
|
+
initiatedResolve = resolve;
|
|
649049
|
+
});
|
|
649050
|
+
const acquired = (async () => {
|
|
649051
|
+
try {
|
|
649052
|
+
const result = await startAcquire(() => initiatedResolve());
|
|
649053
|
+
if (result && typeof result === "object" && "skip" in result) {
|
|
649054
|
+
return { outcome: "skipped", note: result.skip };
|
|
649055
|
+
}
|
|
649056
|
+
return { outcome: "warmed", note: "device ready" };
|
|
649057
|
+
} catch (error) {
|
|
649058
|
+
onError(error);
|
|
649059
|
+
return {
|
|
649060
|
+
outcome: "failed",
|
|
649061
|
+
note: error?.message ?? String(error)
|
|
649062
|
+
};
|
|
649063
|
+
}
|
|
649064
|
+
})();
|
|
649065
|
+
return Promise.race([
|
|
649066
|
+
initiated.then(() => ({
|
|
649067
|
+
outcome: "warmed",
|
|
649068
|
+
note: "boot initiated"
|
|
649069
|
+
})),
|
|
649070
|
+
acquired
|
|
649071
|
+
]);
|
|
649072
|
+
}
|
|
649073
|
+
|
|
648735
649074
|
// dist/core/tests.js
|
|
648736
649075
|
init_cacheDir();
|
|
648737
649076
|
|
|
@@ -649001,6 +649340,13 @@ async function teardownSimulatorRegistry(registry, shutdown) {
|
|
|
649001
649340
|
for (const entry of registry.values()) {
|
|
649002
649341
|
if (!entry.bootedByUs)
|
|
649003
649342
|
continue;
|
|
649343
|
+
if (entry.ready) {
|
|
649344
|
+
try {
|
|
649345
|
+
await entry.ready;
|
|
649346
|
+
} catch {
|
|
649347
|
+
continue;
|
|
649348
|
+
}
|
|
649349
|
+
}
|
|
649004
649350
|
try {
|
|
649005
649351
|
await shutdown(entry);
|
|
649006
649352
|
} catch {
|
|
@@ -649537,6 +649883,20 @@ function combinationKey(context) {
|
|
|
649537
649883
|
function warmUpDecision(prev) {
|
|
649538
649884
|
return prev === "failed" ? "skip" : "attempt";
|
|
649539
649885
|
}
|
|
649886
|
+
function buildWarmPlanDeps() {
|
|
649887
|
+
return {
|
|
649888
|
+
isBrowserRequired,
|
|
649889
|
+
isAppDriverRequired,
|
|
649890
|
+
isMobileTargetPlatform,
|
|
649891
|
+
getDefaultBrowser,
|
|
649892
|
+
requiredBrowserAssets,
|
|
649893
|
+
collectDeviceDescriptors,
|
|
649894
|
+
normalizeDeviceDescriptor,
|
|
649895
|
+
mobileBrowserGate,
|
|
649896
|
+
contextRequirementsSkipMessage,
|
|
649897
|
+
appDriverPlatforms: APP_DRIVER_PLATFORMS
|
|
649898
|
+
};
|
|
649899
|
+
}
|
|
649540
649900
|
function getDriverCapabilities({ runnerDetails, name, options }) {
|
|
649541
649901
|
let capabilities = {};
|
|
649542
649902
|
let args = [];
|
|
@@ -650146,7 +650506,12 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650146
650506
|
skipped: 0
|
|
650147
650507
|
}
|
|
650148
650508
|
},
|
|
650149
|
-
specs: []
|
|
650509
|
+
specs: [],
|
|
650510
|
+
// Inline warm phase results (docs/design/warm-phase.md). Present on the
|
|
650511
|
+
// skeleton so a run that plans nothing (or whose planning fails —
|
|
650512
|
+
// best-effort) still reports the structural empty block; the phase
|
|
650513
|
+
// overwrites it with real task results below.
|
|
650514
|
+
warm: { durationMs: 0, tasks: [] }
|
|
650150
650515
|
};
|
|
650151
650516
|
let limit = resolveConcurrentRunners(config);
|
|
650152
650517
|
log(config, "info", "Running test specs.");
|
|
@@ -650301,6 +650666,7 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650301
650666
|
const serverCount = Math.min(limit, browserPoolJobCount);
|
|
650302
650667
|
log(config, "debug", `Starting ${serverCount} Appium server(s).`);
|
|
650303
650668
|
try {
|
|
650669
|
+
const readinessWaits = [];
|
|
650304
650670
|
for (let i = 0; i < serverCount; i++) {
|
|
650305
650671
|
let display;
|
|
650306
650672
|
if (useXvfbDisplays) {
|
|
@@ -650308,7 +650674,16 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650308
650674
|
xvfbProcesses.push(await startXvfb(display));
|
|
650309
650675
|
log(config, "debug", `Started Xvfb on ${display} for recording.`);
|
|
650310
650676
|
}
|
|
650311
|
-
|
|
650677
|
+
const server = await spawnAppiumServer(appiumEntry, config, display);
|
|
650678
|
+
appiumServers.push(server);
|
|
650679
|
+
const wait2 = appiumIsReady(server.port);
|
|
650680
|
+
wait2.catch(() => {
|
|
650681
|
+
});
|
|
650682
|
+
readinessWaits.push(wait2);
|
|
650683
|
+
}
|
|
650684
|
+
await Promise.all(readinessWaits);
|
|
650685
|
+
for (const server of appiumServers) {
|
|
650686
|
+
log(config, "debug", `Appium is ready on port ${server.port}.`);
|
|
650312
650687
|
}
|
|
650313
650688
|
} catch (error) {
|
|
650314
650689
|
await Promise.all(appiumServers.map((server) => {
|
|
@@ -650331,6 +650706,7 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650331
650706
|
const processRegistry = /* @__PURE__ */ new Map();
|
|
650332
650707
|
const deviceRegistry = createDeviceRegistry();
|
|
650333
650708
|
const simulatorRegistry = createSimulatorRegistry();
|
|
650709
|
+
const resourceRegistry = createResourceRegistry();
|
|
650334
650710
|
const killAllRegistered = async () => {
|
|
650335
650711
|
const entries = [...processRegistry.entries()];
|
|
650336
650712
|
processRegistry.clear();
|
|
@@ -650367,15 +650743,35 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650367
650743
|
process.on("SIGINT", onSignal);
|
|
650368
650744
|
process.on("SIGTERM", onSignal);
|
|
650369
650745
|
try {
|
|
650370
|
-
|
|
650371
|
-
|
|
650372
|
-
|
|
650373
|
-
config,
|
|
650746
|
+
try {
|
|
650747
|
+
const warmTasks = planWarmTasks({
|
|
650748
|
+
sizingJobs,
|
|
650374
650749
|
runnerDetails,
|
|
650375
|
-
|
|
650376
|
-
|
|
650377
|
-
|
|
650750
|
+
limit,
|
|
650751
|
+
hasAppiumPool: !!appiumPool,
|
|
650752
|
+
deps: buildWarmPlanDeps()
|
|
650378
650753
|
});
|
|
650754
|
+
if (warmTasks.length > 0) {
|
|
650755
|
+
log(config, "debug", `Warm phase: ${warmTasks.length} task(s).`);
|
|
650756
|
+
report.warm = await executeWarmTasks({
|
|
650757
|
+
tasks: warmTasks,
|
|
650758
|
+
registry: resourceRegistry,
|
|
650759
|
+
runTask: buildWarmTaskRunner({
|
|
650760
|
+
config,
|
|
650761
|
+
runnerDetails,
|
|
650762
|
+
sizingJobs,
|
|
650763
|
+
appiumPool,
|
|
650764
|
+
installAttempts,
|
|
650765
|
+
warmUpResults,
|
|
650766
|
+
deviceRegistry,
|
|
650767
|
+
simulatorRegistry,
|
|
650768
|
+
resourceRegistry
|
|
650769
|
+
}),
|
|
650770
|
+
log: (level, message) => log(config, level, message)
|
|
650771
|
+
});
|
|
650772
|
+
}
|
|
650773
|
+
} catch (error) {
|
|
650774
|
+
log(config, "warning", `Warm phase skipped (planning failed; the run proceeds with on-demand provisioning): ${error?.message ?? error}`);
|
|
650379
650775
|
}
|
|
650380
650776
|
const runJob = async (job) => {
|
|
650381
650777
|
try {
|
|
@@ -650427,7 +650823,6 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650427
650823
|
const phase = PHASES.includes(entry.spec?._phase) ? entry.spec._phase : "main";
|
|
650428
650824
|
routedByPhase[phase].push(entry);
|
|
650429
650825
|
}
|
|
650430
|
-
const resourceRegistry = createResourceRegistry();
|
|
650431
650826
|
for (const phase of PHASES) {
|
|
650432
650827
|
if (limit > 1) {
|
|
650433
650828
|
await runResourceAware(jobsByPhase[phase], limit, resourceRegistry, runJob);
|
|
@@ -650741,27 +651136,17 @@ async function warmUpContexts({ jobs, config, runnerDetails, appiumPool, install
|
|
|
650741
651136
|
platform
|
|
650742
651137
|
});
|
|
650743
651138
|
if (!supported && context.platform === platform && Array.isArray(context?.steps) && requiredBrowserAssets(context.browser?.name).length > 0) {
|
|
650744
|
-
|
|
650745
|
-
const outcome = await ensureContextBrowserInstalled({
|
|
651139
|
+
await warmBrowserInstall({
|
|
650746
651140
|
browserName: context.browser?.name,
|
|
650747
651141
|
config,
|
|
650748
|
-
|
|
650749
|
-
|
|
650750
|
-
|
|
650751
|
-
|
|
650752
|
-
|
|
650753
|
-
|
|
650754
|
-
|
|
651142
|
+
runnerDetails,
|
|
651143
|
+
installAttempts
|
|
651144
|
+
});
|
|
651145
|
+
supported = isSupportedContext({
|
|
651146
|
+
context,
|
|
651147
|
+
apps: runnerDetails.availableApps,
|
|
651148
|
+
platform
|
|
650755
651149
|
});
|
|
650756
|
-
if (firstAttempt && (outcome === "installed" || outcome === "failed")) {
|
|
650757
|
-
clearAppCache(config);
|
|
650758
|
-
runnerDetails.availableApps = await getAvailableApps({ config });
|
|
650759
|
-
supported = isSupportedContext({
|
|
650760
|
-
context,
|
|
650761
|
-
apps: runnerDetails.availableApps,
|
|
650762
|
-
platform
|
|
650763
|
-
});
|
|
650764
|
-
}
|
|
650765
651150
|
}
|
|
650766
651151
|
if (!supported)
|
|
650767
651152
|
continue;
|
|
@@ -650803,6 +651188,292 @@ async function warmUpContexts({ jobs, config, runnerDetails, appiumPool, install
|
|
|
650803
651188
|
}
|
|
650804
651189
|
}
|
|
650805
651190
|
}
|
|
651191
|
+
async function warmBrowserInstall({ browserName, config, runnerDetails, installAttempts, deps = {} }) {
|
|
651192
|
+
const appName = normalizeBrowserName(browserName);
|
|
651193
|
+
if (runnerDetails.availableApps?.find((app) => app.name === appName)) {
|
|
651194
|
+
return {
|
|
651195
|
+
outcome: "skipped",
|
|
651196
|
+
note: `'${browserName}' is already available`
|
|
651197
|
+
};
|
|
651198
|
+
}
|
|
651199
|
+
const firstAttempt = !installAttempts.has((browserName ?? "<none>").toLowerCase());
|
|
651200
|
+
const outcome = await ensureContextBrowserInstalled({
|
|
651201
|
+
browserName,
|
|
651202
|
+
config,
|
|
651203
|
+
installAttempts,
|
|
651204
|
+
deps: {
|
|
651205
|
+
ensureBrowser: deps.ensureBrowser ?? ((asset, options) => ensureBrowserInstalled(asset, options)),
|
|
651206
|
+
log
|
|
651207
|
+
},
|
|
651208
|
+
// Repair a present-but-broken driver, not just install-if-missing.
|
|
651209
|
+
repair: true
|
|
651210
|
+
});
|
|
651211
|
+
if (firstAttempt && (outcome === "installed" || outcome === "failed")) {
|
|
651212
|
+
(deps.clearAppCache ?? clearAppCache)(config);
|
|
651213
|
+
runnerDetails.availableApps = await (deps.getAvailableApps ?? getAvailableApps)({ config });
|
|
651214
|
+
}
|
|
651215
|
+
if (outcome === "installed")
|
|
651216
|
+
return { outcome: "warmed" };
|
|
651217
|
+
if (outcome === "failed") {
|
|
651218
|
+
return { outcome: "failed", note: `couldn't install '${browserName}'` };
|
|
651219
|
+
}
|
|
651220
|
+
return {
|
|
651221
|
+
outcome: "skipped",
|
|
651222
|
+
note: `'${browserName}' has no installable assets`
|
|
651223
|
+
};
|
|
651224
|
+
}
|
|
651225
|
+
async function resolveAndroidWarmEnv(config) {
|
|
651226
|
+
try {
|
|
651227
|
+
const abi = hostAbi();
|
|
651228
|
+
const sdk = detectAndroidSdk({ cacheDir: config?.cacheDir });
|
|
651229
|
+
if (!sdk?.emulator)
|
|
651230
|
+
return null;
|
|
651231
|
+
const deviceDeps = buildAcquireDeviceDeps(sdk, abi, (m) => log(config, "debug", m));
|
|
651232
|
+
const running = await deviceDeps.listRunning();
|
|
651233
|
+
const capable = running.length > 0 || await checkEmulatorAcceleration(sdk.emulator);
|
|
651234
|
+
if (!capable)
|
|
651235
|
+
return null;
|
|
651236
|
+
return { sdkRoot: sdk.sdkRoot, deviceDeps };
|
|
651237
|
+
} catch {
|
|
651238
|
+
return null;
|
|
651239
|
+
}
|
|
651240
|
+
}
|
|
651241
|
+
async function probeIosToolchainWarm() {
|
|
651242
|
+
if (process.platform !== "darwin")
|
|
651243
|
+
return probeIosToolchain();
|
|
651244
|
+
const runAsync = (command, args, timeout) => new Promise((resolve) => {
|
|
651245
|
+
let stdout = "";
|
|
651246
|
+
let stderr = "";
|
|
651247
|
+
try {
|
|
651248
|
+
const child = (0, import_node_child_process15.spawn)(command, args, { windowsHide: true, timeout });
|
|
651249
|
+
child.stdout?.on("data", (d) => stdout += String(d));
|
|
651250
|
+
child.stderr?.on("data", (d) => stderr += String(d));
|
|
651251
|
+
child.on("error", () => resolve({ status: null, stdout, stderr }));
|
|
651252
|
+
child.on("close", (status) => resolve({ status, stdout, stderr }));
|
|
651253
|
+
} catch {
|
|
651254
|
+
resolve({ status: null, stdout, stderr });
|
|
651255
|
+
}
|
|
651256
|
+
});
|
|
651257
|
+
const [xcodeSelect, simctl] = await Promise.all([
|
|
651258
|
+
runAsync("xcode-select", ["-p"], 15e3),
|
|
651259
|
+
// Same generous ceiling as the sync probe's xcrun spawn: the first cold
|
|
651260
|
+
// simctl call launches CoreSimulatorService.
|
|
651261
|
+
runAsync("xcrun", ["simctl", "list", "devices", "available"], 12e4)
|
|
651262
|
+
]);
|
|
651263
|
+
return probeIosToolchain({
|
|
651264
|
+
run: (command) => command === "xcrun" ? simctl : xcodeSelect
|
|
651265
|
+
});
|
|
651266
|
+
}
|
|
651267
|
+
function buildWarmTaskRunner({ config, runnerDetails, sizingJobs, appiumPool, installAttempts, warmUpResults, deviceRegistry, simulatorRegistry, resourceRegistry }) {
|
|
651268
|
+
let androidEnv;
|
|
651269
|
+
const getAndroidEnv = () => androidEnv ??= resolveAndroidWarmEnv(config);
|
|
651270
|
+
let iosToolchain;
|
|
651271
|
+
const getIosToolchain = () => iosToolchain ??= probeIosToolchainWarm();
|
|
651272
|
+
const acquireLease = async (names) => {
|
|
651273
|
+
while (!resourceRegistry.tryAcquire(names)) {
|
|
651274
|
+
await resourceRegistry.waitForFree();
|
|
651275
|
+
}
|
|
651276
|
+
let released = false;
|
|
651277
|
+
return () => {
|
|
651278
|
+
if (released)
|
|
651279
|
+
return;
|
|
651280
|
+
released = true;
|
|
651281
|
+
resourceRegistry.release(names);
|
|
651282
|
+
};
|
|
651283
|
+
};
|
|
651284
|
+
const withRuntimeInstallLock = async (fn) => {
|
|
651285
|
+
const release = await acquireLease([RUNTIME_INSTALL_RESOURCE]);
|
|
651286
|
+
try {
|
|
651287
|
+
return await fn();
|
|
651288
|
+
} finally {
|
|
651289
|
+
release();
|
|
651290
|
+
}
|
|
651291
|
+
};
|
|
651292
|
+
let androidPreflight;
|
|
651293
|
+
const getAndroidPreflight = () => androidPreflight ??= withRuntimeInstallLock(() => appSurfacePreflight({ config, platform: "android" }));
|
|
651294
|
+
return async (task) => {
|
|
651295
|
+
switch (task.kind) {
|
|
651296
|
+
case "browser-install":
|
|
651297
|
+
return warmBrowserInstall({
|
|
651298
|
+
browserName: task.payload.browserName,
|
|
651299
|
+
config,
|
|
651300
|
+
runnerDetails,
|
|
651301
|
+
installAttempts
|
|
651302
|
+
});
|
|
651303
|
+
case "driver-install": {
|
|
651304
|
+
if (task.payload.platform === "android") {
|
|
651305
|
+
const env = await getAndroidEnv();
|
|
651306
|
+
if (!env) {
|
|
651307
|
+
return {
|
|
651308
|
+
outcome: "skipped",
|
|
651309
|
+
note: "Android toolchain not ready; the driver install stays with the consuming context"
|
|
651310
|
+
};
|
|
651311
|
+
}
|
|
651312
|
+
}
|
|
651313
|
+
if (task.payload.platform === "ios") {
|
|
651314
|
+
const toolchain = await getIosToolchain();
|
|
651315
|
+
if (!toolchain.ok) {
|
|
651316
|
+
return { outcome: "skipped", note: toolchain.reason };
|
|
651317
|
+
}
|
|
651318
|
+
}
|
|
651319
|
+
const { ensureRuntimeInstalled: ensureRuntimeInstalled2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
|
|
651320
|
+
await ensureRuntimeInstalled2([task.payload.driverPackage], {
|
|
651321
|
+
ctx: { cacheDir: config?.cacheDir },
|
|
651322
|
+
deps: { logger: (m) => log(config, "debug", m) }
|
|
651323
|
+
});
|
|
651324
|
+
return { outcome: "warmed" };
|
|
651325
|
+
}
|
|
651326
|
+
case "device-boot": {
|
|
651327
|
+
const desc = task.payload.desc;
|
|
651328
|
+
const onError = (error) => log(config, "warning", `Warm boot of '${task.name}' failed (a consuming context will retry): ${error?.message ?? String(error)}`);
|
|
651329
|
+
if (task.payload.platform === "android") {
|
|
651330
|
+
const env = await getAndroidEnv();
|
|
651331
|
+
if (!env) {
|
|
651332
|
+
return {
|
|
651333
|
+
outcome: "skipped",
|
|
651334
|
+
note: "Android toolchain not ready; device setup stays with the consuming context"
|
|
651335
|
+
};
|
|
651336
|
+
}
|
|
651337
|
+
const releaseEmulatorLease = await acquireLease([
|
|
651338
|
+
"android-emulator"
|
|
651339
|
+
]);
|
|
651340
|
+
return raceBootInitiation({
|
|
651341
|
+
onError,
|
|
651342
|
+
startAcquire: (signalInitiated) => {
|
|
651343
|
+
const acquiring = acquireDevice({
|
|
651344
|
+
desc,
|
|
651345
|
+
registry: deviceRegistry,
|
|
651346
|
+
sdkRoot: env.sdkRoot,
|
|
651347
|
+
deps: wrapInitiationEffects(env.deviceDeps, ["createAvd", "boot"], signalInitiated)
|
|
651348
|
+
});
|
|
651349
|
+
acquiring.then(() => releaseEmulatorLease(), () => releaseEmulatorLease());
|
|
651350
|
+
return acquiring;
|
|
651351
|
+
}
|
|
651352
|
+
});
|
|
651353
|
+
}
|
|
651354
|
+
const toolchain = await getIosToolchain();
|
|
651355
|
+
if (!toolchain.ok) {
|
|
651356
|
+
return { outcome: "skipped", note: toolchain.reason };
|
|
651357
|
+
}
|
|
651358
|
+
const simDeps = buildAcquireSimulatorDeps((m) => log(config, "debug", m));
|
|
651359
|
+
return raceBootInitiation({
|
|
651360
|
+
onError,
|
|
651361
|
+
startAcquire: (signalInitiated) => acquireSimulator({
|
|
651362
|
+
desc,
|
|
651363
|
+
registry: simulatorRegistry,
|
|
651364
|
+
deps: wrapInitiationEffects(simDeps, ["create", "boot"], signalInitiated)
|
|
651365
|
+
})
|
|
651366
|
+
});
|
|
651367
|
+
}
|
|
651368
|
+
case "wda-check": {
|
|
651369
|
+
const hit = locateManagedWda({ ctx: { cacheDir: config?.cacheDir } });
|
|
651370
|
+
if (hit) {
|
|
651371
|
+
return {
|
|
651372
|
+
outcome: "warmed",
|
|
651373
|
+
note: `prebuilt WebDriverAgent available (${hit.key})`
|
|
651374
|
+
};
|
|
651375
|
+
}
|
|
651376
|
+
return {
|
|
651377
|
+
outcome: "skipped",
|
|
651378
|
+
note: "no prebuilt WebDriverAgent for the current toolchain \u2014 `doc-detective install ios` prebuilds it"
|
|
651379
|
+
};
|
|
651380
|
+
}
|
|
651381
|
+
case "session-probe": {
|
|
651382
|
+
if (!appiumPool) {
|
|
651383
|
+
return { outcome: "skipped", note: "no browser Appium pool" };
|
|
651384
|
+
}
|
|
651385
|
+
await warmUpContexts({
|
|
651386
|
+
jobs: sizingJobs,
|
|
651387
|
+
config,
|
|
651388
|
+
runnerDetails,
|
|
651389
|
+
appiumPool,
|
|
651390
|
+
installAttempts,
|
|
651391
|
+
warmUpResults
|
|
651392
|
+
});
|
|
651393
|
+
const ok = [...warmUpResults.values()].filter((v) => v === "ok").length;
|
|
651394
|
+
const failed = warmUpResults.size - ok;
|
|
651395
|
+
return {
|
|
651396
|
+
outcome: "warmed",
|
|
651397
|
+
note: `${ok} combination${ok === 1 ? "" : "s"} ok${failed ? `, ${failed} failed` : ""}`
|
|
651398
|
+
};
|
|
651399
|
+
}
|
|
651400
|
+
case "chromedriver-prefetch":
|
|
651401
|
+
return prefetchMobileChromedriver({
|
|
651402
|
+
config,
|
|
651403
|
+
desc: task.payload.desc,
|
|
651404
|
+
deviceRegistry,
|
|
651405
|
+
getAndroidEnv,
|
|
651406
|
+
deps: {
|
|
651407
|
+
// The cache-mutating half (driver install + Appium co-homing)
|
|
651408
|
+
// runs once per run under the manual runtime-install lease, so
|
|
651409
|
+
// the prefetch task itself only holds its device tag while it
|
|
651410
|
+
// awaits readiness and runs the throwaway session.
|
|
651411
|
+
appSurfacePreflight: () => getAndroidPreflight(),
|
|
651412
|
+
acquireEmulatorLease: () => acquireLease(["android-emulator"])
|
|
651413
|
+
}
|
|
651414
|
+
});
|
|
651415
|
+
}
|
|
651416
|
+
};
|
|
651417
|
+
}
|
|
651418
|
+
async function prefetchMobileChromedriver({ config, desc, deviceRegistry, getAndroidEnv, deps = {} }) {
|
|
651419
|
+
const preflight = deps.appSurfacePreflight ?? appSurfacePreflight;
|
|
651420
|
+
const acquire = deps.acquireDevice ?? acquireDevice;
|
|
651421
|
+
const startServer = deps.startAppiumServer ?? startAppiumServer;
|
|
651422
|
+
const startDriver = deps.driverStart ?? driverStart;
|
|
651423
|
+
const kill4 = deps.killTree ?? killTree;
|
|
651424
|
+
const env = await getAndroidEnv();
|
|
651425
|
+
if (!env) {
|
|
651426
|
+
return {
|
|
651427
|
+
outcome: "skipped",
|
|
651428
|
+
note: "Android toolchain not ready; the first mobile-web session downloads chromedriver as needed"
|
|
651429
|
+
};
|
|
651430
|
+
}
|
|
651431
|
+
const pre = await preflight({ config, platform: "android" });
|
|
651432
|
+
if (!pre.ok)
|
|
651433
|
+
return { outcome: "skipped", note: pre.reason };
|
|
651434
|
+
const releaseLease = deps.acquireEmulatorLease ? await deps.acquireEmulatorLease() : void 0;
|
|
651435
|
+
let acquired;
|
|
651436
|
+
try {
|
|
651437
|
+
acquired = await acquire({
|
|
651438
|
+
desc,
|
|
651439
|
+
registry: deviceRegistry,
|
|
651440
|
+
sdkRoot: env.sdkRoot,
|
|
651441
|
+
deps: env.deviceDeps
|
|
651442
|
+
});
|
|
651443
|
+
} finally {
|
|
651444
|
+
releaseLease?.();
|
|
651445
|
+
}
|
|
651446
|
+
if ("skip" in acquired)
|
|
651447
|
+
return { outcome: "skipped", note: acquired.skip };
|
|
651448
|
+
let server;
|
|
651449
|
+
let driver;
|
|
651450
|
+
try {
|
|
651451
|
+
server = await startServer(pre.appiumEntry, config, void 0, {
|
|
651452
|
+
APPIUM_HOME: pre.appiumHome,
|
|
651453
|
+
ANDROID_HOME: env.sdkRoot,
|
|
651454
|
+
ANDROID_SDK_ROOT: env.sdkRoot
|
|
651455
|
+
}, CHROMEDRIVER_AUTODOWNLOAD_ARGS);
|
|
651456
|
+
driver = await startDriver(buildMobileBrowserCapabilities({
|
|
651457
|
+
platform: "android",
|
|
651458
|
+
udid: acquired.entry.udid,
|
|
651459
|
+
cacheDir: getCacheDir({ cacheDir: config?.cacheDir })
|
|
651460
|
+
}), server.port, 2, { cacheDir: config?.cacheDir });
|
|
651461
|
+
return {
|
|
651462
|
+
outcome: "warmed",
|
|
651463
|
+
note: `chromedriver ready for device '${acquired.entry.name}'`
|
|
651464
|
+
};
|
|
651465
|
+
} finally {
|
|
651466
|
+
if (driver) {
|
|
651467
|
+
try {
|
|
651468
|
+
await driver.deleteSession();
|
|
651469
|
+
} catch {
|
|
651470
|
+
}
|
|
651471
|
+
}
|
|
651472
|
+
if (server) {
|
|
651473
|
+
await kill4(server.process?.pid);
|
|
651474
|
+
}
|
|
651475
|
+
}
|
|
651476
|
+
}
|
|
650806
651477
|
function specIsRouted(spec) {
|
|
650807
651478
|
if (!spec || !Array.isArray(spec.tests))
|
|
650808
651479
|
return false;
|
|
@@ -651150,7 +651821,8 @@ async function runContext({ config, spec, test, context, runnerDetails, appiumPo
|
|
|
651150
651821
|
contextReport.resultDescription = errorMessage;
|
|
651151
651822
|
return contextReport;
|
|
651152
651823
|
}
|
|
651153
|
-
|
|
651824
|
+
if (logLevelEnabled(config, "debug"))
|
|
651825
|
+
clog("debug", `CONTEXT:
|
|
651154
651826
|
${JSON.stringify(context, null, 2)}`);
|
|
651155
651827
|
let driver;
|
|
651156
651828
|
let appiumPort;
|
|
@@ -651169,7 +651841,7 @@ ${JSON.stringify(context, null, 2)}`);
|
|
|
651169
651841
|
env.ANDROID_HOME = appSession.androidSdkRoot;
|
|
651170
651842
|
env.ANDROID_SDK_ROOT = appSession.androidSdkRoot;
|
|
651171
651843
|
}
|
|
651172
|
-
const extraArgs = mobileTarget === "android" ?
|
|
651844
|
+
const extraArgs = mobileTarget === "android" ? CHROMEDRIVER_AUTODOWNLOAD_ARGS : [];
|
|
651173
651845
|
let acquired;
|
|
651174
651846
|
try {
|
|
651175
651847
|
const server = await startAppiumServer(appSession.appiumEntry, config, void 0, env, extraArgs);
|
|
@@ -651462,7 +652134,8 @@ ${JSON.stringify(context, null, 2)}`);
|
|
|
651462
652134
|
stepExecutionFailed = true;
|
|
651463
652135
|
break;
|
|
651464
652136
|
}
|
|
651465
|
-
|
|
652137
|
+
if (logLevelEnabled(config, "debug"))
|
|
652138
|
+
clog("debug", `STEP:
|
|
651466
652139
|
${JSON.stringify(step, null, 2)}`);
|
|
651467
652140
|
if (step.unsafe && runnerDetails.allowUnsafeSteps === false) {
|
|
651468
652141
|
clog("warning", `Skipping unsafe step: ${step.description} in test ${test.testId} context ${context.contextId}`);
|
|
@@ -651528,7 +652201,8 @@ ${JSON.stringify(step, null, 2)}`);
|
|
|
651528
652201
|
processRegistry,
|
|
651529
652202
|
appSession
|
|
651530
652203
|
});
|
|
651531
|
-
|
|
652204
|
+
if (logLevelEnabled(config, "debug"))
|
|
652205
|
+
clog("debug", `RESULT: ${r.status}
|
|
651532
652206
|
${JSON.stringify(r, null, 2)}`);
|
|
651533
652207
|
r.result = r.status;
|
|
651534
652208
|
r.resultDescription = r.description;
|
|
@@ -651925,7 +652599,7 @@ async function runStep({ config = {}, context = {}, step, driver, metaValues = {
|
|
|
651925
652599
|
}
|
|
651926
652600
|
return actionResult;
|
|
651927
652601
|
}
|
|
651928
|
-
async function
|
|
652602
|
+
async function spawnAppiumServer(appiumEntry, config, display, extraEnv, extraArgs) {
|
|
651929
652603
|
const port = await findFreePort();
|
|
651930
652604
|
log(config, "debug", `Starting Appium on port ${port}`);
|
|
651931
652605
|
const env = display || extraEnv ? {
|
|
@@ -651945,31 +652619,41 @@ async function startAppiumServer(appiumEntry, config, display, extraEnv, extraAr
|
|
|
651945
652619
|
});
|
|
651946
652620
|
proc.stderr.on("data", () => {
|
|
651947
652621
|
});
|
|
652622
|
+
return { port, process: proc, display };
|
|
652623
|
+
}
|
|
652624
|
+
async function startAppiumServer(appiumEntry, config, display, extraEnv, extraArgs) {
|
|
652625
|
+
const server = await spawnAppiumServer(appiumEntry, config, display, extraEnv, extraArgs);
|
|
651948
652626
|
try {
|
|
651949
|
-
await appiumIsReady(port);
|
|
652627
|
+
await appiumIsReady(server.port);
|
|
651950
652628
|
} catch (error) {
|
|
651951
|
-
await killTree(
|
|
652629
|
+
await killTree(server.process?.pid);
|
|
651952
652630
|
throw error;
|
|
651953
652631
|
}
|
|
651954
|
-
log(config, "debug", `Appium is ready on port ${port}.`);
|
|
651955
|
-
return
|
|
652632
|
+
log(config, "debug", `Appium is ready on port ${server.port}.`);
|
|
652633
|
+
return server;
|
|
651956
652634
|
}
|
|
651957
|
-
|
|
651958
|
-
|
|
652635
|
+
var STATUS_PROBE_TIMEOUT_MS = 1e4;
|
|
652636
|
+
async function appiumIsReady(port, timeoutMs = 12e4, deps = {}) {
|
|
652637
|
+
const probe = deps.probe ?? (async (p) => {
|
|
652638
|
+
try {
|
|
652639
|
+
const resp = await import_axios6.default.get(`http://127.0.0.1:${p}/status`, {
|
|
652640
|
+
timeout: STATUS_PROBE_TIMEOUT_MS
|
|
652641
|
+
});
|
|
652642
|
+
return resp.status === 200;
|
|
652643
|
+
} catch {
|
|
652644
|
+
return false;
|
|
652645
|
+
}
|
|
652646
|
+
});
|
|
652647
|
+
const sleep4 = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
651959
652648
|
const start = Date.now();
|
|
651960
|
-
while (
|
|
652649
|
+
while (true) {
|
|
652650
|
+
if (await probe(port))
|
|
652651
|
+
return true;
|
|
651961
652652
|
if (Date.now() - start > timeoutMs) {
|
|
651962
652653
|
throw new Error(`Appium server on port ${port} failed to start within ${timeoutMs / 1e3} seconds`);
|
|
651963
652654
|
}
|
|
651964
|
-
await
|
|
651965
|
-
try {
|
|
651966
|
-
let resp = await import_axios6.default.get(`http://127.0.0.1:${port}/status`);
|
|
651967
|
-
if (resp.status === 200)
|
|
651968
|
-
isReady = true;
|
|
651969
|
-
} catch {
|
|
651970
|
-
}
|
|
652655
|
+
await sleep4(250);
|
|
651971
652656
|
}
|
|
651972
|
-
return isReady;
|
|
651973
652657
|
}
|
|
651974
652658
|
async function driverStart(capabilities, port, maxAttempts = 4, ctx = {}) {
|
|
651975
652659
|
const wdio = await loadHeavyDep("webdriverio", { ctx });
|
|
@@ -652159,6 +652843,8 @@ function telemetryNotice(config) {
|
|
|
652159
652843
|
log(config, "info", "Doc Detective collects basic anonymous telemetry to understand product issues and usage. To disable telemetry, set 'telemetry.send' to 'false' in your .doc-detective.json config file.");
|
|
652160
652844
|
}
|
|
652161
652845
|
}
|
|
652846
|
+
var TELEMETRY_FLUSH_TIMEOUT_MS = 2e3;
|
|
652847
|
+
var pendingTelemetryFlush = null;
|
|
652162
652848
|
function sendTelemetry(config, command, results) {
|
|
652163
652849
|
if (config?.telemetry?.send === false)
|
|
652164
652850
|
return;
|
|
@@ -652199,7 +652885,7 @@ function sendTelemetry(config, command, results) {
|
|
|
652199
652885
|
const event = { distinctId, event: command, properties: telemetryData };
|
|
652200
652886
|
const client = new import_posthog_node.PostHog("phc_rjV0MH3nsAd45zFISLgaKAdAXbgDeXt2mOBV2EBHomB", { host: "https://app.posthog.com" });
|
|
652201
652887
|
client.capture(event);
|
|
652202
|
-
client.shutdown();
|
|
652888
|
+
pendingTelemetryFlush = Promise.resolve(client.shutdown(TELEMETRY_FLUSH_TIMEOUT_MS)).then(() => void 0).catch(() => void 0);
|
|
652203
652889
|
}
|
|
652204
652890
|
|
|
652205
652891
|
// dist/core/index.js
|