@wdio/nightwatch-devtools 1.8.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -16
- package/dist/{bidi-WNZOXX5X.js → bidi-C67DYUCA.js} +4 -2
- package/dist/{bidi-WNZOXX5X.js.map → bidi-C67DYUCA.js.map} +1 -1
- package/dist/{chunk-DM4FCAIJ.js → chunk-DRZC45YG.js} +961 -251
- package/dist/chunk-DRZC45YG.js.map +1 -0
- package/dist/index.js +727 -285
- package/dist/index.js.map +1 -1
- package/package.json +10 -7
- package/dist/chunk-DM4FCAIJ.js.map +0 -1
|
@@ -12,10 +12,15 @@ var RUNNER_ENV = {
|
|
|
12
12
|
WDIO_CONFIG: "DEVTOOLS_WDIO_CONFIG",
|
|
13
13
|
NIGHTWATCH_CONFIG: "DEVTOOLS_NIGHTWATCH_CONFIG",
|
|
14
14
|
WDIO_INITIAL_SPECS: "DEVTOOLS_WDIO_INITIAL_SPECS",
|
|
15
|
+
// The selection the Nightwatch run was launched with (specs, --tag, --env, ...), without --config; see encodeInitialArgs.
|
|
16
|
+
NIGHTWATCH_INITIAL_ARGS: "DEVTOOLS_NIGHTWATCH_INITIAL_ARGS",
|
|
15
17
|
RUNNER_CWD: "DEVTOOLS_RUNNER_CWD",
|
|
16
18
|
WDIO_BIN: "DEVTOOLS_WDIO_BIN",
|
|
17
19
|
NIGHTWATCH_BIN: "DEVTOOLS_NIGHTWATCH_BIN"
|
|
18
20
|
};
|
|
21
|
+
function encodeInitialArgs(args) {
|
|
22
|
+
return JSON.stringify(args);
|
|
23
|
+
}
|
|
19
24
|
|
|
20
25
|
// ../core/src/error.ts
|
|
21
26
|
function toError(value) {
|
|
@@ -30,7 +35,11 @@ function toError(value) {
|
|
|
30
35
|
}
|
|
31
36
|
return e;
|
|
32
37
|
}
|
|
33
|
-
|
|
38
|
+
try {
|
|
39
|
+
return new Error(String(value));
|
|
40
|
+
} catch {
|
|
41
|
+
return new Error(Object.prototype.toString.call(value));
|
|
42
|
+
}
|
|
34
43
|
}
|
|
35
44
|
function errorMessage(value) {
|
|
36
45
|
if (value instanceof Error) {
|
|
@@ -248,6 +257,9 @@ import fs2 from "fs/promises";
|
|
|
248
257
|
import path2 from "path";
|
|
249
258
|
|
|
250
259
|
// ../shared/src/trace-actions.ts
|
|
260
|
+
function isWaitAction(action) {
|
|
261
|
+
return action?.method.startsWith("waitFor") ?? false;
|
|
262
|
+
}
|
|
251
263
|
var ASSERT_ACTION_CLASS = "Assert";
|
|
252
264
|
var TRACKED_ASSERT_METHODS = [
|
|
253
265
|
"equal",
|
|
@@ -334,6 +346,8 @@ var ACTION_MAP = {
|
|
|
334
346
|
waitForElementNotVisible: { class: "Element", method: "waitForHidden" },
|
|
335
347
|
waitForElementPresent: { class: "Element", method: "waitForExist" },
|
|
336
348
|
waitForElementNotPresent: { class: "Element", method: "waitForNotExist" },
|
|
349
|
+
// A Selenium wait on an element locator (`until.elementLocated`, `presence_of_element_located`), named by its adapter.
|
|
350
|
+
waitForElementLocated: { class: "Element", method: "waitForExist" },
|
|
337
351
|
// WDIO page/browser reads
|
|
338
352
|
getTitle: { class: "Page", method: "getTitle" },
|
|
339
353
|
getUrl: { class: "Page", method: "getUrl" },
|
|
@@ -344,6 +358,8 @@ var ACTION_MAP = {
|
|
|
344
358
|
getCssValue: { class: "Element", method: "getCSSProperty" },
|
|
345
359
|
getRect: { class: "Element", method: "getRect" },
|
|
346
360
|
getCurrentUrl: { class: "Page", method: "getUrl" },
|
|
361
|
+
// A Selenium wait on any condition other than an element locator.
|
|
362
|
+
wait: { class: "Browser", method: "waitForFunction" },
|
|
347
363
|
// Raw W3C protocol names. The JS adapters wrap a client library and report
|
|
348
364
|
// its method names, but an adapter that patches the protocol chokepoint —
|
|
349
365
|
// the Python one, and any future language binding — reports what WebDriver
|
|
@@ -420,6 +436,9 @@ function isInputDispatchingCommand(command) {
|
|
|
420
436
|
function mapCommandToAction(command) {
|
|
421
437
|
return ACTION_MAP[command] ?? mapAssertCommand(command);
|
|
422
438
|
}
|
|
439
|
+
function isWaitCommand(command) {
|
|
440
|
+
return isWaitAction(mapCommandToAction(command));
|
|
441
|
+
}
|
|
423
442
|
var ASSERT_TITLE_VALUE_MAX = 40;
|
|
424
443
|
function formatAssertValue(value) {
|
|
425
444
|
let text;
|
|
@@ -452,6 +471,29 @@ function formatActionTitle(action, args, params, command) {
|
|
|
452
471
|
}
|
|
453
472
|
var FILL_METHODS = /* @__PURE__ */ new Set(["fill", "selectOption"]);
|
|
454
473
|
|
|
474
|
+
// ../shared/src/browser-schemes.ts
|
|
475
|
+
var BROWSER_INTERNAL_SCHEMES = /* @__PURE__ */ new Set([
|
|
476
|
+
"about",
|
|
477
|
+
"chrome",
|
|
478
|
+
"chrome-error",
|
|
479
|
+
"chrome-extension",
|
|
480
|
+
"chrome-native",
|
|
481
|
+
"chrome-search",
|
|
482
|
+
"chrome-untrusted",
|
|
483
|
+
"devtools",
|
|
484
|
+
"edge",
|
|
485
|
+
"moz-extension",
|
|
486
|
+
"safari-web-extension"
|
|
487
|
+
]);
|
|
488
|
+
var SCHEME = /^([a-z][a-z0-9+.-]*):/;
|
|
489
|
+
function schemeOf(url) {
|
|
490
|
+
return SCHEME.exec(url.toLowerCase())?.[1];
|
|
491
|
+
}
|
|
492
|
+
function isBrowserInternalUrl(url) {
|
|
493
|
+
const scheme = schemeOf(url);
|
|
494
|
+
return scheme !== void 0 && (BROWSER_INTERNAL_SCHEMES.has(scheme) || scheme.startsWith("chrome-"));
|
|
495
|
+
}
|
|
496
|
+
|
|
455
497
|
// ../shared/src/console.ts
|
|
456
498
|
var CONSOLE_METHODS = ["log", "info", "warn", "error"];
|
|
457
499
|
var ANSI_REGEX = /\x1b\[[?]?[0-9;]*[A-Za-z]/g;
|
|
@@ -503,16 +545,6 @@ function detectLogLevel(text) {
|
|
|
503
545
|
function createConsoleLogEntry(type, args, source = LOG_SOURCES.TEST) {
|
|
504
546
|
return { timestamp: Date.now(), type, args, source };
|
|
505
547
|
}
|
|
506
|
-
function mapChromeBrowserLogs(entries) {
|
|
507
|
-
return entries.map((entry) => ({
|
|
508
|
-
timestamp: entry.timestamp,
|
|
509
|
-
type: chromeLogLevelToLogLevel(
|
|
510
|
-
entry.level
|
|
511
|
-
),
|
|
512
|
-
args: [entry.message],
|
|
513
|
-
source: LOG_SOURCES.BROWSER
|
|
514
|
-
}));
|
|
515
|
-
}
|
|
516
548
|
function chromeLogLevelToLogLevel(level) {
|
|
517
549
|
const levelName = (typeof level === "object" ? level?.name ?? "" : level ?? "").toUpperCase();
|
|
518
550
|
switch (levelName) {
|
|
@@ -561,6 +593,9 @@ function namesAnAutomation(caps) {
|
|
|
561
593
|
deepCapString(caps, "appium:automationName") ?? deepCapString(caps, "automationName")
|
|
562
594
|
);
|
|
563
595
|
}
|
|
596
|
+
function isCapabilityBag(value) {
|
|
597
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
598
|
+
}
|
|
564
599
|
function firstCapString(caps, keys, reject = () => false) {
|
|
565
600
|
for (const key of keys) {
|
|
566
601
|
const value = deepCapString(caps, key);
|
|
@@ -571,7 +606,7 @@ function firstCapString(caps, keys, reject = () => false) {
|
|
|
571
606
|
return void 0;
|
|
572
607
|
}
|
|
573
608
|
function deviceFromCapabilities(capabilities) {
|
|
574
|
-
if (!capabilities
|
|
609
|
+
if (!isCapabilityBag(capabilities)) {
|
|
575
610
|
return void 0;
|
|
576
611
|
}
|
|
577
612
|
const caps = capabilities;
|
|
@@ -595,7 +630,7 @@ function deviceFromCapabilities(capabilities) {
|
|
|
595
630
|
};
|
|
596
631
|
}
|
|
597
632
|
function isNativeAppSession(capabilities) {
|
|
598
|
-
if (!capabilities
|
|
633
|
+
if (!isCapabilityBag(capabilities)) {
|
|
599
634
|
return false;
|
|
600
635
|
}
|
|
601
636
|
const caps = capabilities;
|
|
@@ -1045,12 +1080,201 @@ function elementsScript(includeBounds, inViewportOnly, runner) {
|
|
|
1045
1080
|
})()`;
|
|
1046
1081
|
}
|
|
1047
1082
|
|
|
1083
|
+
// ../shared/src/page-scripts.ts
|
|
1084
|
+
var COLLECTOR_READY_EXPRESSION = 'typeof window.wdioTraceCollector !== "undefined"';
|
|
1085
|
+
var COLLECTOR_READY_SCRIPT = `return ${COLLECTOR_READY_EXPRESSION};`;
|
|
1086
|
+
var COLLECTOR_INJECT_SCRIPT = `var s=document.createElement('script');s.textContent=arguments[0];document.head.appendChild(s);${COLLECTOR_READY_SCRIPT}`;
|
|
1087
|
+
function collectorDrainExpression(forceAnchor = false) {
|
|
1088
|
+
const call = forceAnchor ? "window.wdioTraceCollector.captureCurrentDom();" : "";
|
|
1089
|
+
return `if (!(${COLLECTOR_READY_EXPRESSION})) { return null; } ${call} return window.wdioTraceCollector.getTraceData();`;
|
|
1090
|
+
}
|
|
1091
|
+
var CAPTURE_PERFORMANCE_SCRIPT = `
|
|
1092
|
+
return (function() {
|
|
1093
|
+
const performance = window.performance;
|
|
1094
|
+
const navigation = performance.getEntriesByType?.('navigation')?.[0];
|
|
1095
|
+
const resources = performance.getEntriesByType?.('resource') || [];
|
|
1096
|
+
|
|
1097
|
+
return {
|
|
1098
|
+
navigation: navigation ? {
|
|
1099
|
+
url: window.location.href,
|
|
1100
|
+
timing: {
|
|
1101
|
+
loadTime: navigation.loadEventEnd - navigation.fetchStart,
|
|
1102
|
+
domReady: navigation.domContentLoadedEventEnd - navigation.fetchStart,
|
|
1103
|
+
responseTime: navigation.responseEnd - navigation.requestStart,
|
|
1104
|
+
dnsLookup: navigation.domainLookupEnd - navigation.domainLookupStart,
|
|
1105
|
+
tcpConnection: navigation.connectEnd - navigation.connectStart,
|
|
1106
|
+
serverResponse: navigation.responseEnd - navigation.responseStart
|
|
1107
|
+
}
|
|
1108
|
+
} : undefined,
|
|
1109
|
+
resources: resources.map(function(resource) {
|
|
1110
|
+
return {
|
|
1111
|
+
url: resource.name,
|
|
1112
|
+
duration: resource.duration,
|
|
1113
|
+
size: resource.transferSize || 0,
|
|
1114
|
+
type: resource.initiatorType,
|
|
1115
|
+
startTime: resource.startTime,
|
|
1116
|
+
responseEnd: resource.responseEnd
|
|
1117
|
+
};
|
|
1118
|
+
}),
|
|
1119
|
+
cookies: (function() {
|
|
1120
|
+
try { return document.cookie; } catch (e) { return ''; }
|
|
1121
|
+
})(),
|
|
1122
|
+
documentInfo: {
|
|
1123
|
+
url: window.location.href,
|
|
1124
|
+
title: document.title,
|
|
1125
|
+
headers: {
|
|
1126
|
+
userAgent: navigator.userAgent,
|
|
1127
|
+
language: navigator.language,
|
|
1128
|
+
platform: navigator.platform
|
|
1129
|
+
},
|
|
1130
|
+
documentInfo: {
|
|
1131
|
+
readyState: document.readyState,
|
|
1132
|
+
referrer: document.referrer,
|
|
1133
|
+
characterSet: document.characterSet
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
})()
|
|
1138
|
+
`;
|
|
1139
|
+
|
|
1140
|
+
// ../shared/src/command-tree.ts
|
|
1141
|
+
function nestCommands(commands) {
|
|
1142
|
+
const nodes = commands.map((command) => ({
|
|
1143
|
+
command,
|
|
1144
|
+
children: []
|
|
1145
|
+
}));
|
|
1146
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1147
|
+
for (const node of nodes) {
|
|
1148
|
+
const { id } = node.command;
|
|
1149
|
+
if (typeof id === "number" && !byId.has(id)) {
|
|
1150
|
+
byId.set(id, node);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
const parentOf = (node) => {
|
|
1154
|
+
const { parentId } = node.command;
|
|
1155
|
+
return typeof parentId === "number" ? byId.get(parentId) : void 0;
|
|
1156
|
+
};
|
|
1157
|
+
const roots = [];
|
|
1158
|
+
for (const node of nodes) {
|
|
1159
|
+
const parent = parentOf(node);
|
|
1160
|
+
if (parent && !closesCycle(node, parentOf)) {
|
|
1161
|
+
parent.children.push(node);
|
|
1162
|
+
} else {
|
|
1163
|
+
roots.push(node);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
return roots;
|
|
1167
|
+
}
|
|
1168
|
+
function closesCycle(node, parentOf) {
|
|
1169
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1170
|
+
for (let at = parentOf(node); at && !seen.has(at); at = parentOf(at)) {
|
|
1171
|
+
if (at === node) {
|
|
1172
|
+
return true;
|
|
1173
|
+
}
|
|
1174
|
+
seen.add(at);
|
|
1175
|
+
}
|
|
1176
|
+
return false;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// ../shared/src/command-failure.ts
|
|
1180
|
+
function collapsedAssertResult(result) {
|
|
1181
|
+
if (typeof result === "object" && result !== null && "passed" in result) {
|
|
1182
|
+
return result;
|
|
1183
|
+
}
|
|
1184
|
+
return void 0;
|
|
1185
|
+
}
|
|
1186
|
+
function commandFailure(cmd, action) {
|
|
1187
|
+
if (cmd.error) {
|
|
1188
|
+
return errorFailure(cmd.error);
|
|
1189
|
+
}
|
|
1190
|
+
const collapsed = collapsedAssertResult(cmd.result);
|
|
1191
|
+
if (collapsed && collapsed.passed === false) {
|
|
1192
|
+
const isAssert = action.class === ASSERT_ACTION_CLASS;
|
|
1193
|
+
return {
|
|
1194
|
+
message: String(
|
|
1195
|
+
collapsed.message ?? (isAssert ? "Assertion failed" : `${cmd.command} failed`)
|
|
1196
|
+
)
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
if (cmd.result === false && isWaitAction(action)) {
|
|
1200
|
+
const target = cmd.args?.find((a) => typeof a === "string");
|
|
1201
|
+
return {
|
|
1202
|
+
message: target ? `${cmd.command} timed out waiting for ${String(target)}` : `${cmd.command} timed out`
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
return void 0;
|
|
1206
|
+
}
|
|
1207
|
+
function errorFailure(error) {
|
|
1208
|
+
return { message: error.message ?? String(error) };
|
|
1209
|
+
}
|
|
1210
|
+
function rowFailure(cmd) {
|
|
1211
|
+
const action = mapCommandToAction(cmd.command);
|
|
1212
|
+
if (action) {
|
|
1213
|
+
return commandFailure(cmd, action);
|
|
1214
|
+
}
|
|
1215
|
+
return cmd.error ? errorFailure(cmd.error) : void 0;
|
|
1216
|
+
}
|
|
1217
|
+
function retriedRows(commands) {
|
|
1218
|
+
const retried = /* @__PURE__ */ new Set();
|
|
1219
|
+
const walk = (nodes, underPassing) => {
|
|
1220
|
+
for (const { command, children } of nodes) {
|
|
1221
|
+
const failed = Boolean(rowFailure(command));
|
|
1222
|
+
if (underPassing && failed) {
|
|
1223
|
+
retried.add(command);
|
|
1224
|
+
}
|
|
1225
|
+
walk(children, underPassing || !failed);
|
|
1226
|
+
}
|
|
1227
|
+
};
|
|
1228
|
+
walk(nestCommands(commands), false);
|
|
1229
|
+
return retried;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1048
1232
|
// ../shared/src/image.ts
|
|
1049
1233
|
var PNG_BASE64_MAGIC = "iVBOR";
|
|
1050
1234
|
function imageMime(base64) {
|
|
1051
1235
|
return base64.startsWith(PNG_BASE64_MAGIC) ? "image/png" : "image/jpeg";
|
|
1052
1236
|
}
|
|
1053
1237
|
|
|
1238
|
+
// ../shared/src/request-type.ts
|
|
1239
|
+
function getRequestType(url, mimeType) {
|
|
1240
|
+
const contentType = mimeType?.toLowerCase() ?? "";
|
|
1241
|
+
const urlLower = url.toLowerCase();
|
|
1242
|
+
if (contentType.includes("text/html")) {
|
|
1243
|
+
return "document";
|
|
1244
|
+
}
|
|
1245
|
+
if (contentType.includes("text/css")) {
|
|
1246
|
+
return "stylesheet";
|
|
1247
|
+
}
|
|
1248
|
+
if (contentType.includes("javascript") || contentType.includes("ecmascript")) {
|
|
1249
|
+
return "script";
|
|
1250
|
+
}
|
|
1251
|
+
if (contentType.includes("image/")) {
|
|
1252
|
+
return "image";
|
|
1253
|
+
}
|
|
1254
|
+
if (contentType.includes("font/") || contentType.includes("woff")) {
|
|
1255
|
+
return "font";
|
|
1256
|
+
}
|
|
1257
|
+
if (contentType.includes("application/json")) {
|
|
1258
|
+
return "fetch";
|
|
1259
|
+
}
|
|
1260
|
+
if (urlLower.endsWith(".html") || urlLower.endsWith(".htm")) {
|
|
1261
|
+
return "document";
|
|
1262
|
+
}
|
|
1263
|
+
if (urlLower.endsWith(".css")) {
|
|
1264
|
+
return "stylesheet";
|
|
1265
|
+
}
|
|
1266
|
+
if (urlLower.endsWith(".js") || urlLower.endsWith(".mjs")) {
|
|
1267
|
+
return "script";
|
|
1268
|
+
}
|
|
1269
|
+
if (/\.(png|jpg|jpeg|gif|svg|webp|ico)$/.test(urlLower)) {
|
|
1270
|
+
return "image";
|
|
1271
|
+
}
|
|
1272
|
+
if (/\.(woff|woff2|ttf|eot|otf)$/.test(urlLower)) {
|
|
1273
|
+
return "font";
|
|
1274
|
+
}
|
|
1275
|
+
return "xhr";
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1054
1278
|
// ../shared/src/routes.ts
|
|
1055
1279
|
var WS_PATHS = {
|
|
1056
1280
|
/** Adapter session upgrade endpoint. One socket per running adapter. */
|
|
@@ -1147,6 +1371,9 @@ var TEST_STATE = {
|
|
|
1147
1371
|
FAILED: "failed",
|
|
1148
1372
|
SKIPPED: "skipped"
|
|
1149
1373
|
};
|
|
1374
|
+
var NETWORK_CAPTURE_SOURCE = {
|
|
1375
|
+
RESOURCE_TIMING: "resource-timing"
|
|
1376
|
+
};
|
|
1150
1377
|
var SCREENCAST_DEFAULTS = {
|
|
1151
1378
|
enabled: false,
|
|
1152
1379
|
captureFormat: "jpeg",
|
|
@@ -1518,7 +1745,7 @@ function splitNumericSuffix(value) {
|
|
|
1518
1745
|
return { rest: value.slice(0, sep), num: Number(digits) };
|
|
1519
1746
|
}
|
|
1520
1747
|
function callSourceToStack(callSource) {
|
|
1521
|
-
if (!callSource
|
|
1748
|
+
if (!callSource) {
|
|
1522
1749
|
return void 0;
|
|
1523
1750
|
}
|
|
1524
1751
|
const last = splitNumericSuffix(callSource);
|
|
@@ -1551,28 +1778,28 @@ function ownTitle(title, parent) {
|
|
|
1551
1778
|
return title.slice(parent.title.length).trim() || title;
|
|
1552
1779
|
}
|
|
1553
1780
|
function buildGroupPath(cmd, testMetadata) {
|
|
1554
|
-
const
|
|
1781
|
+
const path11 = [];
|
|
1555
1782
|
if (cmd.testUid) {
|
|
1556
1783
|
const entry = testMetadata?.get(cmd.testUid);
|
|
1557
1784
|
for (const ancestor of entry?.ancestry ?? []) {
|
|
1558
|
-
|
|
1785
|
+
path11.push({
|
|
1559
1786
|
uid: ancestor.uid,
|
|
1560
|
-
title: ownTitle(ancestor.title,
|
|
1787
|
+
title: ownTitle(ancestor.title, path11[path11.length - 1])
|
|
1561
1788
|
});
|
|
1562
1789
|
}
|
|
1563
|
-
|
|
1790
|
+
path11.push({
|
|
1564
1791
|
uid: cmd.testUid,
|
|
1565
|
-
title: ownTitle(entry?.title ?? cmd.testUid,
|
|
1792
|
+
title: ownTitle(entry?.title ?? cmd.testUid, path11[path11.length - 1])
|
|
1566
1793
|
});
|
|
1567
1794
|
}
|
|
1568
1795
|
if (cmd.stepUid) {
|
|
1569
1796
|
const stepEntry = testMetadata?.get(cmd.stepUid);
|
|
1570
|
-
|
|
1797
|
+
path11.push({
|
|
1571
1798
|
uid: cmd.stepUid,
|
|
1572
|
-
title: ownTitle(stepEntry?.title ?? cmd.stepUid,
|
|
1799
|
+
title: ownTitle(stepEntry?.title ?? cmd.stepUid, path11[path11.length - 1])
|
|
1573
1800
|
});
|
|
1574
1801
|
}
|
|
1575
|
-
return
|
|
1802
|
+
return path11;
|
|
1576
1803
|
}
|
|
1577
1804
|
|
|
1578
1805
|
// ../trace/src/trace-action-events.ts
|
|
@@ -1591,12 +1818,6 @@ function serializableResult(result) {
|
|
|
1591
1818
|
return void 0;
|
|
1592
1819
|
}
|
|
1593
1820
|
}
|
|
1594
|
-
function collapsedAssertResult(result) {
|
|
1595
|
-
if (typeof result === "object" && result !== null && "passed" in result) {
|
|
1596
|
-
return result;
|
|
1597
|
-
}
|
|
1598
|
-
return void 0;
|
|
1599
|
-
}
|
|
1600
1821
|
function buildAssertParams(cmd) {
|
|
1601
1822
|
const params = Object.fromEntries(
|
|
1602
1823
|
cmd.args.map((arg, index) => [String(index), arg])
|
|
@@ -1689,28 +1910,6 @@ function buildParamsAndTitle(action, cmd) {
|
|
|
1689
1910
|
)
|
|
1690
1911
|
};
|
|
1691
1912
|
}
|
|
1692
|
-
function actionError(cmd, action) {
|
|
1693
|
-
if (cmd.error) {
|
|
1694
|
-
const err = cmd.error;
|
|
1695
|
-
return { message: err.message ?? String(cmd.error) };
|
|
1696
|
-
}
|
|
1697
|
-
const isAssert = action.class === ASSERT_ACTION_CLASS;
|
|
1698
|
-
const collapsed = collapsedAssertResult(cmd.result);
|
|
1699
|
-
if (collapsed && collapsed.passed === false) {
|
|
1700
|
-
return {
|
|
1701
|
-
message: String(
|
|
1702
|
-
collapsed.message ?? (isAssert ? "Assertion failed" : `${cmd.command} failed`)
|
|
1703
|
-
)
|
|
1704
|
-
};
|
|
1705
|
-
}
|
|
1706
|
-
if (cmd.result === false && action.method.startsWith("waitFor")) {
|
|
1707
|
-
const target = cmd.args?.find((a) => typeof a === "string");
|
|
1708
|
-
return {
|
|
1709
|
-
message: target ? `${cmd.command} timed out waiting for ${String(target)}` : `${cmd.command} timed out`
|
|
1710
|
-
};
|
|
1711
|
-
}
|
|
1712
|
-
return void 0;
|
|
1713
|
-
}
|
|
1714
1913
|
function resolveActionPoint(action, cmd, snapshotIndex) {
|
|
1715
1914
|
if (action.class !== "Element" || !POINTABLE_METHODS.has(action.method)) {
|
|
1716
1915
|
return void 0;
|
|
@@ -1729,10 +1928,13 @@ function resolveActionPoint(action, cmd, snapshotIndex) {
|
|
|
1729
1928
|
}
|
|
1730
1929
|
return void 0;
|
|
1731
1930
|
}
|
|
1732
|
-
function buildAfterEvent(cmd, action, callId, endMs,
|
|
1931
|
+
function buildAfterEvent(cmd, action, callId, endMs, ctx) {
|
|
1932
|
+
const { snapshotIndex } = ctx;
|
|
1733
1933
|
const afterEvent = { type: "after", callId, endTime: endMs };
|
|
1734
|
-
const error =
|
|
1735
|
-
if (error) {
|
|
1934
|
+
const error = commandFailure(cmd, action);
|
|
1935
|
+
if (error && ctx.retried.has(cmd)) {
|
|
1936
|
+
afterEvent.retriedError = error;
|
|
1937
|
+
} else if (error) {
|
|
1736
1938
|
afterEvent.error = error;
|
|
1737
1939
|
}
|
|
1738
1940
|
const result = serializableResult(cmd.result);
|
|
@@ -1749,13 +1951,11 @@ function buildAfterEvent(cmd, action, callId, endMs, snapshotIndex) {
|
|
|
1749
1951
|
}
|
|
1750
1952
|
return afterEvent;
|
|
1751
1953
|
}
|
|
1752
|
-
function
|
|
1954
|
+
function pushBefore(stream, cmd, action, pageId, wallTime, parentCallId, snapshotIndex) {
|
|
1753
1955
|
stream.callCounter++;
|
|
1754
1956
|
const callId = `call@${stream.callCounter}`;
|
|
1755
1957
|
const rawStartMs = (cmd.startTime ?? cmd.timestamp) - wallTime;
|
|
1756
|
-
const rawEndMs = cmd.timestamp - wallTime;
|
|
1757
1958
|
const startMs = Math.max(stream.prevEndMs, rawStartMs);
|
|
1758
|
-
const endMs = Math.max(startMs + 1, rawEndMs);
|
|
1759
1959
|
const { params, title } = buildParamsAndTitle(action, cmd);
|
|
1760
1960
|
const beforeEvent = {
|
|
1761
1961
|
type: "before",
|
|
@@ -1767,7 +1967,7 @@ function pushActionPair(stream, cmd, action, pageId, wallTime, snapshotIndex) {
|
|
|
1767
1967
|
params,
|
|
1768
1968
|
title,
|
|
1769
1969
|
apiName: `${action.class.toLowerCase()}.${action.method}`,
|
|
1770
|
-
parentId: stream.openGroups[stream.openGroups.length - 1]?.callId
|
|
1970
|
+
parentId: parentCallId ?? stream.openGroups[stream.openGroups.length - 1]?.callId
|
|
1771
1971
|
};
|
|
1772
1972
|
const stack = callSourceToStack(cmd.callSource);
|
|
1773
1973
|
if (stack) {
|
|
@@ -1778,7 +1978,38 @@ function pushActionPair(stream, cmd, action, pageId, wallTime, snapshotIndex) {
|
|
|
1778
1978
|
beforeEvent.beforeSnapshot = beforeName;
|
|
1779
1979
|
}
|
|
1780
1980
|
stream.events.push(beforeEvent);
|
|
1781
|
-
|
|
1981
|
+
return { callId, startMs };
|
|
1982
|
+
}
|
|
1983
|
+
function emitNode(stream, node, ctx, parentCallId) {
|
|
1984
|
+
const cmd = node.command;
|
|
1985
|
+
const action = mapCommandToAction(cmd.command);
|
|
1986
|
+
if (!action) {
|
|
1987
|
+
for (const child of node.children) {
|
|
1988
|
+
emitNode(stream, child, ctx, parentCallId);
|
|
1989
|
+
}
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
const { callId, startMs } = pushBefore(
|
|
1993
|
+
stream,
|
|
1994
|
+
cmd,
|
|
1995
|
+
action,
|
|
1996
|
+
ctx.pageId,
|
|
1997
|
+
ctx.wallTime,
|
|
1998
|
+
parentCallId,
|
|
1999
|
+
ctx.snapshotIndex
|
|
2000
|
+
);
|
|
2001
|
+
if (node.children.length) {
|
|
2002
|
+
stream.prevEndMs = startMs;
|
|
2003
|
+
for (const child of node.children) {
|
|
2004
|
+
emitNode(stream, child, ctx, callId);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
const endMs = Math.max(
|
|
2008
|
+
startMs + 1,
|
|
2009
|
+
cmd.timestamp - ctx.wallTime,
|
|
2010
|
+
node.children.length ? stream.prevEndMs : 0
|
|
2011
|
+
);
|
|
2012
|
+
stream.events.push(buildAfterEvent(cmd, action, callId, endMs, ctx));
|
|
1782
2013
|
stream.prevEndMs = endMs;
|
|
1783
2014
|
}
|
|
1784
2015
|
function buildActionEvents(commands, pageId, wallTime, testMetadata, snapshotIndex) {
|
|
@@ -1791,20 +2022,42 @@ function buildActionEvents(commands, pageId, wallTime, testMetadata, snapshotInd
|
|
|
1791
2022
|
const ordered = [...commands].sort(
|
|
1792
2023
|
(a, b) => (a.startTime ?? a.timestamp) - (b.startTime ?? b.timestamp) || (a.sequence ?? 0) - (b.sequence ?? 0)
|
|
1793
2024
|
);
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
2025
|
+
const ctx = {
|
|
2026
|
+
pageId,
|
|
2027
|
+
wallTime,
|
|
2028
|
+
snapshotIndex,
|
|
2029
|
+
retried: retriedRows(ordered)
|
|
2030
|
+
};
|
|
2031
|
+
for (const node of nestCommands(ordered)) {
|
|
2032
|
+
if (hasAction(node)) {
|
|
2033
|
+
syncGroups(stream, node.command, pageId, wallTime, testMetadata);
|
|
1798
2034
|
}
|
|
1799
|
-
|
|
1800
|
-
pushActionPair(stream, cmd, action, pageId, wallTime, snapshotIndex);
|
|
2035
|
+
emitNode(stream, node, ctx);
|
|
1801
2036
|
}
|
|
1802
2037
|
closeGroupsFrom(stream, 0);
|
|
1803
2038
|
return stream.events;
|
|
1804
2039
|
}
|
|
2040
|
+
function hasAction(node) {
|
|
2041
|
+
return Boolean(mapCommandToAction(node.command.command)) || node.children.some(hasAction);
|
|
2042
|
+
}
|
|
1805
2043
|
|
|
1806
2044
|
// ../trace/src/trace-har.ts
|
|
1807
2045
|
var INLINE_BODY_TEXT_MAX_BYTES = 8 * 1024;
|
|
2046
|
+
var HAR_PHASE_NOT_APPLICABLE = -1;
|
|
2047
|
+
function toHarTimings(timings, duration) {
|
|
2048
|
+
if (!timings) {
|
|
2049
|
+
return { send: 0, wait: Math.max(0, duration), receive: 0 };
|
|
2050
|
+
}
|
|
2051
|
+
return {
|
|
2052
|
+
blocked: timings.blocked ?? HAR_PHASE_NOT_APPLICABLE,
|
|
2053
|
+
dns: timings.dns ?? HAR_PHASE_NOT_APPLICABLE,
|
|
2054
|
+
connect: timings.connect ?? HAR_PHASE_NOT_APPLICABLE,
|
|
2055
|
+
ssl: timings.ssl ?? HAR_PHASE_NOT_APPLICABLE,
|
|
2056
|
+
send: timings.send ?? 0,
|
|
2057
|
+
wait: timings.wait ?? 0,
|
|
2058
|
+
receive: timings.receive ?? 0
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
1808
2061
|
function toHeaderArray(h) {
|
|
1809
2062
|
if (!h) {
|
|
1810
2063
|
return [];
|
|
@@ -1868,11 +2121,9 @@ function networkRequestToHar(entry, opts = {}) {
|
|
|
1868
2121
|
bodySize: entry.size ?? -1
|
|
1869
2122
|
},
|
|
1870
2123
|
cache: {},
|
|
1871
|
-
timings:
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
receive: 0
|
|
1875
|
-
}
|
|
2124
|
+
timings: toHarTimings(entry.timings, duration),
|
|
2125
|
+
_resourceType: entry.type,
|
|
2126
|
+
...entry.source ? { _source: entry.source } : {}
|
|
1876
2127
|
}
|
|
1877
2128
|
};
|
|
1878
2129
|
}
|
|
@@ -1989,6 +2240,7 @@ function capturedSteps(commands) {
|
|
|
1989
2240
|
function generateTranscript(commands, startWallTime, title) {
|
|
1990
2241
|
const wallTimeISO = new Date(startWallTime).toISOString();
|
|
1991
2242
|
const lines = [`# ${title ?? "Session"} \u2014 ${wallTimeISO}`, ""];
|
|
2243
|
+
const retried = retriedRows(commands);
|
|
1992
2244
|
capturedSteps(commands).forEach(({ entry, action }, idx) => {
|
|
1993
2245
|
const rawArgs = entry.args;
|
|
1994
2246
|
const parts = [stripAnsi(formatActionTitle(action, rawArgs))];
|
|
@@ -1999,7 +2251,8 @@ function generateTranscript(commands, startWallTime, title) {
|
|
|
1999
2251
|
}
|
|
2000
2252
|
}
|
|
2001
2253
|
if (entry.error) {
|
|
2002
|
-
|
|
2254
|
+
const label = retried.has(entry) ? "RETRIED" : "ERROR";
|
|
2255
|
+
parts.push(`${label}: ${errorMessage2(entry.error)}`);
|
|
2003
2256
|
}
|
|
2004
2257
|
lines.push(asNumberedItem(`${idx + 1}. `, parts.join(" ")));
|
|
2005
2258
|
});
|
|
@@ -2741,7 +2994,7 @@ async function maybeWriteManifest(ctx, fanOutArtifacts) {
|
|
|
2741
2994
|
}
|
|
2742
2995
|
const artifacts = ctx.collectedArtifacts ?? fanOutArtifacts;
|
|
2743
2996
|
try {
|
|
2744
|
-
const
|
|
2997
|
+
const path11 = await writeArtifactsManifest(
|
|
2745
2998
|
ctx.resolveOutputDir(),
|
|
2746
2999
|
buildArtifactsManifest({
|
|
2747
3000
|
sessionId: ctx.sessionId,
|
|
@@ -2750,7 +3003,7 @@ async function maybeWriteManifest(ctx, fanOutArtifacts) {
|
|
|
2750
3003
|
testMetadata: ctx.testMetadata
|
|
2751
3004
|
})
|
|
2752
3005
|
);
|
|
2753
|
-
ctx.log?.("info", `Artifacts manifest written to ${
|
|
3006
|
+
ctx.log?.("info", `Artifacts manifest written to ${path11}`);
|
|
2754
3007
|
} catch (err) {
|
|
2755
3008
|
ctx.log?.(
|
|
2756
3009
|
"warn",
|
|
@@ -2764,48 +3017,6 @@ import { createRequire } from "module";
|
|
|
2764
3017
|
|
|
2765
3018
|
// ../core/src/net.ts
|
|
2766
3019
|
import * as net from "net";
|
|
2767
|
-
|
|
2768
|
-
// ../core/src/request-type.ts
|
|
2769
|
-
function getRequestType(url, mimeType) {
|
|
2770
|
-
const contentType = mimeType?.toLowerCase() ?? "";
|
|
2771
|
-
const urlLower = url.toLowerCase();
|
|
2772
|
-
if (contentType.includes("text/html")) {
|
|
2773
|
-
return "document";
|
|
2774
|
-
}
|
|
2775
|
-
if (contentType.includes("text/css")) {
|
|
2776
|
-
return "stylesheet";
|
|
2777
|
-
}
|
|
2778
|
-
if (contentType.includes("javascript") || contentType.includes("ecmascript")) {
|
|
2779
|
-
return "script";
|
|
2780
|
-
}
|
|
2781
|
-
if (contentType.includes("image/")) {
|
|
2782
|
-
return "image";
|
|
2783
|
-
}
|
|
2784
|
-
if (contentType.includes("font/") || contentType.includes("woff")) {
|
|
2785
|
-
return "font";
|
|
2786
|
-
}
|
|
2787
|
-
if (contentType.includes("application/json")) {
|
|
2788
|
-
return "fetch";
|
|
2789
|
-
}
|
|
2790
|
-
if (urlLower.endsWith(".html") || urlLower.endsWith(".htm")) {
|
|
2791
|
-
return "document";
|
|
2792
|
-
}
|
|
2793
|
-
if (urlLower.endsWith(".css")) {
|
|
2794
|
-
return "stylesheet";
|
|
2795
|
-
}
|
|
2796
|
-
if (urlLower.endsWith(".js") || urlLower.endsWith(".mjs")) {
|
|
2797
|
-
return "script";
|
|
2798
|
-
}
|
|
2799
|
-
if (/\.(png|jpg|jpeg|gif|svg|webp|ico)$/.test(urlLower)) {
|
|
2800
|
-
return "image";
|
|
2801
|
-
}
|
|
2802
|
-
if (/\.(woff|woff2|ttf|eot|otf)$/.test(urlLower)) {
|
|
2803
|
-
return "font";
|
|
2804
|
-
}
|
|
2805
|
-
return "xhr";
|
|
2806
|
-
}
|
|
2807
|
-
|
|
2808
|
-
// ../core/src/net.ts
|
|
2809
3020
|
function isPortInUse(port, hostname) {
|
|
2810
3021
|
return new Promise((resolve) => {
|
|
2811
3022
|
const server = net.createServer();
|
|
@@ -2893,34 +3104,56 @@ function bidiResponseTiming(timings, startTime, timestamp) {
|
|
|
2893
3104
|
const endTime = Number(timestamp ?? Date.now());
|
|
2894
3105
|
return { endTime, time: Math.max(0, endTime - startTime) };
|
|
2895
3106
|
}
|
|
2896
|
-
|
|
3107
|
+
var MAX_TRACKED_REQUESTS = 5e3;
|
|
3108
|
+
function remember(rows, id, entry) {
|
|
3109
|
+
rows.set(id, entry);
|
|
3110
|
+
if (rows.size <= MAX_TRACKED_REQUESTS) {
|
|
3111
|
+
return;
|
|
3112
|
+
}
|
|
3113
|
+
for (const [key, row] of rows) {
|
|
3114
|
+
if (row.status !== void 0) {
|
|
3115
|
+
rows.delete(key);
|
|
3116
|
+
return;
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
rows.delete(rows.keys().next().value);
|
|
3120
|
+
}
|
|
3121
|
+
function handleBidiRequestSent(rawEvent, rows, sinks, log) {
|
|
2897
3122
|
const event = rawEvent;
|
|
2898
3123
|
try {
|
|
2899
3124
|
const requestId = String(event?.request?.request ?? event?.id ?? "");
|
|
2900
|
-
|
|
3125
|
+
const shape = rawEvent;
|
|
3126
|
+
if (!requestId || shape?.response || shape?.errorText) {
|
|
2901
3127
|
return;
|
|
2902
3128
|
}
|
|
3129
|
+
const previous = rows.get(requestId);
|
|
2903
3130
|
const entry = {
|
|
2904
3131
|
id: requestId,
|
|
2905
3132
|
url: event?.request?.url ?? "",
|
|
2906
3133
|
method: event?.request?.method ?? "GET",
|
|
2907
3134
|
requestHeaders: arrayHeadersToObject(event?.request?.headers),
|
|
2908
|
-
|
|
2909
|
-
|
|
3135
|
+
// A redirect hop re-sends the request under the same id: one row, which
|
|
3136
|
+
// keeps the clock of the hop it follows and reopens for the next answer.
|
|
3137
|
+
timestamp: previous?.timestamp ?? Date.now(),
|
|
3138
|
+
startTime: previous?.startTime ?? Number(event?.timestamp ?? Date.now()),
|
|
2910
3139
|
type: getRequestType(event?.request?.url ?? "")
|
|
2911
3140
|
};
|
|
2912
|
-
|
|
2913
|
-
|
|
3141
|
+
remember(rows, requestId, entry);
|
|
3142
|
+
if (previous) {
|
|
3143
|
+
sinks.replaceNetworkRequest(requestId, entry);
|
|
3144
|
+
} else {
|
|
3145
|
+
sinks.pushNetworkRequest(entry);
|
|
3146
|
+
}
|
|
2914
3147
|
} catch (err) {
|
|
2915
3148
|
log("warn", `beforeRequestSent threw: ${errorMessage(err)}`);
|
|
2916
3149
|
}
|
|
2917
3150
|
}
|
|
2918
|
-
function handleBidiResponseCompleted(rawEvent,
|
|
3151
|
+
function handleBidiResponseCompleted(rawEvent, rows, sinks, log) {
|
|
2919
3152
|
const event = rawEvent;
|
|
2920
3153
|
try {
|
|
2921
3154
|
const requestId = String(event?.request?.request ?? event?.id ?? "");
|
|
2922
|
-
const previous =
|
|
2923
|
-
if (!previous) {
|
|
3155
|
+
const previous = rows.get(requestId);
|
|
3156
|
+
if (!previous || !event?.response) {
|
|
2924
3157
|
return;
|
|
2925
3158
|
}
|
|
2926
3159
|
const { endTime, time } = bidiResponseTiming(
|
|
@@ -2935,25 +3168,78 @@ function handleBidiResponseCompleted(rawEvent, pending, sinks, log) {
|
|
|
2935
3168
|
responseHeaders: arrayHeadersToObject(event?.response?.headers),
|
|
2936
3169
|
type: getRequestType(previous.url, event?.response?.mimeType),
|
|
2937
3170
|
endTime,
|
|
2938
|
-
time,
|
|
2939
|
-
size: Number(event?.response?.bytesReceived) || void 0
|
|
3171
|
+
time,
|
|
3172
|
+
size: Number(event?.response?.bytesReceived) || void 0
|
|
3173
|
+
};
|
|
3174
|
+
remember(rows, requestId, finalized);
|
|
3175
|
+
sinks.replaceNetworkRequest(requestId, finalized);
|
|
3176
|
+
} catch (err) {
|
|
3177
|
+
log("warn", `responseCompleted threw: ${errorMessage(err)}`);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
function handleBidiFetchError(rawEvent, rows, sinks, log) {
|
|
3181
|
+
const event = rawEvent;
|
|
3182
|
+
try {
|
|
3183
|
+
const requestId = String(event?.request?.request ?? event?.id ?? "");
|
|
3184
|
+
const previous = rows.get(requestId);
|
|
3185
|
+
if (!previous || typeof event?.errorText !== "string") {
|
|
3186
|
+
return;
|
|
3187
|
+
}
|
|
3188
|
+
const { endTime, time } = bidiResponseTiming(
|
|
3189
|
+
event?.request?.timings,
|
|
3190
|
+
previous.startTime,
|
|
3191
|
+
event?.timestamp
|
|
3192
|
+
);
|
|
3193
|
+
const errorText = event?.errorText ?? "Failed";
|
|
3194
|
+
const finalized = {
|
|
3195
|
+
...previous,
|
|
3196
|
+
status: 0,
|
|
3197
|
+
statusText: errorText,
|
|
3198
|
+
error: errorText,
|
|
3199
|
+
endTime,
|
|
3200
|
+
time
|
|
2940
3201
|
};
|
|
2941
|
-
|
|
3202
|
+
remember(rows, requestId, finalized);
|
|
2942
3203
|
sinks.replaceNetworkRequest(requestId, finalized);
|
|
2943
3204
|
} catch (err) {
|
|
2944
|
-
log("warn", `
|
|
3205
|
+
log("warn", `fetchError threw: ${errorMessage(err)}`);
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
async function subscribeFetchErrors(inspector, rows, sinks, log) {
|
|
3209
|
+
if (typeof inspector.fetchError === "function") {
|
|
3210
|
+
await inspector.fetchError((e) => handleBidiFetchError(e, rows, sinks, log));
|
|
3211
|
+
return;
|
|
3212
|
+
}
|
|
3213
|
+
const bidi = inspector.bidi;
|
|
3214
|
+
if (typeof bidi?.subscribe !== "function" || !bidi.socket?.on) {
|
|
3215
|
+
return;
|
|
2945
3216
|
}
|
|
3217
|
+
await bidi.subscribe("network.fetchError");
|
|
3218
|
+
bidi.socket.on("message", (raw) => {
|
|
3219
|
+
try {
|
|
3220
|
+
const { method, params } = JSON.parse(String(raw));
|
|
3221
|
+
if (method === "network.fetchError") {
|
|
3222
|
+
handleBidiFetchError(params, rows, sinks, log);
|
|
3223
|
+
}
|
|
3224
|
+
} catch {
|
|
3225
|
+
}
|
|
3226
|
+
});
|
|
2946
3227
|
}
|
|
2947
3228
|
async function attachNetworkInspector(driver, factory, sinks, log) {
|
|
2948
3229
|
try {
|
|
2949
3230
|
const inspector = await factory(driver);
|
|
2950
|
-
const
|
|
3231
|
+
const rows = /* @__PURE__ */ new Map();
|
|
2951
3232
|
await inspector.beforeRequestSent(
|
|
2952
|
-
(e) => handleBidiRequestSent(e,
|
|
3233
|
+
(e) => handleBidiRequestSent(e, rows, sinks, log)
|
|
2953
3234
|
);
|
|
2954
3235
|
await inspector.responseCompleted(
|
|
2955
|
-
(e) => handleBidiResponseCompleted(e,
|
|
3236
|
+
(e) => handleBidiResponseCompleted(e, rows, sinks, log)
|
|
2956
3237
|
);
|
|
3238
|
+
try {
|
|
3239
|
+
await subscribeFetchErrors(inspector, rows, sinks, log);
|
|
3240
|
+
} catch (err) {
|
|
3241
|
+
log("warn", `BiDi network.fetchError unavailable: ${errorMessage(err)}`);
|
|
3242
|
+
}
|
|
2957
3243
|
log("info", "\u2713 BiDi NetworkInspector attached (request + response)");
|
|
2958
3244
|
return true;
|
|
2959
3245
|
} catch (err) {
|
|
@@ -3036,7 +3322,7 @@ function resolveBaseDir(input) {
|
|
|
3036
3322
|
if (!dir) {
|
|
3037
3323
|
continue;
|
|
3038
3324
|
}
|
|
3039
|
-
if (dir.includes(NODE_MODULES_SEGMENT)) {
|
|
3325
|
+
if (`${dir}${path4.sep}`.includes(NODE_MODULES_SEGMENT)) {
|
|
3040
3326
|
continue;
|
|
3041
3327
|
}
|
|
3042
3328
|
if (isWritable(dir)) {
|
|
@@ -3111,6 +3397,144 @@ function serializeWebSnapshot(nodes, context, options = {}) {
|
|
|
3111
3397
|
// ../core/src/locators/xml-parsing.ts
|
|
3112
3398
|
import { DOMParser } from "@xmldom/xmldom";
|
|
3113
3399
|
import xpath from "xpath";
|
|
3400
|
+
|
|
3401
|
+
// ../core/src/locators/xpath-index.ts
|
|
3402
|
+
var NAME = /[A-Za-z_][\w.-]*/y;
|
|
3403
|
+
var active = null;
|
|
3404
|
+
function parseSimpleXPath(expr) {
|
|
3405
|
+
if (!expr.startsWith("//")) {
|
|
3406
|
+
return null;
|
|
3407
|
+
}
|
|
3408
|
+
let pos = 2;
|
|
3409
|
+
let tag;
|
|
3410
|
+
if (expr[pos] === "*") {
|
|
3411
|
+
tag = "*";
|
|
3412
|
+
pos++;
|
|
3413
|
+
} else {
|
|
3414
|
+
NAME.lastIndex = pos;
|
|
3415
|
+
const m = NAME.exec(expr);
|
|
3416
|
+
if (!m) {
|
|
3417
|
+
return null;
|
|
3418
|
+
}
|
|
3419
|
+
tag = m[0];
|
|
3420
|
+
pos = NAME.lastIndex;
|
|
3421
|
+
}
|
|
3422
|
+
if (pos === expr.length) {
|
|
3423
|
+
return { tag, conditions: [] };
|
|
3424
|
+
}
|
|
3425
|
+
if (expr[pos] !== "[" || !expr.endsWith("]")) {
|
|
3426
|
+
return null;
|
|
3427
|
+
}
|
|
3428
|
+
const conditions = parseConditions(expr.slice(pos + 1, -1));
|
|
3429
|
+
return conditions ? { tag, conditions } : null;
|
|
3430
|
+
}
|
|
3431
|
+
function parseConditions(body) {
|
|
3432
|
+
const conditions = [];
|
|
3433
|
+
let pos = 0;
|
|
3434
|
+
for (; ; ) {
|
|
3435
|
+
if (body[pos] !== "@") {
|
|
3436
|
+
return null;
|
|
3437
|
+
}
|
|
3438
|
+
NAME.lastIndex = pos + 1;
|
|
3439
|
+
const m = NAME.exec(body);
|
|
3440
|
+
if (!m || body[NAME.lastIndex] !== "=") {
|
|
3441
|
+
return null;
|
|
3442
|
+
}
|
|
3443
|
+
const quote = body[NAME.lastIndex + 1];
|
|
3444
|
+
if (quote !== '"' && quote !== "'") {
|
|
3445
|
+
return null;
|
|
3446
|
+
}
|
|
3447
|
+
const start = NAME.lastIndex + 2;
|
|
3448
|
+
const end = body.indexOf(quote, start);
|
|
3449
|
+
if (end === -1) {
|
|
3450
|
+
return null;
|
|
3451
|
+
}
|
|
3452
|
+
conditions.push({ name: m[0], value: body.slice(start, end) });
|
|
3453
|
+
pos = end + 1;
|
|
3454
|
+
if (pos === body.length) {
|
|
3455
|
+
return conditions;
|
|
3456
|
+
}
|
|
3457
|
+
if (!body.startsWith(" and ", pos)) {
|
|
3458
|
+
return null;
|
|
3459
|
+
}
|
|
3460
|
+
pos += 5;
|
|
3461
|
+
}
|
|
3462
|
+
}
|
|
3463
|
+
function append(map, key, value) {
|
|
3464
|
+
const list = map.get(key);
|
|
3465
|
+
if (list) {
|
|
3466
|
+
list.push(value);
|
|
3467
|
+
} else {
|
|
3468
|
+
map.set(key, [value]);
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
function buildIndex(doc) {
|
|
3472
|
+
const index = {
|
|
3473
|
+
doc,
|
|
3474
|
+
all: [],
|
|
3475
|
+
byTag: /* @__PURE__ */ new Map(),
|
|
3476
|
+
byAttr: /* @__PURE__ */ new Map()
|
|
3477
|
+
};
|
|
3478
|
+
const stack = doc.documentElement ? [doc.documentElement] : [];
|
|
3479
|
+
const ordered = [];
|
|
3480
|
+
while (stack.length > 0) {
|
|
3481
|
+
const el = stack.pop();
|
|
3482
|
+
if (el.namespaceURI || el.nodeName.includes(":")) {
|
|
3483
|
+
return null;
|
|
3484
|
+
}
|
|
3485
|
+
ordered.push(el);
|
|
3486
|
+
for (let i = el.childNodes.length - 1; i >= 0; i--) {
|
|
3487
|
+
const child = el.childNodes.item(i);
|
|
3488
|
+
if (child?.nodeType === 1) {
|
|
3489
|
+
stack.push(child);
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
}
|
|
3493
|
+
for (const el of ordered) {
|
|
3494
|
+
index.all.push(el);
|
|
3495
|
+
append(index.byTag, el.nodeName, el);
|
|
3496
|
+
for (let i = 0; i < el.attributes.length; i++) {
|
|
3497
|
+
const { name, value } = el.attributes.item(i);
|
|
3498
|
+
if (name === "xmlns" || name.includes(":")) {
|
|
3499
|
+
return null;
|
|
3500
|
+
}
|
|
3501
|
+
let byValue = index.byAttr.get(name);
|
|
3502
|
+
if (!byValue) {
|
|
3503
|
+
byValue = /* @__PURE__ */ new Map();
|
|
3504
|
+
index.byAttr.set(name, byValue);
|
|
3505
|
+
}
|
|
3506
|
+
append(byValue, value, el);
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
return index;
|
|
3510
|
+
}
|
|
3511
|
+
function withXPathIndex(doc, walk) {
|
|
3512
|
+
const previous = active;
|
|
3513
|
+
active = doc ? buildIndex(doc) : null;
|
|
3514
|
+
try {
|
|
3515
|
+
return walk();
|
|
3516
|
+
} finally {
|
|
3517
|
+
active = previous;
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
function selectIndexed(doc, expr) {
|
|
3521
|
+
if (active?.doc !== doc) {
|
|
3522
|
+
return null;
|
|
3523
|
+
}
|
|
3524
|
+
const query = parseSimpleXPath(expr);
|
|
3525
|
+
if (!query) {
|
|
3526
|
+
return null;
|
|
3527
|
+
}
|
|
3528
|
+
const [first, ...rest] = query.conditions;
|
|
3529
|
+
const candidates = first ? active.byAttr.get(first.name)?.get(first.value) ?? [] : query.tag === "*" ? active.all : active.byTag.get(query.tag) ?? [];
|
|
3530
|
+
return candidates.filter(
|
|
3531
|
+
(el) => (query.tag === "*" || el.nodeName === query.tag) && rest.every(
|
|
3532
|
+
(c) => el.hasAttribute(c.name) && el.getAttribute(c.name) === c.value
|
|
3533
|
+
)
|
|
3534
|
+
);
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3537
|
+
// ../core/src/locators/xml-parsing.ts
|
|
3114
3538
|
function childNodesOf(node) {
|
|
3115
3539
|
const children = [];
|
|
3116
3540
|
if (node.childNodes) {
|
|
@@ -3134,14 +3558,14 @@ function translateRecursively(domNode, parentPath = "", index = null) {
|
|
|
3134
3558
|
}
|
|
3135
3559
|
}
|
|
3136
3560
|
}
|
|
3137
|
-
const
|
|
3561
|
+
const path11 = index === null ? "" : `${parentPath ? parentPath + "." : ""}${index}`;
|
|
3138
3562
|
return {
|
|
3139
3563
|
children: childNodesOf(domNode).map(
|
|
3140
|
-
(childNode, childIndex) => translateRecursively(childNode,
|
|
3564
|
+
(childNode, childIndex) => translateRecursively(childNode, path11, childIndex)
|
|
3141
3565
|
),
|
|
3142
3566
|
tagName: domNode.nodeName,
|
|
3143
3567
|
attributes,
|
|
3144
|
-
path:
|
|
3568
|
+
path: path11
|
|
3145
3569
|
};
|
|
3146
3570
|
}
|
|
3147
3571
|
function isSameElement(node1, node2) {
|
|
@@ -3240,6 +3664,10 @@ function xmlToDOM(sourceXML) {
|
|
|
3240
3664
|
}
|
|
3241
3665
|
function evaluateXPath(doc, xpathExpr) {
|
|
3242
3666
|
try {
|
|
3667
|
+
const indexed = selectIndexed(doc, xpathExpr);
|
|
3668
|
+
if (indexed) {
|
|
3669
|
+
return indexed;
|
|
3670
|
+
}
|
|
3243
3671
|
const nodes = xpath.select(xpathExpr, doc);
|
|
3244
3672
|
if (Array.isArray(nodes)) {
|
|
3245
3673
|
return nodes;
|
|
@@ -3278,11 +3706,11 @@ function checkXPathUniqueness(doc, xpathExpr, targetNode) {
|
|
|
3278
3706
|
return { isUnique: false };
|
|
3279
3707
|
}
|
|
3280
3708
|
}
|
|
3281
|
-
function findDOMNodeByPath(doc,
|
|
3282
|
-
if (!
|
|
3709
|
+
function findDOMNodeByPath(doc, path11) {
|
|
3710
|
+
if (!path11) {
|
|
3283
3711
|
return doc.documentElement;
|
|
3284
3712
|
}
|
|
3285
|
-
const indices =
|
|
3713
|
+
const indices = path11.split(".").map(Number);
|
|
3286
3714
|
let current = doc.documentElement;
|
|
3287
3715
|
for (const index of indices) {
|
|
3288
3716
|
if (!current) {
|
|
@@ -4488,7 +4916,7 @@ function generateAllElementLocators(sourceXML, options) {
|
|
|
4488
4916
|
results: [],
|
|
4489
4917
|
parsedDOM
|
|
4490
4918
|
};
|
|
4491
|
-
traverseTree(sourceJSON, ctx);
|
|
4919
|
+
withXPathIndex(parsedDOM, () => traverseTree(sourceJSON, ctx));
|
|
4492
4920
|
return ctx.results;
|
|
4493
4921
|
}
|
|
4494
4922
|
|
|
@@ -4832,21 +5260,21 @@ async function captureAndAttachVideo(input) {
|
|
|
4832
5260
|
import http from "http";
|
|
4833
5261
|
import https from "https";
|
|
4834
5262
|
var WEBDRIVER_REQUEST_TIMEOUT_MS = 5e3;
|
|
4835
|
-
function basePrefix(
|
|
4836
|
-
if (!
|
|
5263
|
+
function basePrefix(path11) {
|
|
5264
|
+
if (!path11 || path11 === "/") {
|
|
4837
5265
|
return "";
|
|
4838
5266
|
}
|
|
4839
|
-
return
|
|
5267
|
+
return path11.endsWith("/") ? path11.slice(0, -1) : path11;
|
|
4840
5268
|
}
|
|
4841
5269
|
function formatHost(hostname) {
|
|
4842
5270
|
const isIpv6Literal = hostname.includes(":") && !hostname.startsWith("[");
|
|
4843
5271
|
return isIpv6Literal ? `[${hostname}]` : hostname;
|
|
4844
5272
|
}
|
|
4845
|
-
function sessionEndpoint(address, sessionId,
|
|
5273
|
+
function sessionEndpoint(address, sessionId, path11) {
|
|
4846
5274
|
const protocol = address.protocol ?? "http";
|
|
4847
5275
|
const prefix = basePrefix(address.path);
|
|
4848
5276
|
const host = formatHost(address.hostname);
|
|
4849
|
-
return `${protocol}://${host}:${address.port}${prefix}/session/${sessionId}/${
|
|
5277
|
+
return `${protocol}://${host}:${address.port}${prefix}/session/${sessionId}/${path11}`;
|
|
4850
5278
|
}
|
|
4851
5279
|
function authHeaders(address) {
|
|
4852
5280
|
if (!address.user || !address.key) {
|
|
@@ -4930,21 +5358,222 @@ function webdriverRequest(address, endpoint, method, body) {
|
|
|
4930
5358
|
req.end();
|
|
4931
5359
|
});
|
|
4932
5360
|
}
|
|
4933
|
-
function webdriverGet(address, sessionId,
|
|
5361
|
+
function webdriverGet(address, sessionId, path11) {
|
|
4934
5362
|
return webdriverRequest(
|
|
4935
5363
|
address,
|
|
4936
|
-
sessionEndpoint(address, sessionId,
|
|
5364
|
+
sessionEndpoint(address, sessionId, path11),
|
|
4937
5365
|
"GET"
|
|
4938
5366
|
);
|
|
4939
5367
|
}
|
|
4940
|
-
function webdriverPost(address, sessionId,
|
|
5368
|
+
function webdriverPost(address, sessionId, path11, body) {
|
|
4941
5369
|
return webdriverRequest(
|
|
4942
5370
|
address,
|
|
4943
|
-
sessionEndpoint(address, sessionId,
|
|
5371
|
+
sessionEndpoint(address, sessionId, path11),
|
|
4944
5372
|
"POST",
|
|
4945
5373
|
body
|
|
4946
5374
|
);
|
|
4947
5375
|
}
|
|
5376
|
+
function webdriverExecute(address, sessionId, body, args = []) {
|
|
5377
|
+
return webdriverPost(address, sessionId, "execute/sync", {
|
|
5378
|
+
script: body,
|
|
5379
|
+
args
|
|
5380
|
+
});
|
|
5381
|
+
}
|
|
5382
|
+
|
|
5383
|
+
// ../core/src/appium-interceptor.ts
|
|
5384
|
+
var INTERCEPT_CAPABILITY = "appium:intercept";
|
|
5385
|
+
var APPIUM_OPTIONS = "appium:options";
|
|
5386
|
+
var NATIVE_NETWORK_DRAIN_INTERVAL_MS = 2e3;
|
|
5387
|
+
function flattenInterceptedHeaders(headers) {
|
|
5388
|
+
const flat = {};
|
|
5389
|
+
for (const [name, value] of Object.entries(headers ?? {})) {
|
|
5390
|
+
if (/\s/.test(name)) {
|
|
5391
|
+
continue;
|
|
5392
|
+
}
|
|
5393
|
+
flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
|
|
5394
|
+
}
|
|
5395
|
+
return flat;
|
|
5396
|
+
}
|
|
5397
|
+
function interceptedBodyText(body) {
|
|
5398
|
+
if (body === void 0 || body === null || body === "") {
|
|
5399
|
+
return void 0;
|
|
5400
|
+
}
|
|
5401
|
+
return typeof body === "string" ? body : JSON.stringify(body);
|
|
5402
|
+
}
|
|
5403
|
+
function interceptedToNetworkRequest(entry, id, observedAt) {
|
|
5404
|
+
const responseHeaders = flattenInterceptedHeaders(entry.responseHeaders);
|
|
5405
|
+
const responseBody = interceptedBodyText(entry.responseBody);
|
|
5406
|
+
return {
|
|
5407
|
+
id,
|
|
5408
|
+
url: entry.url,
|
|
5409
|
+
method: entry.method,
|
|
5410
|
+
status: entry.statusCode,
|
|
5411
|
+
type: getRequestType(entry.url, responseHeaders["content-type"]),
|
|
5412
|
+
timestamp: observedAt.timestamp,
|
|
5413
|
+
startTime: observedAt.startTime,
|
|
5414
|
+
endTime: observedAt.startTime,
|
|
5415
|
+
requestHeaders: flattenInterceptedHeaders(entry.requestHeaders),
|
|
5416
|
+
responseHeaders,
|
|
5417
|
+
response: {
|
|
5418
|
+
fromCache: false,
|
|
5419
|
+
headers: responseHeaders,
|
|
5420
|
+
mimeType: responseHeaders["content-type"]?.split(";")[0]?.trim() ?? "",
|
|
5421
|
+
status: entry.statusCode
|
|
5422
|
+
},
|
|
5423
|
+
requestBody: interceptedBodyText(entry.requestBody),
|
|
5424
|
+
responseBody,
|
|
5425
|
+
size: responseBody === void 0 ? void 0 : Buffer.byteLength(responseBody)
|
|
5426
|
+
};
|
|
5427
|
+
}
|
|
5428
|
+
var InterceptorNetworkPoller = class {
|
|
5429
|
+
#execute;
|
|
5430
|
+
#listenerId;
|
|
5431
|
+
#seen = 0;
|
|
5432
|
+
// Drains are chained: two overlapping reads would both list the entries past the same `#seen`.
|
|
5433
|
+
#tail = Promise.resolve([]);
|
|
5434
|
+
constructor(execute) {
|
|
5435
|
+
this.#execute = execute;
|
|
5436
|
+
}
|
|
5437
|
+
async start() {
|
|
5438
|
+
const id = await this.#execute("interceptor: startListening", [{}]);
|
|
5439
|
+
this.#listenerId = typeof id === "string" ? id : void 0;
|
|
5440
|
+
return this.#listenerId !== void 0;
|
|
5441
|
+
}
|
|
5442
|
+
drain() {
|
|
5443
|
+
this.#tail = this.#tail.catch(() => []).then(() => this.#readFresh());
|
|
5444
|
+
return this.#tail;
|
|
5445
|
+
}
|
|
5446
|
+
async #readFresh() {
|
|
5447
|
+
const listenerId = this.#listenerId;
|
|
5448
|
+
if (!listenerId) {
|
|
5449
|
+
return [];
|
|
5450
|
+
}
|
|
5451
|
+
const data = await this.#execute("interceptor: getInterceptedData", [
|
|
5452
|
+
{ id: listenerId }
|
|
5453
|
+
]);
|
|
5454
|
+
if (!Array.isArray(data)) {
|
|
5455
|
+
throw new Error("the plugin returned no intercepted data");
|
|
5456
|
+
}
|
|
5457
|
+
if (data.length <= this.#seen) {
|
|
5458
|
+
return [];
|
|
5459
|
+
}
|
|
5460
|
+
const observedAt = { timestamp: Date.now(), startTime: performance.now() };
|
|
5461
|
+
const fresh = data.slice(this.#seen).map(
|
|
5462
|
+
(entry, offset) => interceptedToNetworkRequest(
|
|
5463
|
+
entry,
|
|
5464
|
+
`interceptor-${listenerId}-${this.#seen + offset}`,
|
|
5465
|
+
observedAt
|
|
5466
|
+
)
|
|
5467
|
+
);
|
|
5468
|
+
this.#seen = data.length;
|
|
5469
|
+
return fresh;
|
|
5470
|
+
}
|
|
5471
|
+
};
|
|
5472
|
+
function asksForIntercept(caps) {
|
|
5473
|
+
if (!caps || typeof caps !== "object") {
|
|
5474
|
+
return false;
|
|
5475
|
+
}
|
|
5476
|
+
const map = caps;
|
|
5477
|
+
const read = (key) => typeof map.get === "function" ? map.get(key) : map[key];
|
|
5478
|
+
if (read(INTERCEPT_CAPABILITY) === true) {
|
|
5479
|
+
return true;
|
|
5480
|
+
}
|
|
5481
|
+
const grouped = read(APPIUM_OPTIONS);
|
|
5482
|
+
return !!grouped && typeof grouped === "object" && grouped.intercept === true;
|
|
5483
|
+
}
|
|
5484
|
+
function requestsInterceptedNetwork(capabilities) {
|
|
5485
|
+
if (asksForIntercept(capabilities)) {
|
|
5486
|
+
return true;
|
|
5487
|
+
}
|
|
5488
|
+
if (!capabilities || typeof capabilities !== "object") {
|
|
5489
|
+
return false;
|
|
5490
|
+
}
|
|
5491
|
+
const { alwaysMatch, firstMatch } = capabilities;
|
|
5492
|
+
return [alwaysMatch, ...Array.isArray(firstMatch) ? firstMatch : []].some(
|
|
5493
|
+
asksForIntercept
|
|
5494
|
+
);
|
|
5495
|
+
}
|
|
5496
|
+
var NativeNetworkCapture = class {
|
|
5497
|
+
#sink;
|
|
5498
|
+
#onLog;
|
|
5499
|
+
#now;
|
|
5500
|
+
#lastDrainAt = Number.NEGATIVE_INFINITY;
|
|
5501
|
+
#poller;
|
|
5502
|
+
// A start superseded by a later one (session replaced mid-handshake) must not install its poller.
|
|
5503
|
+
#generation = 0;
|
|
5504
|
+
constructor(sink, onLog, now = Date.now) {
|
|
5505
|
+
this.#sink = sink;
|
|
5506
|
+
this.#onLog = onLog;
|
|
5507
|
+
this.#now = now;
|
|
5508
|
+
}
|
|
5509
|
+
/** Called per session: a listener dies with its session. */
|
|
5510
|
+
async start(target) {
|
|
5511
|
+
const generation = ++this.#generation;
|
|
5512
|
+
this.#poller = void 0;
|
|
5513
|
+
if (!target?.requested || !isNativeAppSession(target.capabilities)) {
|
|
5514
|
+
return;
|
|
5515
|
+
}
|
|
5516
|
+
if (!target.execute) {
|
|
5517
|
+
this.#onLog(
|
|
5518
|
+
"warn",
|
|
5519
|
+
`${INTERCEPT_CAPABILITY} is set but ${target.unavailableReason ?? "the driver cannot be reached outside the command path"}; native network is not captured`
|
|
5520
|
+
);
|
|
5521
|
+
return;
|
|
5522
|
+
}
|
|
5523
|
+
const poller = new InterceptorNetworkPoller(target.execute);
|
|
5524
|
+
const started = await poller.start().catch((err) => {
|
|
5525
|
+
this.#onLog(
|
|
5526
|
+
"warn",
|
|
5527
|
+
`appium-interceptor listener failed to start: ${errorMessage(err)}`
|
|
5528
|
+
);
|
|
5529
|
+
return false;
|
|
5530
|
+
});
|
|
5531
|
+
if (generation !== this.#generation) {
|
|
5532
|
+
return;
|
|
5533
|
+
}
|
|
5534
|
+
if (!started) {
|
|
5535
|
+
this.#onLog(
|
|
5536
|
+
"warn",
|
|
5537
|
+
`${INTERCEPT_CAPABILITY} is set but the interceptor listener did not start; is Appium running with --use-plugins=appium-interceptor?`
|
|
5538
|
+
);
|
|
5539
|
+
return;
|
|
5540
|
+
}
|
|
5541
|
+
this.#onLog("info", "Native network capture active via appium-interceptor");
|
|
5542
|
+
this.#poller = poller;
|
|
5543
|
+
this.#lastDrainAt = Number.NEGATIVE_INFINITY;
|
|
5544
|
+
}
|
|
5545
|
+
/** Whether a listener is running, so a caller can skip a drain that cannot find anything. */
|
|
5546
|
+
get active() {
|
|
5547
|
+
return this.#poller !== void 0;
|
|
5548
|
+
}
|
|
5549
|
+
/** At session end, so a drain after the driver quit does not reach a dead session. */
|
|
5550
|
+
stop() {
|
|
5551
|
+
this.#generation++;
|
|
5552
|
+
this.#poller = void 0;
|
|
5553
|
+
}
|
|
5554
|
+
/** Lists what the proxy recorded since the last call. A test or session boundary must not pass `throttle`. */
|
|
5555
|
+
async forward(options = {}) {
|
|
5556
|
+
const poller = this.#poller;
|
|
5557
|
+
if (!poller) {
|
|
5558
|
+
return;
|
|
5559
|
+
}
|
|
5560
|
+
const now = this.#now();
|
|
5561
|
+
if (options.throttle && now - this.#lastDrainAt < NATIVE_NETWORK_DRAIN_INTERVAL_MS) {
|
|
5562
|
+
return;
|
|
5563
|
+
}
|
|
5564
|
+
this.#lastDrainAt = now;
|
|
5565
|
+
const requests = await poller.drain().catch((err) => {
|
|
5566
|
+
this.#onLog(
|
|
5567
|
+
"warn",
|
|
5568
|
+
`Reading appium-interceptor data failed: ${errorMessage(err)}`
|
|
5569
|
+
);
|
|
5570
|
+
return [];
|
|
5571
|
+
});
|
|
5572
|
+
if (requests.length > 0) {
|
|
5573
|
+
this.#sink.recordNetworkRequests(requests);
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
};
|
|
4948
5577
|
|
|
4949
5578
|
// ../core/src/viewport.ts
|
|
4950
5579
|
var VISUAL_VIEWPORT_SCRIPT = `
|
|
@@ -4999,10 +5628,60 @@ async function resolveViewport(capabilities, probes) {
|
|
|
4999
5628
|
import { createRequire as createRequire3 } from "module";
|
|
5000
5629
|
|
|
5001
5630
|
// ../core/src/stack.ts
|
|
5631
|
+
import { existsSync, readFileSync } from "fs";
|
|
5632
|
+
import path8 from "path";
|
|
5633
|
+
import { fileURLToPath } from "url";
|
|
5002
5634
|
import { parse as parseStackTrace } from "stacktrace-parser";
|
|
5635
|
+
var WORKSPACE_ROOT_NAME = "devtools-monorepo";
|
|
5636
|
+
function findOwnPackagesDir(fromDir) {
|
|
5637
|
+
for (let dir = fromDir; ; dir = path8.dirname(dir)) {
|
|
5638
|
+
if (existsSync(path8.join(dir, "pnpm-workspace.yaml"))) {
|
|
5639
|
+
return readPackageName(dir) === WORKSPACE_ROOT_NAME ? path8.join(dir, "packages") : void 0;
|
|
5640
|
+
}
|
|
5641
|
+
if (path8.dirname(dir) === dir) {
|
|
5642
|
+
return void 0;
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
}
|
|
5646
|
+
function readPackageName(dir) {
|
|
5647
|
+
try {
|
|
5648
|
+
const pkg = JSON.parse(
|
|
5649
|
+
readFileSync(path8.join(dir, "package.json"), "utf8")
|
|
5650
|
+
);
|
|
5651
|
+
return typeof pkg.name === "string" ? pkg.name : void 0;
|
|
5652
|
+
} catch {
|
|
5653
|
+
return void 0;
|
|
5654
|
+
}
|
|
5655
|
+
}
|
|
5656
|
+
var ownPackagesDir;
|
|
5657
|
+
function resolveOwnPackagesDir() {
|
|
5658
|
+
if (ownPackagesDir === void 0) {
|
|
5659
|
+
try {
|
|
5660
|
+
ownPackagesDir = findOwnPackagesDir(path8.dirname(fileURLToPath(import.meta.url))) ?? null;
|
|
5661
|
+
} catch {
|
|
5662
|
+
ownPackagesDir = null;
|
|
5663
|
+
}
|
|
5664
|
+
}
|
|
5665
|
+
return ownPackagesDir ?? void 0;
|
|
5666
|
+
}
|
|
5667
|
+
function isPackageSource(file, packagesDir) {
|
|
5668
|
+
if (!packagesDir) {
|
|
5669
|
+
return false;
|
|
5670
|
+
}
|
|
5671
|
+
try {
|
|
5672
|
+
const filePath = file.startsWith("file://") ? fileURLToPath(file) : file;
|
|
5673
|
+
const relative = path8.relative(packagesDir, filePath);
|
|
5674
|
+
if (relative.startsWith("..") || path8.isAbsolute(relative)) {
|
|
5675
|
+
return false;
|
|
5676
|
+
}
|
|
5677
|
+
return relative.split(path8.sep)[1] === "src";
|
|
5678
|
+
} catch {
|
|
5679
|
+
return false;
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5003
5682
|
function isUserCodeFrame(frame) {
|
|
5004
5683
|
const { file } = frame;
|
|
5005
|
-
return !!(file && !file.includes("/node_modules/") && !file.includes("<anonymous>") && !file.includes("node:internal") && !file.includes("/dist/") && !file.endsWith("/index.js"));
|
|
5684
|
+
return !!(file && !file.includes("/node_modules/") && !file.includes("<anonymous>") && !file.includes("node:internal") && !file.includes("/dist/") && !file.endsWith("/index.js") && !isPackageSource(file, resolveOwnPackagesDir()));
|
|
5006
5685
|
}
|
|
5007
5686
|
function normalizeFilePath(filePath) {
|
|
5008
5687
|
const stripped = filePath.replace(/^file:\/\//, "").split(":")[0];
|
|
@@ -5019,16 +5698,24 @@ function isAssertFromUserCode(stack) {
|
|
|
5019
5698
|
const caller = parseStackTrace(stack)[1];
|
|
5020
5699
|
return !!caller && isUserCodeFrame(caller);
|
|
5021
5700
|
}
|
|
5701
|
+
var NO_CALL_SOURCE = {
|
|
5702
|
+
filePath: void 0,
|
|
5703
|
+
callSource: void 0
|
|
5704
|
+
};
|
|
5022
5705
|
function getCallSourceFromStack(stack = new Error().stack) {
|
|
5023
5706
|
if (!stack) {
|
|
5024
|
-
return
|
|
5707
|
+
return NO_CALL_SOURCE;
|
|
5025
5708
|
}
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5709
|
+
try {
|
|
5710
|
+
const frame = parseStackTrace(stack).find(isUserCodeFrame);
|
|
5711
|
+
if (!frame?.file) {
|
|
5712
|
+
return NO_CALL_SOURCE;
|
|
5713
|
+
}
|
|
5714
|
+
const filePath = normalizeFilePath(frame.file);
|
|
5715
|
+
return { filePath, callSource: `${filePath}:${frame.lineNumber ?? 0}` };
|
|
5716
|
+
} catch {
|
|
5717
|
+
return NO_CALL_SOURCE;
|
|
5029
5718
|
}
|
|
5030
|
-
const filePath = normalizeFilePath(frame.file);
|
|
5031
|
-
return { filePath, callSource: `${filePath}:${frame.lineNumber ?? 0}` };
|
|
5032
5719
|
}
|
|
5033
5720
|
|
|
5034
5721
|
// ../core/src/assert-patcher.ts
|
|
@@ -5250,19 +5937,14 @@ function patchNodeAssert(onCommand, onLog, resolveAssertTarget) {
|
|
|
5250
5937
|
|
|
5251
5938
|
// ../core/src/script-loader.ts
|
|
5252
5939
|
import fs8 from "fs/promises";
|
|
5253
|
-
import
|
|
5940
|
+
import path9 from "path";
|
|
5254
5941
|
import { createRequire as createRequire4 } from "module";
|
|
5255
5942
|
var require4 = createRequire4(import.meta.url);
|
|
5256
|
-
var COLLECTOR_READY_EXPRESSION = 'typeof window.wdioTraceCollector !== "undefined"';
|
|
5257
|
-
function collectorDrainExpression(forceAnchor = false) {
|
|
5258
|
-
const call = forceAnchor ? "window.wdioTraceCollector.captureCurrentDom();" : "";
|
|
5259
|
-
return `if (!(${COLLECTOR_READY_EXPRESSION})) { return null; } ${call} return window.wdioTraceCollector.getTraceData();`;
|
|
5260
|
-
}
|
|
5261
5943
|
function collectorSourceCandidates(entry) {
|
|
5262
|
-
const dir =
|
|
5944
|
+
const dir = path9.dirname(entry);
|
|
5263
5945
|
return [
|
|
5264
|
-
|
|
5265
|
-
|
|
5946
|
+
path9.join(dir, "script.js"),
|
|
5947
|
+
path9.join(dir, "..", "dist", "script.js")
|
|
5266
5948
|
];
|
|
5267
5949
|
}
|
|
5268
5950
|
async function loadCollectorSource() {
|
|
@@ -5284,20 +5966,8 @@ async function loadCollectorSource() {
|
|
|
5284
5966
|
async function loadInjectableScript() {
|
|
5285
5967
|
return `(async function() { ${await loadCollectorSource()} })()`;
|
|
5286
5968
|
}
|
|
5287
|
-
var NON_INSTRUMENTABLE_SCHEMES = [
|
|
5288
|
-
"about:",
|
|
5289
|
-
"data:",
|
|
5290
|
-
"chrome:",
|
|
5291
|
-
"chrome-error:",
|
|
5292
|
-
"edge:",
|
|
5293
|
-
"moz-extension:",
|
|
5294
|
-
"chrome-extension:"
|
|
5295
|
-
];
|
|
5296
5969
|
function isInstrumentableDocument(url) {
|
|
5297
|
-
|
|
5298
|
-
return false;
|
|
5299
|
-
}
|
|
5300
|
-
return !NON_INSTRUMENTABLE_SCHEMES.some((scheme) => url.startsWith(scheme));
|
|
5970
|
+
return Boolean(url) && !isBrowserInternalUrl(url) && schemeOf(url) !== "data";
|
|
5301
5971
|
}
|
|
5302
5972
|
async function drainCollectorWithRecovery(opts) {
|
|
5303
5973
|
const payload = await opts.drain();
|
|
@@ -5329,6 +5999,9 @@ async function drainCollectorWithRecovery(opts) {
|
|
|
5329
5999
|
async function pollUntilReady(check, opts = {}) {
|
|
5330
6000
|
const attempts = opts.attempts ?? 5;
|
|
5331
6001
|
const intervalMs = opts.intervalMs ?? 200;
|
|
6002
|
+
if (opts.checkFirst && await check()) {
|
|
6003
|
+
return true;
|
|
6004
|
+
}
|
|
5332
6005
|
for (let i = 0; i < attempts; i++) {
|
|
5333
6006
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
5334
6007
|
if (await check()) {
|
|
@@ -5402,7 +6075,7 @@ var TerminalLineThrottle = class {
|
|
|
5402
6075
|
// ../core/src/finalize-screencast.ts
|
|
5403
6076
|
import fs9 from "fs";
|
|
5404
6077
|
import os2 from "os";
|
|
5405
|
-
import
|
|
6078
|
+
import path10 from "path";
|
|
5406
6079
|
async function finalizeScreencast({
|
|
5407
6080
|
recorder,
|
|
5408
6081
|
sessionId,
|
|
@@ -5426,12 +6099,12 @@ async function finalizeScreencast({
|
|
|
5426
6099
|
}
|
|
5427
6100
|
const fileName = `${filenamePrefix}-${sessionId}.webm`;
|
|
5428
6101
|
const candidate = outputDir || process.cwd();
|
|
5429
|
-
let videoPath =
|
|
6102
|
+
let videoPath = path10.join(candidate, fileName);
|
|
5430
6103
|
try {
|
|
5431
6104
|
fs9.mkdirSync(candidate, { recursive: true });
|
|
5432
6105
|
fs9.accessSync(candidate, fs9.constants.W_OK);
|
|
5433
6106
|
} catch {
|
|
5434
|
-
videoPath =
|
|
6107
|
+
videoPath = path10.join(os2.tmpdir(), fileName);
|
|
5435
6108
|
}
|
|
5436
6109
|
try {
|
|
5437
6110
|
await encodeToVideo(frames, videoPath, { captureFormat });
|
|
@@ -5499,54 +6172,9 @@ function isInputDispatchInFlight() {
|
|
|
5499
6172
|
}
|
|
5500
6173
|
|
|
5501
6174
|
// ../core/src/performance-capture.ts
|
|
5502
|
-
|
|
5503
|
-
(
|
|
5504
|
-
|
|
5505
|
-
const navigation = performance.getEntriesByType?.('navigation')?.[0];
|
|
5506
|
-
const resources = performance.getEntriesByType?.('resource') || [];
|
|
5507
|
-
|
|
5508
|
-
return {
|
|
5509
|
-
navigation: navigation ? {
|
|
5510
|
-
url: window.location.href,
|
|
5511
|
-
timing: {
|
|
5512
|
-
loadTime: navigation.loadEventEnd - navigation.fetchStart,
|
|
5513
|
-
domReady: navigation.domContentLoadedEventEnd - navigation.fetchStart,
|
|
5514
|
-
responseTime: navigation.responseEnd - navigation.requestStart,
|
|
5515
|
-
dnsLookup: navigation.domainLookupEnd - navigation.domainLookupStart,
|
|
5516
|
-
tcpConnection: navigation.connectEnd - navigation.connectStart,
|
|
5517
|
-
serverResponse: navigation.responseEnd - navigation.responseStart
|
|
5518
|
-
}
|
|
5519
|
-
} : undefined,
|
|
5520
|
-
resources: resources.map(function(resource) {
|
|
5521
|
-
return {
|
|
5522
|
-
url: resource.name,
|
|
5523
|
-
duration: resource.duration,
|
|
5524
|
-
size: resource.transferSize || 0,
|
|
5525
|
-
type: resource.initiatorType,
|
|
5526
|
-
startTime: resource.startTime,
|
|
5527
|
-
responseEnd: resource.responseEnd
|
|
5528
|
-
};
|
|
5529
|
-
}),
|
|
5530
|
-
cookies: (function() {
|
|
5531
|
-
try { return document.cookie; } catch (e) { return ''; }
|
|
5532
|
-
})(),
|
|
5533
|
-
documentInfo: {
|
|
5534
|
-
url: window.location.href,
|
|
5535
|
-
title: document.title,
|
|
5536
|
-
headers: {
|
|
5537
|
-
userAgent: navigator.userAgent,
|
|
5538
|
-
language: navigator.language,
|
|
5539
|
-
platform: navigator.platform
|
|
5540
|
-
},
|
|
5541
|
-
documentInfo: {
|
|
5542
|
-
readyState: document.readyState,
|
|
5543
|
-
referrer: document.referrer,
|
|
5544
|
-
characterSet: document.characterSet
|
|
5545
|
-
}
|
|
5546
|
-
}
|
|
5547
|
-
};
|
|
5548
|
-
})()
|
|
5549
|
-
`;
|
|
6175
|
+
function formatMilliseconds(ms) {
|
|
6176
|
+
return typeof ms === "number" && Number.isFinite(ms) ? `${ms.toFixed(2)} ms` : void 0;
|
|
6177
|
+
}
|
|
5550
6178
|
function applyPerformanceData(command, payload, navigatedUrl) {
|
|
5551
6179
|
if (!payload || !payload.navigation) {
|
|
5552
6180
|
return false;
|
|
@@ -5559,7 +6187,7 @@ function applyPerformanceData(command, payload, navigatedUrl) {
|
|
|
5559
6187
|
command.documentInfo = payload.documentInfo;
|
|
5560
6188
|
command.result = {
|
|
5561
6189
|
url: navigatedUrl,
|
|
5562
|
-
loadTime: payload.navigation?.timing?.loadTime,
|
|
6190
|
+
loadTime: formatMilliseconds(payload.navigation?.timing?.loadTime),
|
|
5563
6191
|
resources: payload.resources,
|
|
5564
6192
|
resourceCount: payload.resources?.length,
|
|
5565
6193
|
cookies: payload.cookies,
|
|
@@ -5591,14 +6219,17 @@ function rememberReadValue(value, selector) {
|
|
|
5591
6219
|
}
|
|
5592
6220
|
}
|
|
5593
6221
|
}
|
|
5594
|
-
function
|
|
5595
|
-
|
|
6222
|
+
function clearReadValues() {
|
|
6223
|
+
selectorByReadValue.clear();
|
|
5596
6224
|
}
|
|
5597
6225
|
function resolveAssertTargetFromArgs(args, fromHandle) {
|
|
5598
6226
|
for (const arg of args) {
|
|
5599
|
-
const
|
|
5600
|
-
if (
|
|
5601
|
-
return
|
|
6227
|
+
const handle = fromHandle?.(arg);
|
|
6228
|
+
if (handle) {
|
|
6229
|
+
return handle;
|
|
6230
|
+
}
|
|
6231
|
+
if (selectorByReadValue.has(arg)) {
|
|
6232
|
+
return selectorByReadValue.get(arg) ?? void 0;
|
|
5602
6233
|
}
|
|
5603
6234
|
}
|
|
5604
6235
|
return void 0;
|
|
@@ -5919,7 +6550,33 @@ var ScreencastRecorderBase = class {
|
|
|
5919
6550
|
}
|
|
5920
6551
|
};
|
|
5921
6552
|
|
|
6553
|
+
// ../core/src/browser-focus.ts
|
|
6554
|
+
import { spawn } from "child_process";
|
|
6555
|
+
var LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
6556
|
+
function restoreBrowserFocus(target, platform = process.platform, launch = spawn) {
|
|
6557
|
+
const local = !target.host || LOCAL_HOSTS.has(target.host);
|
|
6558
|
+
if (platform !== "darwin" || !local || !/safari/i.test(target.browserName ?? "") || /ios/i.test(target.platformName ?? "")) {
|
|
6559
|
+
return false;
|
|
6560
|
+
}
|
|
6561
|
+
try {
|
|
6562
|
+
const child = launch("open", ["-a", "Safari"], {
|
|
6563
|
+
detached: true,
|
|
6564
|
+
stdio: "ignore"
|
|
6565
|
+
});
|
|
6566
|
+
child.on?.(
|
|
6567
|
+
"error",
|
|
6568
|
+
(err) => target.onError?.(`Could not bring Safari to the front: ${err.message}`)
|
|
6569
|
+
);
|
|
6570
|
+
child.unref?.();
|
|
6571
|
+
return true;
|
|
6572
|
+
} catch (err) {
|
|
6573
|
+
target.onError?.(`Could not bring Safari to the front: ${String(err)}`);
|
|
6574
|
+
return false;
|
|
6575
|
+
}
|
|
6576
|
+
}
|
|
6577
|
+
|
|
5922
6578
|
// ../core/src/session-capturer.ts
|
|
6579
|
+
import { randomInt } from "crypto";
|
|
5923
6580
|
import fs10 from "fs/promises";
|
|
5924
6581
|
import { WebSocket } from "ws";
|
|
5925
6582
|
var SessionCapturerBase = class _SessionCapturerBase {
|
|
@@ -5952,7 +6609,8 @@ var SessionCapturerBase = class _SessionCapturerBase {
|
|
|
5952
6609
|
// (WDIO owns the command lifecycle), so this state is harmless overhead.
|
|
5953
6610
|
// `protected` (not `#`) so subclasses can override the send/replace flow
|
|
5954
6611
|
// while still sharing the counter and de-dup set with base helpers.
|
|
5955
|
-
|
|
6612
|
+
// A row's public `id` must not repeat across processes: a rerun child's rows join its parent's in the backend's accumulator, and test workers share one dashboard.
|
|
6613
|
+
commandCounter = randomInt(2 ** 32) * 2 ** 20;
|
|
5956
6614
|
sentCommandIds = /* @__PURE__ */ new Set();
|
|
5957
6615
|
// Map of file path → source text. Populated by `captureSource` (also
|
|
5958
6616
|
// accessed by adapter-specific source-discovery flows, e.g. service's
|
|
@@ -6267,26 +6925,24 @@ var SessionCapturerBase = class _SessionCapturerBase {
|
|
|
6267
6925
|
*
|
|
6268
6926
|
* `skipConsoleLogs` / `skipNetworkRequests` opt out when an out-of-band
|
|
6269
6927
|
* channel (BiDi) is already delivering those streams — without the gate
|
|
6270
|
-
* the dashboard would see each entry twice.
|
|
6928
|
+
* the dashboard would see each entry twice. `skipResourceTimingRequests`
|
|
6929
|
+
* drops only the page's Resource Timing entries: a driver-side source
|
|
6930
|
+
* reports the same loads with their headers, while the collector's patched
|
|
6931
|
+
* fetch/XHR rows still carry the bodies nothing else captures.
|
|
6271
6932
|
*/
|
|
6272
6933
|
processTracePayload(payload, opts = {}) {
|
|
6273
6934
|
const { mutations, traceLogs, consoleLogs, networkRequests, metadata } = payload;
|
|
6274
6935
|
if (metadata && typeof metadata === "object") {
|
|
6275
6936
|
this.mergeMetadata(metadata);
|
|
6276
6937
|
}
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
...entry,
|
|
6280
|
-
source: LOG_SOURCES.BROWSER
|
|
6281
|
-
}));
|
|
6938
|
+
const tagged = opts.skipConsoleLogs ? [] : this.#tagBrowserConsoleLogs(consoleLogs);
|
|
6939
|
+
if (tagged.length > 0) {
|
|
6282
6940
|
this.consoleLogs.push(...tagged);
|
|
6283
6941
|
this.sendUpstream("consoleLogs", tagged);
|
|
6284
6942
|
}
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
this.sendUpstream("networkRequests", reqs);
|
|
6289
|
-
}
|
|
6943
|
+
this.recordNetworkRequests(
|
|
6944
|
+
this.#acceptedNetworkRequests(networkRequests, opts)
|
|
6945
|
+
);
|
|
6290
6946
|
if (Array.isArray(mutations) && mutations.length > 0) {
|
|
6291
6947
|
const batch = mutations;
|
|
6292
6948
|
reattributeDomAnchors(
|
|
@@ -6303,6 +6959,50 @@ var SessionCapturerBase = class _SessionCapturerBase {
|
|
|
6303
6959
|
this.sendUpstream("logs", logs);
|
|
6304
6960
|
}
|
|
6305
6961
|
}
|
|
6962
|
+
#tagBrowserConsoleLogs(consoleLogs) {
|
|
6963
|
+
if (!Array.isArray(consoleLogs)) {
|
|
6964
|
+
return [];
|
|
6965
|
+
}
|
|
6966
|
+
return consoleLogs.map((entry) => ({
|
|
6967
|
+
...entry,
|
|
6968
|
+
source: LOG_SOURCES.BROWSER
|
|
6969
|
+
}));
|
|
6970
|
+
}
|
|
6971
|
+
/** Lists network rows and sends them in one message; a re-sent id replaces its row, as the dashboard does. */
|
|
6972
|
+
recordNetworkRequests(reqs) {
|
|
6973
|
+
if (reqs.length === 0) {
|
|
6974
|
+
return;
|
|
6975
|
+
}
|
|
6976
|
+
for (const req of reqs) {
|
|
6977
|
+
this.#upsertNetworkRequest(req);
|
|
6978
|
+
}
|
|
6979
|
+
this.sendUpstream("networkRequests", reqs);
|
|
6980
|
+
}
|
|
6981
|
+
/** Row index by request id; checked against the row before use, since adapters also write rows by index. */
|
|
6982
|
+
#networkRequestIndex = /* @__PURE__ */ new Map();
|
|
6983
|
+
#upsertNetworkRequest(req) {
|
|
6984
|
+
let at = req.id ? this.#networkRequestIndex.get(req.id) : void 0;
|
|
6985
|
+
if (at !== void 0 && this.networkRequests[at]?.id !== req.id) {
|
|
6986
|
+
at = this.networkRequests.findIndex((r) => r.id === req.id);
|
|
6987
|
+
}
|
|
6988
|
+
if (at !== void 0 && at !== -1) {
|
|
6989
|
+
this.networkRequests[at] = req;
|
|
6990
|
+
this.#networkRequestIndex.set(req.id, at);
|
|
6991
|
+
return;
|
|
6992
|
+
}
|
|
6993
|
+
if (req.id) {
|
|
6994
|
+
this.#networkRequestIndex.set(req.id, this.networkRequests.length);
|
|
6995
|
+
}
|
|
6996
|
+
this.networkRequests.push(req);
|
|
6997
|
+
}
|
|
6998
|
+
#acceptedNetworkRequests(networkRequests, opts) {
|
|
6999
|
+
if (opts.skipNetworkRequests || !Array.isArray(networkRequests)) {
|
|
7000
|
+
return [];
|
|
7001
|
+
}
|
|
7002
|
+
return networkRequests.filter(
|
|
7003
|
+
(req) => !opts.skipResourceTimingRequests || req.source !== NETWORK_CAPTURE_SOURCE.RESOURCE_TIMING
|
|
7004
|
+
);
|
|
7005
|
+
}
|
|
6306
7006
|
/**
|
|
6307
7007
|
* Resolve when the WS reaches OPEN state, or `false` on timeout / error.
|
|
6308
7008
|
* Returns immediately if already open. Used by adapters that need a
|
|
@@ -6711,11 +7411,20 @@ var TestReporterBase = class {
|
|
|
6711
7411
|
|
|
6712
7412
|
export {
|
|
6713
7413
|
mapCommandToAction,
|
|
7414
|
+
isWaitCommand,
|
|
6714
7415
|
stripAnsi,
|
|
6715
|
-
|
|
7416
|
+
COLLECTOR_READY_SCRIPT,
|
|
7417
|
+
COLLECTOR_INJECT_SCRIPT,
|
|
7418
|
+
collectorDrainExpression,
|
|
7419
|
+
CAPTURE_PERFORMANCE_SCRIPT,
|
|
7420
|
+
commandFailure,
|
|
7421
|
+
getRequestType,
|
|
6716
7422
|
WS_SCOPE,
|
|
6717
7423
|
REUSE_ENV,
|
|
7424
|
+
RUNNER_ENV,
|
|
7425
|
+
encodeInitialArgs,
|
|
6718
7426
|
TEST_STATE,
|
|
7427
|
+
NETWORK_CAPTURE_SOURCE,
|
|
6719
7428
|
SCREENCAST_DEFAULTS,
|
|
6720
7429
|
captureActionSnapshot,
|
|
6721
7430
|
toError,
|
|
@@ -6728,6 +7437,9 @@ export {
|
|
|
6728
7437
|
TestAttemptTracker,
|
|
6729
7438
|
webdriverGet,
|
|
6730
7439
|
webdriverPost,
|
|
7440
|
+
webdriverExecute,
|
|
7441
|
+
requestsInterceptedNetwork,
|
|
7442
|
+
NativeNetworkCapture,
|
|
6731
7443
|
resolveViewport,
|
|
6732
7444
|
isUserCodeFrame,
|
|
6733
7445
|
normalizeFilePath,
|
|
@@ -6744,11 +7456,8 @@ export {
|
|
|
6744
7456
|
recordSpecBoundary,
|
|
6745
7457
|
flushRangeLogged,
|
|
6746
7458
|
finalizeTraceExport,
|
|
6747
|
-
getRequestType,
|
|
6748
7459
|
findFreePort,
|
|
6749
7460
|
attachBidiHandlers,
|
|
6750
|
-
COLLECTOR_READY_EXPRESSION,
|
|
6751
|
-
collectorDrainExpression,
|
|
6752
7461
|
loadInjectableScript,
|
|
6753
7462
|
drainCollectorWithRecovery,
|
|
6754
7463
|
pollUntilReady,
|
|
@@ -6756,12 +7465,13 @@ export {
|
|
|
6756
7465
|
finalizeScreencast,
|
|
6757
7466
|
beginInputDispatch,
|
|
6758
7467
|
resolveAdapterOutputDir,
|
|
6759
|
-
CAPTURE_PERFORMANCE_SCRIPT,
|
|
6760
7468
|
applyPerformanceData,
|
|
6761
7469
|
rememberReadValue,
|
|
7470
|
+
clearReadValues,
|
|
6762
7471
|
resolveAssertTargetFromArgs,
|
|
6763
7472
|
RetryTracker,
|
|
6764
7473
|
ScreencastRecorderBase,
|
|
7474
|
+
restoreBrowserFocus,
|
|
6765
7475
|
SessionCapturerBase,
|
|
6766
7476
|
createSuiteStats,
|
|
6767
7477
|
createTestStats,
|
|
@@ -6773,4 +7483,4 @@ export {
|
|
|
6773
7483
|
findTestDefinitions,
|
|
6774
7484
|
TestReporterBase
|
|
6775
7485
|
};
|
|
6776
|
-
//# sourceMappingURL=chunk-
|
|
7486
|
+
//# sourceMappingURL=chunk-DRZC45YG.js.map
|