@wdio/nightwatch-devtools 1.8.2 → 2.0.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 +70 -16
- package/dist/{bidi-WNZOXX5X.js → bidi-AZX3WRGJ.js} +4 -2
- package/dist/{bidi-WNZOXX5X.js.map → bidi-AZX3WRGJ.js.map} +1 -1
- package/dist/{chunk-DM4FCAIJ.js → chunk-TUK7ZLQI.js} +627 -88
- package/dist/chunk-TUK7ZLQI.js.map +1 -0
- package/dist/index.js +244 -49
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
- package/dist/chunk-DM4FCAIJ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CAPTURE_PERFORMANCE_SCRIPT,
|
|
3
3
|
COLLECTOR_READY_EXPRESSION,
|
|
4
|
+
NETWORK_CAPTURE_SOURCE,
|
|
5
|
+
NativeNetworkCapture,
|
|
4
6
|
REUSE_ENV,
|
|
5
7
|
RetryTracker,
|
|
6
8
|
SCREENCAST_DEFAULTS,
|
|
@@ -47,9 +49,11 @@ import {
|
|
|
47
49
|
recordSpecBoundary,
|
|
48
50
|
registerCollectorPreload,
|
|
49
51
|
rememberReadValue,
|
|
52
|
+
requestsInterceptedNetwork,
|
|
50
53
|
resolveAdapterOutputDir,
|
|
51
54
|
resolveAssertTargetFromArgs,
|
|
52
55
|
resolveViewport,
|
|
56
|
+
restoreBrowserFocus,
|
|
53
57
|
safeSerializeAssertArg,
|
|
54
58
|
serializeError,
|
|
55
59
|
stampSuiteEnd,
|
|
@@ -58,9 +62,10 @@ import {
|
|
|
58
62
|
toError,
|
|
59
63
|
tracePolicyModeWarning,
|
|
60
64
|
upsertRichestSnapshot,
|
|
65
|
+
webdriverExecute,
|
|
61
66
|
webdriverGet,
|
|
62
67
|
webdriverPost
|
|
63
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-TUK7ZLQI.js";
|
|
64
69
|
|
|
65
70
|
// src/index.ts
|
|
66
71
|
import { fileURLToPath } from "url";
|
|
@@ -654,7 +659,7 @@ var firstDefined = (obj, ...keys) => {
|
|
|
654
659
|
}
|
|
655
660
|
return void 0;
|
|
656
661
|
};
|
|
657
|
-
function
|
|
662
|
+
function configuredWebDriver(browser) {
|
|
658
663
|
const transportSettings = getPath(browser, "transport", "settings", "webdriver") || getPath(browser, "queue", "transport", "settings", "webdriver") || getPath(
|
|
659
664
|
browser,
|
|
660
665
|
"nightwatchInstance",
|
|
@@ -664,13 +669,24 @@ function resolveWebDriverAddress(browser) {
|
|
|
664
669
|
) || {};
|
|
665
670
|
const opts = getProp(browser, "options") ?? {};
|
|
666
671
|
const nightwatchSettings = getPath(browser, "nightwatchInstance", "settings") || getPath(browser, "globals", "nightwatchInstance", "settings") || {};
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
);
|
|
673
|
-
return {
|
|
672
|
+
const sources = [
|
|
673
|
+
transportSettings,
|
|
674
|
+
getProp(opts, "webdriver"),
|
|
675
|
+
getProp(nightwatchSettings, "webdriver")
|
|
676
|
+
];
|
|
677
|
+
const pick = (...keys) => sources.map((source) => firstDefined(source, ...keys)).find(Boolean);
|
|
678
|
+
return {
|
|
679
|
+
host: pick("host", "server_address"),
|
|
680
|
+
port: pick("port"),
|
|
681
|
+
pathPrefix: pick("default_path_prefix")
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
function resolveWebDriverAddress(browser) {
|
|
685
|
+
const { host, port } = configuredWebDriver(browser);
|
|
686
|
+
return {
|
|
687
|
+
driverHost: String(host || "localhost"),
|
|
688
|
+
driverPort: Number(port || 9515)
|
|
689
|
+
};
|
|
674
690
|
}
|
|
675
691
|
function address(browser) {
|
|
676
692
|
const { driverHost, driverPort } = resolveWebDriverAddress(browser);
|
|
@@ -691,7 +707,21 @@ function webdriverPost2(browser, path5, body) {
|
|
|
691
707
|
const id = sessionId(browser);
|
|
692
708
|
return id ? webdriverPost(address(browser), id, path5, body) : Promise.resolve(null);
|
|
693
709
|
}
|
|
694
|
-
function
|
|
710
|
+
function sessionExecutor(browser) {
|
|
711
|
+
const id = sessionId(browser);
|
|
712
|
+
const { host, port, pathPrefix } = configuredWebDriver(browser);
|
|
713
|
+
if (!id || !port) {
|
|
714
|
+
return void 0;
|
|
715
|
+
}
|
|
716
|
+
const at = {
|
|
717
|
+
hostname: String(host || "localhost"),
|
|
718
|
+
port: Number(port),
|
|
719
|
+
path: typeof pathPrefix === "string" ? pathPrefix : void 0,
|
|
720
|
+
onWarn: (message) => log3.warn(message)
|
|
721
|
+
};
|
|
722
|
+
return (script, args) => webdriverExecute(at, id, script, args);
|
|
723
|
+
}
|
|
724
|
+
function webdriverExecute2(browser, body) {
|
|
695
725
|
return webdriverPost2(browser, "execute/sync", { script: body, args: [] });
|
|
696
726
|
}
|
|
697
727
|
|
|
@@ -706,7 +736,7 @@ function captureActionSnapshot2(browser, command, timestamp, runner, native = fa
|
|
|
706
736
|
runner,
|
|
707
737
|
takeScreenshot: () => webdriverGet2(browser, "screenshot"),
|
|
708
738
|
...native ? {} : {
|
|
709
|
-
runScript: (src) =>
|
|
739
|
+
runScript: (src) => webdriverExecute2(browser, `return (${src})`),
|
|
710
740
|
getUrl: () => webdriverGet2(browser, "url"),
|
|
711
741
|
getTitle: () => webdriverGet2(browser, "title")
|
|
712
742
|
}
|
|
@@ -714,6 +744,7 @@ function captureActionSnapshot2(browser, command, timestamp, runner, native = fa
|
|
|
714
744
|
}
|
|
715
745
|
|
|
716
746
|
// src/helpers/perfLogs.ts
|
|
747
|
+
var RESOURCE_TIMING_MATCH_MS = 2e3;
|
|
717
748
|
function applyResponseReceived(p, response) {
|
|
718
749
|
const responseHeaders = {};
|
|
719
750
|
for (const [k, v] of Object.entries(response.headers || {})) {
|
|
@@ -739,7 +770,9 @@ function startPendingRequest(params, entry, pending) {
|
|
|
739
770
|
url: req.url,
|
|
740
771
|
method: req.method,
|
|
741
772
|
requestHeaders: req.headers ?? {},
|
|
742
|
-
|
|
773
|
+
// Epoch, from the event's own wall clock: every consumer dates a row by
|
|
774
|
+
// `timestamp`, and the monotonic `startTime` only diffs within a session.
|
|
775
|
+
timestamp: typeof params.wallTime === "number" ? Math.round(params.wallTime * 1e3) : entry.timestamp,
|
|
743
776
|
startTime
|
|
744
777
|
});
|
|
745
778
|
}
|
|
@@ -797,6 +830,95 @@ function parseNetworkFromPerfLogs(logs) {
|
|
|
797
830
|
}
|
|
798
831
|
return completed;
|
|
799
832
|
}
|
|
833
|
+
function resourceTimingRowsByUrl(rows) {
|
|
834
|
+
const byUrl = /* @__PURE__ */ new Map();
|
|
835
|
+
rows.forEach((row, index) => {
|
|
836
|
+
if (row.source !== NETWORK_CAPTURE_SOURCE.RESOURCE_TIMING) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
const indexes = byUrl.get(row.url);
|
|
840
|
+
if (indexes) {
|
|
841
|
+
indexes.push(index);
|
|
842
|
+
} else {
|
|
843
|
+
byUrl.set(row.url, [index]);
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
return byUrl;
|
|
847
|
+
}
|
|
848
|
+
function takeNearestResourceTimingRow(indexes, rows, at) {
|
|
849
|
+
let best;
|
|
850
|
+
let bestDelta = RESOURCE_TIMING_MATCH_MS;
|
|
851
|
+
for (const index of indexes) {
|
|
852
|
+
const delta = Math.abs(rows[index].timestamp - at);
|
|
853
|
+
if (delta <= bestDelta) {
|
|
854
|
+
best = index;
|
|
855
|
+
bestDelta = delta;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
if (best !== void 0) {
|
|
859
|
+
indexes.splice(indexes.indexOf(best), 1);
|
|
860
|
+
}
|
|
861
|
+
return best;
|
|
862
|
+
}
|
|
863
|
+
function overlay(row, entry) {
|
|
864
|
+
const merged = {
|
|
865
|
+
...row,
|
|
866
|
+
method: entry.method,
|
|
867
|
+
requestHeaders: entry.requestHeaders,
|
|
868
|
+
type: entry.type ?? row.type,
|
|
869
|
+
...entry.status !== void 0 ? { status: entry.status } : {},
|
|
870
|
+
...entry.statusText !== void 0 ? { statusText: entry.statusText } : {},
|
|
871
|
+
...entry.responseHeaders ? { responseHeaders: entry.responseHeaders } : {},
|
|
872
|
+
...entry.size !== void 0 ? { size: entry.size } : {},
|
|
873
|
+
...entry.error !== void 0 ? { error: entry.error } : {}
|
|
874
|
+
};
|
|
875
|
+
delete merged.source;
|
|
876
|
+
return merged;
|
|
877
|
+
}
|
|
878
|
+
function withoutLoadsTheLogListed(payload, listed) {
|
|
879
|
+
const requests = payload.networkRequests;
|
|
880
|
+
if (!Array.isArray(requests) || listed.length === 0) {
|
|
881
|
+
return payload;
|
|
882
|
+
}
|
|
883
|
+
const rows = requests;
|
|
884
|
+
const rowsByUrl = resourceTimingRowsByUrl(rows);
|
|
885
|
+
const taken = /* @__PURE__ */ new Set();
|
|
886
|
+
for (const load of listed) {
|
|
887
|
+
const index = takeNearestResourceTimingRow(
|
|
888
|
+
rowsByUrl.get(load.url) ?? [],
|
|
889
|
+
rows,
|
|
890
|
+
load.timestamp
|
|
891
|
+
);
|
|
892
|
+
if (index !== void 0) {
|
|
893
|
+
taken.add(index);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (taken.size === 0) {
|
|
897
|
+
return payload;
|
|
898
|
+
}
|
|
899
|
+
return {
|
|
900
|
+
...payload,
|
|
901
|
+
networkRequests: rows.filter((_, index) => !taken.has(index))
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
function upgradeResourceTimingRows(incoming, existing) {
|
|
905
|
+
const rowsByUrl = resourceTimingRowsByUrl(existing);
|
|
906
|
+
const upgrades = [];
|
|
907
|
+
const fresh = [];
|
|
908
|
+
for (const entry of incoming) {
|
|
909
|
+
const index = takeNearestResourceTimingRow(
|
|
910
|
+
rowsByUrl.get(entry.url) ?? [],
|
|
911
|
+
existing,
|
|
912
|
+
entry.timestamp
|
|
913
|
+
);
|
|
914
|
+
if (index === void 0) {
|
|
915
|
+
fresh.push(entry);
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
upgrades.push({ index, request: overlay(existing[index], entry) });
|
|
919
|
+
}
|
|
920
|
+
return { upgrades, fresh };
|
|
921
|
+
}
|
|
800
922
|
function dedupeNetworkRequests(incoming, existing) {
|
|
801
923
|
const failedKey = (entry) => {
|
|
802
924
|
try {
|
|
@@ -849,6 +971,9 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
849
971
|
// True once BiDi inspectors are attached — the per-command perf-log network
|
|
850
972
|
// capture path skips when set, so we don't double-emit network requests.
|
|
851
973
|
bidiActive = false;
|
|
974
|
+
/** Whether BiDi has delivered at least one network event; a subscription
|
|
975
|
+
* that delivers nothing is not a source. */
|
|
976
|
+
bidiNetworkObserved = false;
|
|
852
977
|
/** Whether the session was created with `goog:loggingPrefs.performance`, set
|
|
853
978
|
* from the capabilities at session init. A perf log exists only because a
|
|
854
979
|
* session asked for one, so without it every fetch is a round trip that can
|
|
@@ -857,6 +982,10 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
857
982
|
* 21 of them in a two-test run, where XCUITest lists `performance` among its
|
|
858
983
|
* supported types and then serves none of it. */
|
|
859
984
|
perfLogsRequested = false;
|
|
985
|
+
/** Loads the performance log listed before the page's drain could, spent
|
|
986
|
+
* at the next drain that reaches the driver, whatever it finds, and
|
|
987
|
+
* emptied with the session that listed them. */
|
|
988
|
+
loadsListedByLog = [];
|
|
860
989
|
/** True once the collector is registered to run at document-start. Every
|
|
861
990
|
* document then instruments and anchors itself, so the paths that exist to
|
|
862
991
|
* notice a navigation after the fact — re-injection and the settle poll — have
|
|
@@ -869,6 +998,11 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
869
998
|
runner = nightwatchRunnerId(false);
|
|
870
999
|
actionSnapshots = [];
|
|
871
1000
|
snapshotCaptures = [];
|
|
1001
|
+
/** Native app network from appium-interceptor's proxy; started per session. */
|
|
1002
|
+
nativeNetwork = new NativeNetworkCapture(
|
|
1003
|
+
this,
|
|
1004
|
+
(level, message) => log4[level](message)
|
|
1005
|
+
);
|
|
872
1006
|
constructor(devtoolsOptions = {}, browser) {
|
|
873
1007
|
super(devtoolsOptions);
|
|
874
1008
|
this.#browser = browser;
|
|
@@ -1014,7 +1148,7 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
1014
1148
|
/** The current document's own birth time, which is what a DOM anchor is
|
|
1015
1149
|
* stamped with. Undefined when the session cannot answer. */
|
|
1016
1150
|
async documentOrigin(browser) {
|
|
1017
|
-
return
|
|
1151
|
+
return webdriverExecute2(browser, "return performance.timeOrigin;").then((origin) => origin ?? void 0).catch(() => void 0);
|
|
1018
1152
|
}
|
|
1019
1153
|
/**
|
|
1020
1154
|
* Wait for a navigation to actually replace the document, then drain with a
|
|
@@ -1097,7 +1231,7 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
1097
1231
|
return;
|
|
1098
1232
|
}
|
|
1099
1233
|
try {
|
|
1100
|
-
const alreadyPresent = await
|
|
1234
|
+
const alreadyPresent = await webdriverExecute2(
|
|
1101
1235
|
browser,
|
|
1102
1236
|
`return ${COLLECTOR_READY_EXPRESSION};`
|
|
1103
1237
|
);
|
|
@@ -1109,14 +1243,15 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
1109
1243
|
const script = document.createElement('script');
|
|
1110
1244
|
script.textContent = ${JSON.stringify(scriptContent)};
|
|
1111
1245
|
document.head.appendChild(script);
|
|
1112
|
-
return
|
|
1246
|
+
return ${COLLECTOR_READY_EXPRESSION};
|
|
1113
1247
|
`;
|
|
1114
|
-
await
|
|
1115
|
-
const hasCollector = await pollUntilReady(
|
|
1116
|
-
async () => await
|
|
1248
|
+
const injected = await webdriverExecute2(browser, injectionScript);
|
|
1249
|
+
const hasCollector = injected === true || await pollUntilReady(
|
|
1250
|
+
async () => await webdriverExecute2(
|
|
1117
1251
|
browser,
|
|
1118
1252
|
`return ${COLLECTOR_READY_EXPRESSION};`
|
|
1119
|
-
) === true
|
|
1253
|
+
) === true,
|
|
1254
|
+
{ checkFirst: true }
|
|
1120
1255
|
);
|
|
1121
1256
|
if (hasCollector) {
|
|
1122
1257
|
log4.info("\u2713 Script injected and collector ready");
|
|
@@ -1160,20 +1295,8 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
1160
1295
|
return;
|
|
1161
1296
|
}
|
|
1162
1297
|
const networkEntries = parseNetworkFromPerfLogs(logs);
|
|
1163
|
-
if (networkEntries.length
|
|
1164
|
-
|
|
1165
|
-
}
|
|
1166
|
-
const deduped = dedupeNetworkRequests(
|
|
1167
|
-
networkEntries,
|
|
1168
|
-
this.networkRequests
|
|
1169
|
-
);
|
|
1170
|
-
if (deduped.length > 0) {
|
|
1171
|
-
const normalized = deduped.map((d) => ({
|
|
1172
|
-
...d,
|
|
1173
|
-
type: d.type ?? "other"
|
|
1174
|
-
}));
|
|
1175
|
-
this.networkRequests.push(...normalized);
|
|
1176
|
-
this.sendUpstream("networkRequests", normalized);
|
|
1298
|
+
if (networkEntries.length > 0) {
|
|
1299
|
+
this.#ingestPerfLogEntries(networkEntries);
|
|
1177
1300
|
}
|
|
1178
1301
|
} catch (err) {
|
|
1179
1302
|
const msg = errorMessage(err) ?? "";
|
|
@@ -1182,6 +1305,30 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
1182
1305
|
}
|
|
1183
1306
|
}
|
|
1184
1307
|
}
|
|
1308
|
+
/** A log entry for a load the page already reported replaces that row in
|
|
1309
|
+
* place, under the row's own id; the rest are appended once. */
|
|
1310
|
+
#ingestPerfLogEntries(entries) {
|
|
1311
|
+
const { upgrades, fresh } = upgradeResourceTimingRows(
|
|
1312
|
+
entries,
|
|
1313
|
+
this.networkRequests
|
|
1314
|
+
);
|
|
1315
|
+
for (const { index, request } of upgrades) {
|
|
1316
|
+
this.networkRequests[index] = request;
|
|
1317
|
+
}
|
|
1318
|
+
const deduped = dedupeNetworkRequests(
|
|
1319
|
+
fresh,
|
|
1320
|
+
this.networkRequests
|
|
1321
|
+
);
|
|
1322
|
+
const appended = deduped.map((d) => ({ ...d, type: d.type ?? "other" }));
|
|
1323
|
+
this.networkRequests.push(...appended);
|
|
1324
|
+
this.loadsListedByLog.push(
|
|
1325
|
+
...appended.map(({ url, timestamp }) => ({ url, timestamp }))
|
|
1326
|
+
);
|
|
1327
|
+
const sent = [...upgrades.map((upgrade) => upgrade.request), ...appended];
|
|
1328
|
+
if (sent.length > 0) {
|
|
1329
|
+
this.sendUpstream("networkRequests", sent);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1185
1332
|
/** `forceAnchor` forces a full-DOM anchor of the current document before
|
|
1186
1333
|
* draining, so a freshly injected collector's async anchor isn't lost.
|
|
1187
1334
|
* `anchorTimestamp` is the command this drain's anchors were CAUSED by — pass
|
|
@@ -1189,28 +1336,45 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
1189
1336
|
* that command, since it overrides the inference at ingest. */
|
|
1190
1337
|
async captureTrace(browser, forceAnchor = false, anchorTimestamp) {
|
|
1191
1338
|
if (this.isNativeAppSession) {
|
|
1339
|
+
await this.nativeNetwork.forward({ throttle: true });
|
|
1192
1340
|
return;
|
|
1193
1341
|
}
|
|
1194
1342
|
await this.drainCollector(browser, forceAnchor, anchorTimestamp);
|
|
1195
1343
|
await this.captureNetworkFromPerformanceLogs(browser);
|
|
1196
1344
|
}
|
|
1345
|
+
/** At a test or scenario end, before its slice is written: the proxy drain there is never throttled. */
|
|
1346
|
+
async captureTraceAtTestEnd(browser) {
|
|
1347
|
+
if (this.isNativeAppSession) {
|
|
1348
|
+
await this.nativeNetwork.forward();
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
await this.captureTrace(browser, true);
|
|
1352
|
+
}
|
|
1197
1353
|
async drainCollector(browser, forceAnchor, anchorTimestamp) {
|
|
1198
1354
|
try {
|
|
1199
1355
|
const traceData = await drainCollectorWithRecovery({
|
|
1200
|
-
drain: () =>
|
|
1356
|
+
drain: () => webdriverExecute2(
|
|
1201
1357
|
browser,
|
|
1202
1358
|
collectorDrainExpression(forceAnchor)
|
|
1203
1359
|
),
|
|
1204
1360
|
injectIntoCurrentDocument: () => this.injectScript(browser),
|
|
1205
|
-
currentUrl: () =>
|
|
1361
|
+
currentUrl: () => webdriverExecute2(browser, "return location.href;").then(
|
|
1206
1362
|
(u) => u ?? void 0
|
|
1207
1363
|
),
|
|
1208
1364
|
log: (level, message) => log4[level](message)
|
|
1209
1365
|
});
|
|
1366
|
+
const listedByLog = this.loadsListedByLog;
|
|
1367
|
+
this.loadsListedByLog = [];
|
|
1210
1368
|
if (!traceData) {
|
|
1211
1369
|
return;
|
|
1212
1370
|
}
|
|
1213
|
-
this.processTracePayload(
|
|
1371
|
+
this.processTracePayload(
|
|
1372
|
+
withoutLoadsTheLogListed(traceData, listedByLog),
|
|
1373
|
+
{
|
|
1374
|
+
anchorTimestamp,
|
|
1375
|
+
skipResourceTimingRequests: this.bidiNetworkObserved
|
|
1376
|
+
}
|
|
1377
|
+
);
|
|
1214
1378
|
const mutationCount = Array.isArray(
|
|
1215
1379
|
traceData.mutations
|
|
1216
1380
|
) ? traceData.mutations.length : 0;
|
|
@@ -1624,17 +1788,23 @@ function callbackError(result, depth = 0) {
|
|
|
1624
1788
|
return void 0;
|
|
1625
1789
|
}
|
|
1626
1790
|
const r = result;
|
|
1627
|
-
if ("
|
|
1628
|
-
return depth < 2 ? callbackError(r.value, depth + 1) : void 0;
|
|
1629
|
-
}
|
|
1630
|
-
if ("passed" in r || !r.error) {
|
|
1791
|
+
if ("passed" in r) {
|
|
1631
1792
|
return void 0;
|
|
1632
1793
|
}
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1794
|
+
if (r.error instanceof Error) {
|
|
1795
|
+
return r.error;
|
|
1796
|
+
}
|
|
1797
|
+
if (r.error) {
|
|
1798
|
+
const err = new Error(String(r.message ?? r.error));
|
|
1799
|
+
if (typeof r.stack === "string") {
|
|
1800
|
+
err.stack = r.stack;
|
|
1801
|
+
}
|
|
1802
|
+
return err;
|
|
1803
|
+
}
|
|
1804
|
+
if ("value" in r) {
|
|
1805
|
+
return depth < 2 ? callbackError(r.value, depth + 1) : void 0;
|
|
1636
1806
|
}
|
|
1637
|
-
return
|
|
1807
|
+
return void 0;
|
|
1638
1808
|
}
|
|
1639
1809
|
|
|
1640
1810
|
// src/helpers/assertTarget.ts
|
|
@@ -2308,6 +2478,9 @@ var BrowserProxy = class {
|
|
|
2308
2478
|
this.attachScreenshot(browser, lastCommand, methodName);
|
|
2309
2479
|
}
|
|
2310
2480
|
this.anchorDestination(browser, methodName);
|
|
2481
|
+
if (!this.isDomMutating(methodName)) {
|
|
2482
|
+
void this.sessionCapturer.nativeNetwork.forward({ throttle: true });
|
|
2483
|
+
}
|
|
2311
2484
|
}
|
|
2312
2485
|
isDomMutating(methodName) {
|
|
2313
2486
|
return NAVIGATION_COMMANDS.includes(methodName) || [
|
|
@@ -2636,7 +2809,7 @@ function initReporterChain(ctx) {
|
|
|
2636
2809
|
}
|
|
2637
2810
|
function readViewport(browser) {
|
|
2638
2811
|
return resolveViewport(browser.capabilities || {}, {
|
|
2639
|
-
runScript: (body) =>
|
|
2812
|
+
runScript: (body) => webdriverExecute2(browser, body),
|
|
2640
2813
|
getWindowSize: () => webdriverGet2(browser, "window/rect"),
|
|
2641
2814
|
onWarn: (message) => log10.warn(message)
|
|
2642
2815
|
});
|
|
@@ -2674,6 +2847,18 @@ async function broadcastSessionMetadata(ctx, browser) {
|
|
|
2674
2847
|
log10.info(
|
|
2675
2848
|
`\u2713 Browser: ${browserName}${browserVersion ? " " + browserVersion : ""} (session: ${sessionId2})`
|
|
2676
2849
|
);
|
|
2850
|
+
if (ctx.mode === "live" && restoreBrowserFocus({
|
|
2851
|
+
browserName: String(browserName),
|
|
2852
|
+
platformName: String(
|
|
2853
|
+
capabilities.platformName || desiredCapabilities.platformName || ""
|
|
2854
|
+
),
|
|
2855
|
+
host: resolveWebDriverAddress(browser).driverHost,
|
|
2856
|
+
onError: (message) => log10.warn(message)
|
|
2857
|
+
})) {
|
|
2858
|
+
log10.info(
|
|
2859
|
+
"\u2713 Safari brought back to the front (it delivers clicks only there)"
|
|
2860
|
+
);
|
|
2861
|
+
}
|
|
2677
2862
|
const wantsPerfLog = wantsPerformanceLog(
|
|
2678
2863
|
capabilities,
|
|
2679
2864
|
desiredCapabilities
|
|
@@ -2681,7 +2866,7 @@ async function broadcastSessionMetadata(ctx, browser) {
|
|
|
2681
2866
|
ctx.sessionCapturer.perfLogsRequested = wantsPerfLog;
|
|
2682
2867
|
if (!wantsPerfLog && !ctx.bidiEnabled) {
|
|
2683
2868
|
log10.warn(
|
|
2684
|
-
"\u26A0 Network tab will
|
|
2869
|
+
"\u26A0 Network tab will carry the page's own Resource Timing only (no headers, no bodies). Add 'goog:loggingPrefs': { performance: 'ALL' } to your capabilities (or enable bidi:true) for full requests"
|
|
2685
2870
|
);
|
|
2686
2871
|
}
|
|
2687
2872
|
}
|
|
@@ -2694,7 +2879,7 @@ async function tryAttachBidi(ctx, browser) {
|
|
|
2694
2879
|
log10.warn("bidi:true set but browser.driver unavailable \u2014 skipping");
|
|
2695
2880
|
return;
|
|
2696
2881
|
}
|
|
2697
|
-
const { attachBidiHandlers, buildBidiSinks } = await import("./bidi-
|
|
2882
|
+
const { attachBidiHandlers, buildBidiSinks } = await import("./bidi-AZX3WRGJ.js");
|
|
2698
2883
|
const ok = await attachBidiHandlers(
|
|
2699
2884
|
driver,
|
|
2700
2885
|
buildBidiSinks(ctx.sessionCapturer)
|
|
@@ -2718,6 +2903,12 @@ async function armCaptureForSession(ctx, browser) {
|
|
|
2718
2903
|
ctx.armedSessionId = browser.sessionId ?? void 0;
|
|
2719
2904
|
await tryRegisterPreload(ctx, browser);
|
|
2720
2905
|
await tryAttachBidi(ctx, browser);
|
|
2906
|
+
await ctx.sessionCapturer.nativeNetwork.start({
|
|
2907
|
+
requested: requestsInterceptedNetwork(browser.desiredCapabilities),
|
|
2908
|
+
capabilities: browser.capabilities,
|
|
2909
|
+
execute: sessionExecutor(browser),
|
|
2910
|
+
unavailableReason: "the session id or the configured WebDriver port is unknown"
|
|
2911
|
+
});
|
|
2721
2912
|
}
|
|
2722
2913
|
function needsCaptureRearm(ctx, sessionId2) {
|
|
2723
2914
|
return Boolean(ctx.sessionCapturer) && sessionId2 !== void 0 && ctx.armedSessionId !== void 0 && ctx.armedSessionId !== sessionId2;
|
|
@@ -2729,6 +2920,9 @@ async function armReplacedSession(ctx, browser) {
|
|
|
2729
2920
|
}
|
|
2730
2921
|
ctx.sessionCapturer.preloadRegistered = false;
|
|
2731
2922
|
ctx.sessionCapturer.bidiActive = false;
|
|
2923
|
+
ctx.sessionCapturer.bidiNetworkObserved = false;
|
|
2924
|
+
ctx.sessionCapturer.loadsListedByLog = [];
|
|
2925
|
+
ctx.sessionCapturer.nativeNetwork.stop();
|
|
2732
2926
|
log10.info(`Session replaced \u2014 re-arming capture for ${sessionId2}`);
|
|
2733
2927
|
await armCaptureForSession(ctx, browser);
|
|
2734
2928
|
}
|
|
@@ -3215,7 +3409,7 @@ async function captureCucumberScenarioBeforeQuit(ctx, browser, result) {
|
|
|
3215
3409
|
assertCalls
|
|
3216
3410
|
);
|
|
3217
3411
|
}
|
|
3218
|
-
await ctx.sessionCapturer.
|
|
3412
|
+
await ctx.sessionCapturer.captureTraceAtTestEnd(browser);
|
|
3219
3413
|
flushTestSlice(ctx);
|
|
3220
3414
|
await ctx.emitTestArtifacts(
|
|
3221
3415
|
scenario?.uid,
|
|
@@ -3936,7 +4130,7 @@ var NightwatchDevToolsPlugin = class {
|
|
|
3936
4130
|
this.browserProxy.drainNativeAssertCalls()
|
|
3937
4131
|
);
|
|
3938
4132
|
}
|
|
3939
|
-
await this.sessionCapturer.
|
|
4133
|
+
await this.sessionCapturer.captureTraceAtTestEnd(browser);
|
|
3940
4134
|
flushTestSlice(this.#getInternals());
|
|
3941
4135
|
const results = browser.currentTest?.results;
|
|
3942
4136
|
const failed = !!results && ((results.errors ?? 0) > 0 || (results.failed ?? 0) > 0);
|
|
@@ -3982,6 +4176,7 @@ var NightwatchDevToolsPlugin = class {
|
|
|
3982
4176
|
});
|
|
3983
4177
|
}
|
|
3984
4178
|
async after(browser) {
|
|
4179
|
+
this.sessionCapturer?.nativeNetwork.stop();
|
|
3985
4180
|
await this.#screencast.rotation;
|
|
3986
4181
|
await this.#finalizeCurrentScreencast();
|
|
3987
4182
|
try {
|