@wdio/nightwatch-devtools 1.7.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +78 -43
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -6826,6 +6826,14 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
6826
6826
|
this.commandsLog.push(entry);
|
|
6827
6827
|
return { entry, oldTimestamp };
|
|
6828
6828
|
}
|
|
6829
|
+
/** Birth time of the document this capturer last observed, so a replacement
|
|
6830
|
+
* is still visible to a poll that starts after the navigation committed. */
|
|
6831
|
+
lastDocumentOrigin;
|
|
6832
|
+
/** The current document's own birth time, which is what a DOM anchor is
|
|
6833
|
+
* stamped with. Undefined when the session cannot answer. */
|
|
6834
|
+
async documentOrigin(browser) {
|
|
6835
|
+
return webdriverExecute(browser, "return performance.timeOrigin;").then((origin) => origin ?? void 0).catch(() => void 0);
|
|
6836
|
+
}
|
|
6829
6837
|
/**
|
|
6830
6838
|
* Wait for a navigation to actually replace the document, then drain with a
|
|
6831
6839
|
* forced anchor so the destination's DOM enters the stream.
|
|
@@ -6833,23 +6841,39 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
6833
6841
|
* A Nightwatch click resolves BEFORE its navigation commits, so the drain that
|
|
6834
6842
|
* runs at command completion still finds the outgoing page's collector: it
|
|
6835
6843
|
* recovers nothing, and the destination is never anchored — every action on the
|
|
6836
|
-
* new page then replays the page it came from.
|
|
6837
|
-
*
|
|
6838
|
-
*
|
|
6844
|
+
* new page then replays the page it came from.
|
|
6845
|
+
*
|
|
6846
|
+
* The replacement signal is the document's own `performance.timeOrigin`
|
|
6847
|
+
* changing, NOT the collector going missing. Under the preload every document
|
|
6848
|
+
* instruments itself at document-start, so the collector is never absent and
|
|
6849
|
+
* that older signal stood permanently false — the destination was then only
|
|
6850
|
+
* ever anchored by a drain that happened to be slow enough to land after the
|
|
6851
|
+
* navigation, and tightening that latency lost the destination page entirely.
|
|
6852
|
+
* A same-URL re-navigation is a new document and a new origin, so this covers
|
|
6853
|
+
* it too; a command that navigated nowhere polls out and costs one drain of an
|
|
6854
|
+
* empty buffer.
|
|
6855
|
+
*
|
|
6856
|
+
* The baseline is the last origin THIS capturer saw, never one read on entry.
|
|
6857
|
+
* Reading it here would compare the document against itself: a command that
|
|
6858
|
+
* completes AFTER its navigation committed (`browser.url` waits for load, so
|
|
6859
|
+
* that is the normal case) would baseline the destination and then report no
|
|
6860
|
+
* change, dropping the very anchor this exists to take. With no baseline yet
|
|
6861
|
+
* a navigation cannot be ruled out either, so the first DOM-mutating command
|
|
6862
|
+
* of a run anchors unconditionally rather than guessing — `captureCurrentDom`
|
|
6863
|
+
* is idempotent per document, so an already-anchored page costs one drain.
|
|
6839
6864
|
*/
|
|
6840
6865
|
async anchorAfterNavigation(browser) {
|
|
6866
|
+
const before = this.lastDocumentOrigin;
|
|
6841
6867
|
const replaced = await pollUntilReady(
|
|
6842
|
-
async () =>
|
|
6843
|
-
browser
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
// the full settle poll.
|
|
6852
|
-
this.preloadRegistered ? { attempts: 1, intervalMs: 0 } : { attempts: 5, intervalMs: 150 }
|
|
6868
|
+
async () => {
|
|
6869
|
+
const now = await this.documentOrigin(browser);
|
|
6870
|
+
if (now === void 0) {
|
|
6871
|
+
return false;
|
|
6872
|
+
}
|
|
6873
|
+
this.lastDocumentOrigin = now;
|
|
6874
|
+
return before === void 0 || now !== before;
|
|
6875
|
+
},
|
|
6876
|
+
{ attempts: 5, intervalMs: 150 }
|
|
6853
6877
|
);
|
|
6854
6878
|
if (!replaced) {
|
|
6855
6879
|
return;
|
|
@@ -6970,16 +6994,16 @@ var SessionCapturer = class extends SessionCapturerBase {
|
|
|
6970
6994
|
}
|
|
6971
6995
|
}
|
|
6972
6996
|
}
|
|
6973
|
-
/**
|
|
6974
|
-
* Capture trace data from the browser (network requests, console logs, etc.)
|
|
6975
|
-
*/
|
|
6976
6997
|
/** `forceAnchor` forces a full-DOM anchor of the current document before
|
|
6977
6998
|
* draining, so a freshly injected collector's async anchor isn't lost.
|
|
6978
6999
|
* `anchorTimestamp` is the command this drain's anchors were CAUSED by — pass
|
|
6979
7000
|
* it only when the caller observed the document being replaced right after
|
|
6980
7001
|
* that command, since it overrides the inference at ingest. */
|
|
6981
7002
|
async captureTrace(browser, forceAnchor = false, anchorTimestamp) {
|
|
7003
|
+
await this.drainCollector(browser, forceAnchor, anchorTimestamp);
|
|
6982
7004
|
await this.captureNetworkFromPerformanceLogs(browser);
|
|
7005
|
+
}
|
|
7006
|
+
async drainCollector(browser, forceAnchor, anchorTimestamp) {
|
|
6983
7007
|
try {
|
|
6984
7008
|
const traceData = await drainCollectorWithRecovery({
|
|
6985
7009
|
drain: () => webdriverExecute(
|
|
@@ -8081,6 +8105,7 @@ var BrowserProxy = class {
|
|
|
8081
8105
|
captureFreshCommand(browser, methodName, logArgs, serializedResult, meta, cmdSig, commandError) {
|
|
8082
8106
|
this.retryTracker.setLastSig(cmdSig);
|
|
8083
8107
|
this.retryTracker.setLastId(null);
|
|
8108
|
+
this.drainOutgoingPage(browser, methodName);
|
|
8084
8109
|
this.sessionCapturer.captureCommand(methodName, logArgs, serializedResult, commandError, meta).catch(
|
|
8085
8110
|
(err) => log7.error(`Failed to capture ${methodName}: ${err.message}`)
|
|
8086
8111
|
);
|
|
@@ -8091,32 +8116,10 @@ var BrowserProxy = class {
|
|
|
8091
8116
|
log7.info(`[command] ${methodName}`);
|
|
8092
8117
|
this.attachScreenshot(browser, lastCommand, methodName);
|
|
8093
8118
|
}
|
|
8094
|
-
this.
|
|
8119
|
+
this.anchorDestination(browser, methodName);
|
|
8095
8120
|
}
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
* reasons that no single drain can serve.
|
|
8099
|
-
*
|
|
8100
|
-
* The first drain fires synchronously, with no setTimeout in front. It used to
|
|
8101
|
-
* defer 200ms to stay off Nightwatch's callback stack, safe only because the
|
|
8102
|
-
* drain went through `browser.execute`, a QUEUED command; over the raw HTTP
|
|
8103
|
-
* transport it touches no queue, and because a driver serialises requests per
|
|
8104
|
-
* session, a drain issued here is served BEFORE the next queued command. That
|
|
8105
|
-
* is what captures the OUTGOING page's field edits — deferred, a submit click
|
|
8106
|
-
* navigated first and they died with the page, so the `#password` fill row
|
|
8107
|
-
* replayed with an empty password box.
|
|
8108
|
-
*
|
|
8109
|
-
* The second drain is what anchors the DESTINATION, and it has to wait: a
|
|
8110
|
-
* Nightwatch click resolves before its navigation commits, so the first drain
|
|
8111
|
-
* still finds the outgoing page's collector, recovers nothing, and the new
|
|
8112
|
-
* document is never anchored — every action on it then replayed the page it
|
|
8113
|
-
* came from (measured: 5 of 20 rows). `anchorAfterNavigation` keys off the
|
|
8114
|
-
* document actually being replaced rather than off which command ran, so it
|
|
8115
|
-
* covers any route to a new document — a submit click, a JS redirect, a
|
|
8116
|
-
* same-command re-navigation — without a list of commands to keep in sync.
|
|
8117
|
-
*/
|
|
8118
|
-
maybeRepollMutations(browser, methodName) {
|
|
8119
|
-
const isDomMutating = NAVIGATION_COMMANDS.includes(methodName) || [
|
|
8121
|
+
isDomMutating(methodName) {
|
|
8122
|
+
return NAVIGATION_COMMANDS.includes(methodName) || [
|
|
8120
8123
|
"click",
|
|
8121
8124
|
"doubleClick",
|
|
8122
8125
|
"rightClick",
|
|
@@ -8128,11 +8131,43 @@ var BrowserProxy = class {
|
|
|
8128
8131
|
"forward",
|
|
8129
8132
|
"refresh"
|
|
8130
8133
|
].includes(methodName);
|
|
8131
|
-
|
|
8134
|
+
}
|
|
8135
|
+
/**
|
|
8136
|
+
* Drains the OUTGOING page's field edits, which die with the document the
|
|
8137
|
+
* moment a submit navigates. It goes over the raw HTTP transport, so it
|
|
8138
|
+
* touches no Nightwatch queue, and a driver serialises requests per session —
|
|
8139
|
+
* so it is served before the next queued command only for as long as it stays
|
|
8140
|
+
* the FIRST request this class issues when a command completes. That call
|
|
8141
|
+
* position, and the drain-before-perf-logs order inside `captureTrace`, are
|
|
8142
|
+
* both load-bearing: behind the snapshot probes and the screenshot it needed
|
|
8143
|
+
* about 130 ms of head start and got 18 ms, and the last field a test filled
|
|
8144
|
+
* before submitting replayed as an empty box.
|
|
8145
|
+
*
|
|
8146
|
+
* It deliberately carries only this one request. `anchorAfterNavigation` is
|
|
8147
|
+
* issued later, from `anchorDestination`, so the row's own screenshot and DOM
|
|
8148
|
+
* snapshot are not pushed behind two round trips.
|
|
8149
|
+
*/
|
|
8150
|
+
drainOutgoingPage(browser, methodName) {
|
|
8151
|
+
if (!this.isDomMutating(methodName)) {
|
|
8132
8152
|
return;
|
|
8133
8153
|
}
|
|
8134
8154
|
this.sessionCapturer.captureTrace(browser, true).catch(() => {
|
|
8135
8155
|
});
|
|
8156
|
+
}
|
|
8157
|
+
/**
|
|
8158
|
+
* Anchors the DESTINATION, and it has to wait: a Nightwatch click resolves
|
|
8159
|
+
* before its navigation commits, so the outgoing drain still finds the old
|
|
8160
|
+
* page's collector, recovers nothing, and the new document is never anchored —
|
|
8161
|
+
* every action on it then replayed the page it came from (measured: 5 of 20
|
|
8162
|
+
* rows). `anchorAfterNavigation` keys off the document actually being replaced
|
|
8163
|
+
* rather than off which command ran, so it covers any route to a new document —
|
|
8164
|
+
* a submit click, a JS redirect, a same-command re-navigation — without a list
|
|
8165
|
+
* of commands to keep in sync.
|
|
8166
|
+
*/
|
|
8167
|
+
anchorDestination(browser, methodName) {
|
|
8168
|
+
if (!this.isDomMutating(methodName)) {
|
|
8169
|
+
return;
|
|
8170
|
+
}
|
|
8136
8171
|
this.sessionCapturer.snapshotCaptures.push(
|
|
8137
8172
|
this.sessionCapturer.anchorAfterNavigation(browser).catch(() => {
|
|
8138
8173
|
})
|