@checkly/playwright-core 1.41.2-beta.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/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +3 -0
- package/ThirdPartyNotices.txt +1513 -0
- package/bin/PrintDeps.exe +0 -0
- package/bin/README.md +2 -0
- package/bin/install_media_pack.ps1 +5 -0
- package/bin/reinstall_chrome_beta_linux.sh +40 -0
- package/bin/reinstall_chrome_beta_mac.sh +13 -0
- package/bin/reinstall_chrome_beta_win.ps1 +23 -0
- package/bin/reinstall_chrome_stable_linux.sh +40 -0
- package/bin/reinstall_chrome_stable_mac.sh +12 -0
- package/bin/reinstall_chrome_stable_win.ps1 +23 -0
- package/bin/reinstall_msedge_beta_linux.sh +40 -0
- package/bin/reinstall_msedge_beta_mac.sh +11 -0
- package/bin/reinstall_msedge_beta_win.ps1 +22 -0
- package/bin/reinstall_msedge_dev_linux.sh +40 -0
- package/bin/reinstall_msedge_dev_mac.sh +11 -0
- package/bin/reinstall_msedge_dev_win.ps1 +22 -0
- package/bin/reinstall_msedge_stable_linux.sh +40 -0
- package/bin/reinstall_msedge_stable_mac.sh +11 -0
- package/bin/reinstall_msedge_stable_win.ps1 +23 -0
- package/browsers.json +64 -0
- package/cli.js +17 -0
- package/index.d.ts +17 -0
- package/index.js +33 -0
- package/index.mjs +28 -0
- package/lib/androidServerImpl.js +69 -0
- package/lib/browserServerImpl.js +92 -0
- package/lib/cli/driver.js +97 -0
- package/lib/cli/program.js +582 -0
- package/lib/cli/programWithTestStub.js +67 -0
- package/lib/client/accessibility.js +50 -0
- package/lib/client/android.js +473 -0
- package/lib/client/api.js +272 -0
- package/lib/client/artifact.js +79 -0
- package/lib/client/browser.js +145 -0
- package/lib/client/browserContext.js +509 -0
- package/lib/client/browserType.js +233 -0
- package/lib/client/cdpSession.js +53 -0
- package/lib/client/channelOwner.js +229 -0
- package/lib/client/clientHelper.js +57 -0
- package/lib/client/clientInstrumentation.js +40 -0
- package/lib/client/connection.js +327 -0
- package/lib/client/consoleMessage.js +55 -0
- package/lib/client/coverage.js +41 -0
- package/lib/client/dialog.js +57 -0
- package/lib/client/download.js +62 -0
- package/lib/client/electron.js +130 -0
- package/lib/client/elementHandle.js +291 -0
- package/lib/client/errors.js +77 -0
- package/lib/client/events.js +93 -0
- package/lib/client/fetch.js +343 -0
- package/lib/client/fileChooser.js +45 -0
- package/lib/client/frame.js +506 -0
- package/lib/client/harRouter.js +93 -0
- package/lib/client/input.js +111 -0
- package/lib/client/jsHandle.js +123 -0
- package/lib/client/jsonPipe.js +35 -0
- package/lib/client/localUtils.js +35 -0
- package/lib/client/locator.js +432 -0
- package/lib/client/network.js +601 -0
- package/lib/client/page.js +707 -0
- package/lib/client/playwright.js +74 -0
- package/lib/client/selectors.js +67 -0
- package/lib/client/stream.js +54 -0
- package/lib/client/tracing.js +135 -0
- package/lib/client/types.js +24 -0
- package/lib/client/video.js +51 -0
- package/lib/client/waiter.js +158 -0
- package/lib/client/webError.js +37 -0
- package/lib/client/worker.js +71 -0
- package/lib/client/writableStream.js +54 -0
- package/lib/common/socksProxy.js +569 -0
- package/lib/common/timeoutSettings.js +73 -0
- package/lib/common/types.js +5 -0
- package/lib/generated/consoleApiSource.js +7 -0
- package/lib/generated/injectedScriptSource.js +7 -0
- package/lib/generated/recorderSource.js +7 -0
- package/lib/generated/utilityScriptSource.js +7 -0
- package/lib/image_tools/colorUtils.js +98 -0
- package/lib/image_tools/compare.js +108 -0
- package/lib/image_tools/imageChannel.js +70 -0
- package/lib/image_tools/stats.js +102 -0
- package/lib/inProcessFactory.js +54 -0
- package/lib/inprocess.js +20 -0
- package/lib/outofprocess.js +67 -0
- package/lib/protocol/debug.js +27 -0
- package/lib/protocol/serializers.js +172 -0
- package/lib/protocol/transport.js +82 -0
- package/lib/protocol/validator.js +2599 -0
- package/lib/protocol/validatorPrimitives.js +139 -0
- package/lib/remote/playwrightConnection.js +274 -0
- package/lib/remote/playwrightServer.js +110 -0
- package/lib/server/accessibility.js +62 -0
- package/lib/server/android/android.js +441 -0
- package/lib/server/android/backendAdb.js +172 -0
- package/lib/server/artifact.js +104 -0
- package/lib/server/browser.js +129 -0
- package/lib/server/browserContext.js +609 -0
- package/lib/server/browserType.js +300 -0
- package/lib/server/chromium/appIcon.png +0 -0
- package/lib/server/chromium/chromium.js +346 -0
- package/lib/server/chromium/chromiumSwitches.js +41 -0
- package/lib/server/chromium/crAccessibility.js +237 -0
- package/lib/server/chromium/crBrowser.js +521 -0
- package/lib/server/chromium/crConnection.js +228 -0
- package/lib/server/chromium/crCoverage.js +246 -0
- package/lib/server/chromium/crDevTools.js +104 -0
- package/lib/server/chromium/crDragDrop.js +144 -0
- package/lib/server/chromium/crExecutionContext.js +156 -0
- package/lib/server/chromium/crInput.js +171 -0
- package/lib/server/chromium/crNetworkManager.js +723 -0
- package/lib/server/chromium/crPage.js +1173 -0
- package/lib/server/chromium/crPdf.js +147 -0
- package/lib/server/chromium/crProtocolHelper.js +131 -0
- package/lib/server/chromium/crServiceWorker.js +115 -0
- package/lib/server/chromium/defaultFontFamilies.js +145 -0
- package/lib/server/chromium/videoRecorder.js +155 -0
- package/lib/server/console.js +59 -0
- package/lib/server/cookieStore.js +112 -0
- package/lib/server/debugController.js +236 -0
- package/lib/server/debugger.js +132 -0
- package/lib/server/deviceDescriptors.js +21 -0
- package/lib/server/deviceDescriptorsSource.json +1549 -0
- package/lib/server/dialog.js +70 -0
- package/lib/server/dispatchers/androidDispatcher.js +193 -0
- package/lib/server/dispatchers/artifactDispatcher.js +118 -0
- package/lib/server/dispatchers/browserContextDispatcher.js +306 -0
- package/lib/server/dispatchers/browserDispatcher.js +170 -0
- package/lib/server/dispatchers/browserTypeDispatcher.js +55 -0
- package/lib/server/dispatchers/cdpSessionDispatcher.js +48 -0
- package/lib/server/dispatchers/debugControllerDispatcher.js +103 -0
- package/lib/server/dispatchers/dialogDispatcher.js +44 -0
- package/lib/server/dispatchers/dispatcher.js +400 -0
- package/lib/server/dispatchers/electronDispatcher.js +80 -0
- package/lib/server/dispatchers/elementHandlerDispatcher.js +228 -0
- package/lib/server/dispatchers/frameDispatcher.js +287 -0
- package/lib/server/dispatchers/jsHandleDispatcher.js +102 -0
- package/lib/server/dispatchers/jsonPipeDispatcher.js +61 -0
- package/lib/server/dispatchers/localUtilsDispatcher.js +399 -0
- package/lib/server/dispatchers/networkDispatchers.js +221 -0
- package/lib/server/dispatchers/pageDispatcher.js +363 -0
- package/lib/server/dispatchers/playwrightDispatcher.js +105 -0
- package/lib/server/dispatchers/selectorsDispatcher.js +36 -0
- package/lib/server/dispatchers/streamDispatcher.js +62 -0
- package/lib/server/dispatchers/tracingDispatcher.js +54 -0
- package/lib/server/dispatchers/writableStreamDispatcher.js +55 -0
- package/lib/server/dom.js +808 -0
- package/lib/server/download.js +53 -0
- package/lib/server/electron/electron.js +254 -0
- package/lib/server/electron/loader.js +57 -0
- package/lib/server/errors.js +68 -0
- package/lib/server/fetch.js +611 -0
- package/lib/server/fileChooser.js +42 -0
- package/lib/server/fileUploadUtils.js +71 -0
- package/lib/server/firefox/ffAccessibility.js +215 -0
- package/lib/server/firefox/ffBrowser.js +447 -0
- package/lib/server/firefox/ffConnection.js +168 -0
- package/lib/server/firefox/ffExecutionContext.js +138 -0
- package/lib/server/firefox/ffInput.js +150 -0
- package/lib/server/firefox/ffNetworkManager.js +231 -0
- package/lib/server/firefox/ffPage.js +558 -0
- package/lib/server/firefox/firefox.js +91 -0
- package/lib/server/formData.js +75 -0
- package/lib/server/frameSelectors.js +171 -0
- package/lib/server/frames.js +1597 -0
- package/lib/server/har/harRecorder.js +139 -0
- package/lib/server/har/harTracer.js +539 -0
- package/lib/server/helper.js +103 -0
- package/lib/server/index.js +96 -0
- package/lib/server/input.js +301 -0
- package/lib/server/instrumentation.js +74 -0
- package/lib/server/isomorphic/utilityScriptSerializers.js +212 -0
- package/lib/server/javascript.js +305 -0
- package/lib/server/launchApp.js +90 -0
- package/lib/server/macEditingCommands.js +139 -0
- package/lib/server/network.js +607 -0
- package/lib/server/page.js +793 -0
- package/lib/server/pipeTransport.js +85 -0
- package/lib/server/playwright.js +82 -0
- package/lib/server/progress.js +102 -0
- package/lib/server/protocolError.js +49 -0
- package/lib/server/recorder/codeGenerator.js +153 -0
- package/lib/server/recorder/csharp.js +310 -0
- package/lib/server/recorder/java.js +216 -0
- package/lib/server/recorder/javascript.js +229 -0
- package/lib/server/recorder/jsonl.js +47 -0
- package/lib/server/recorder/language.js +44 -0
- package/lib/server/recorder/python.js +275 -0
- package/lib/server/recorder/recorderActions.js +5 -0
- package/lib/server/recorder/recorderApp.js +181 -0
- package/lib/server/recorder/recorderUtils.js +48 -0
- package/lib/server/recorder/utils.js +45 -0
- package/lib/server/recorder.js +700 -0
- package/lib/server/registry/browserFetcher.js +168 -0
- package/lib/server/registry/dependencies.js +322 -0
- package/lib/server/registry/index.js +925 -0
- package/lib/server/registry/nativeDeps.js +383 -0
- package/lib/server/registry/oopDownloadBrowserMain.js +138 -0
- package/lib/server/screenshotter.js +354 -0
- package/lib/server/selectors.js +73 -0
- package/lib/server/socksInterceptor.js +100 -0
- package/lib/server/trace/recorder/snapshotter.js +168 -0
- package/lib/server/trace/recorder/snapshotterInjected.js +493 -0
- package/lib/server/trace/recorder/tracing.js +552 -0
- package/lib/server/trace/test/inMemorySnapshotter.js +93 -0
- package/lib/server/trace/viewer/traceViewer.js +229 -0
- package/lib/server/transport.js +191 -0
- package/lib/server/types.js +24 -0
- package/lib/server/usKeyboardLayout.js +555 -0
- package/lib/server/webkit/webkit.js +87 -0
- package/lib/server/webkit/wkAccessibility.js +194 -0
- package/lib/server/webkit/wkBrowser.js +328 -0
- package/lib/server/webkit/wkConnection.js +173 -0
- package/lib/server/webkit/wkExecutionContext.js +146 -0
- package/lib/server/webkit/wkInput.js +169 -0
- package/lib/server/webkit/wkInterceptableRequest.js +158 -0
- package/lib/server/webkit/wkPage.js +1198 -0
- package/lib/server/webkit/wkProvisionalPage.js +59 -0
- package/lib/server/webkit/wkWorkers.js +104 -0
- package/lib/third_party/diff_match_patch.js +2222 -0
- package/lib/third_party/pixelmatch.js +255 -0
- package/lib/utils/ascii.js +31 -0
- package/lib/utils/comparators.js +171 -0
- package/lib/utils/crypto.js +33 -0
- package/lib/utils/debug.js +46 -0
- package/lib/utils/debugLogger.js +89 -0
- package/lib/utils/env.js +47 -0
- package/lib/utils/eventsHelper.js +38 -0
- package/lib/utils/fileUtils.js +66 -0
- package/lib/utils/glob.js +83 -0
- package/lib/utils/happy-eyeballs.js +154 -0
- package/lib/utils/headers.js +52 -0
- package/lib/utils/hostPlatform.js +124 -0
- package/lib/utils/httpServer.js +195 -0
- package/lib/utils/index.js +324 -0
- package/lib/utils/isomorphic/cssParser.js +250 -0
- package/lib/utils/isomorphic/cssTokenizer.js +979 -0
- package/lib/utils/isomorphic/locatorGenerators.js +651 -0
- package/lib/utils/isomorphic/locatorParser.js +179 -0
- package/lib/utils/isomorphic/locatorUtils.js +62 -0
- package/lib/utils/isomorphic/selectorParser.js +397 -0
- package/lib/utils/isomorphic/stringUtils.js +107 -0
- package/lib/utils/isomorphic/traceUtils.js +39 -0
- package/lib/utils/linuxUtils.js +78 -0
- package/lib/utils/manualPromise.js +109 -0
- package/lib/utils/mimeType.js +29 -0
- package/lib/utils/multimap.js +75 -0
- package/lib/utils/network.js +189 -0
- package/lib/utils/processLauncher.js +248 -0
- package/lib/utils/profiler.js +53 -0
- package/lib/utils/rtti.js +41 -0
- package/lib/utils/semaphore.js +51 -0
- package/lib/utils/spawnAsync.js +45 -0
- package/lib/utils/stackTrace.js +123 -0
- package/lib/utils/task.js +58 -0
- package/lib/utils/time.js +37 -0
- package/lib/utils/timeoutRunner.js +131 -0
- package/lib/utils/traceUtils.js +44 -0
- package/lib/utils/userAgent.js +105 -0
- package/lib/utils/wsServer.js +125 -0
- package/lib/utils/zipFile.js +75 -0
- package/lib/utils/zones.js +99 -0
- package/lib/utilsBundle.js +81 -0
- package/lib/utilsBundleImpl/index.js +51 -0
- package/lib/utilsBundleImpl/xdg-open +1066 -0
- package/lib/vite/htmlReport/index.html +66 -0
- package/lib/vite/recorder/assets/codeMirrorModule-Hs9-1ZG4.css +1 -0
- package/lib/vite/recorder/assets/codeMirrorModule-I9ks4y7D.js +24 -0
- package/lib/vite/recorder/assets/codicon-zGuYmc9o.ttf +0 -0
- package/lib/vite/recorder/assets/index-ljsTwXtJ.css +1 -0
- package/lib/vite/recorder/assets/index-yg8ypzl6.js +47 -0
- package/lib/vite/recorder/index.html +29 -0
- package/lib/vite/recorder/playwright-logo.svg +9 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-GluP1cQ1.js +24 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-fqJB1XDu.js +24 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-y3M3aAqy.js +24 -0
- package/lib/vite/traceViewer/assets/wsPort-Rvwd4WC-.js +69 -0
- package/lib/vite/traceViewer/assets/wsPort-dlD7vDkY.js +69 -0
- package/lib/vite/traceViewer/assets/wsPort-qOE2NWrO.js +69 -0
- package/lib/vite/traceViewer/assets/xtermModule-Yt6xwiJ_.js +9 -0
- package/lib/vite/traceViewer/codeMirrorModule.Hs9-1ZG4.css +1 -0
- package/lib/vite/traceViewer/codicon.zGuYmc9o.ttf +0 -0
- package/lib/vite/traceViewer/index.-g_5lMbJ.css +1 -0
- package/lib/vite/traceViewer/index.4X7zDysg.js +2 -0
- package/lib/vite/traceViewer/index.HkJgzlGy.js +2 -0
- package/lib/vite/traceViewer/index.html +26 -0
- package/lib/vite/traceViewer/index.kRjx5sAJ.js +2 -0
- package/lib/vite/traceViewer/playwright-logo.svg +9 -0
- package/lib/vite/traceViewer/snapshot.html +21 -0
- package/lib/vite/traceViewer/sw.bundle.js +4 -0
- package/lib/vite/traceViewer/uiMode.1Wcp_Kto.js +10 -0
- package/lib/vite/traceViewer/uiMode.GTNzARcV.js +10 -0
- package/lib/vite/traceViewer/uiMode.html +17 -0
- package/lib/vite/traceViewer/uiMode.pWy0Re7G.css +1 -0
- package/lib/vite/traceViewer/uiMode.zV-7Lf9v.js +10 -0
- package/lib/vite/traceViewer/wsPort.kSgQKQ0y.css +1 -0
- package/lib/vite/traceViewer/xtermModule.0lwXJFHT.css +32 -0
- package/lib/zipBundle.js +25 -0
- package/lib/zipBundleImpl.js +5 -0
- package/package.json +43 -0
- package/types/protocol.d.ts +20304 -0
- package/types/structs.d.ts +45 -0
- package/types/types.d.ts +20626 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Snapshotter = void 0;
|
|
7
|
+
var _browserContext = require("../../browserContext");
|
|
8
|
+
var _page = require("../../page");
|
|
9
|
+
var _eventsHelper = require("../../../utils/eventsHelper");
|
|
10
|
+
var _debugLogger = require("../../../utils/debugLogger");
|
|
11
|
+
var _snapshotterInjected = require("./snapshotterInjected");
|
|
12
|
+
var _utils = require("../../../utils");
|
|
13
|
+
var _utilsBundle = require("../../../utilsBundle");
|
|
14
|
+
/**
|
|
15
|
+
* Copyright (c) Microsoft Corporation.
|
|
16
|
+
*
|
|
17
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
18
|
+
* you may not use this file except in compliance with the License.
|
|
19
|
+
* You may obtain a copy of the License at
|
|
20
|
+
*
|
|
21
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
22
|
+
*
|
|
23
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
24
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
25
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
26
|
+
* See the License for the specific language governing permissions and
|
|
27
|
+
* limitations under the License.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
class Snapshotter {
|
|
31
|
+
constructor(context, delegate) {
|
|
32
|
+
this._context = void 0;
|
|
33
|
+
this._delegate = void 0;
|
|
34
|
+
this._eventListeners = [];
|
|
35
|
+
this._snapshotStreamer = void 0;
|
|
36
|
+
this._initialized = false;
|
|
37
|
+
this._started = false;
|
|
38
|
+
this._context = context;
|
|
39
|
+
this._delegate = delegate;
|
|
40
|
+
const guid = (0, _utils.createGuid)();
|
|
41
|
+
this._snapshotStreamer = '__playwright_snapshot_streamer_' + guid;
|
|
42
|
+
}
|
|
43
|
+
started() {
|
|
44
|
+
return this._started;
|
|
45
|
+
}
|
|
46
|
+
async start() {
|
|
47
|
+
this._started = true;
|
|
48
|
+
if (!this._initialized) {
|
|
49
|
+
this._initialized = true;
|
|
50
|
+
await this._initialize();
|
|
51
|
+
}
|
|
52
|
+
await this.reset();
|
|
53
|
+
}
|
|
54
|
+
async reset() {
|
|
55
|
+
if (this._started) await this._runInAllFrames(`window["${this._snapshotStreamer}"].reset()`);
|
|
56
|
+
}
|
|
57
|
+
async stop() {
|
|
58
|
+
this._started = false;
|
|
59
|
+
}
|
|
60
|
+
resetForReuse() {
|
|
61
|
+
// Next time we start recording, we will call addInitScript again.
|
|
62
|
+
this._initialized = false;
|
|
63
|
+
}
|
|
64
|
+
async _initialize() {
|
|
65
|
+
for (const page of this._context.pages()) this._onPage(page);
|
|
66
|
+
this._eventListeners = [_eventsHelper.eventsHelper.addEventListener(this._context, _browserContext.BrowserContext.Events.Page, this._onPage.bind(this))];
|
|
67
|
+
const initScript = `(${_snapshotterInjected.frameSnapshotStreamer})("${this._snapshotStreamer}", ${!!this._context._options.javaScriptEnabled})`;
|
|
68
|
+
await this._context.addInitScript(initScript);
|
|
69
|
+
await this._runInAllFrames(initScript);
|
|
70
|
+
}
|
|
71
|
+
async _runInAllFrames(expression) {
|
|
72
|
+
const frames = [];
|
|
73
|
+
for (const page of this._context.pages()) frames.push(...page.frames());
|
|
74
|
+
await Promise.all(frames.map(frame => {
|
|
75
|
+
return frame.nonStallingRawEvaluateInExistingMainContext(expression).catch(e => _debugLogger.debugLogger.log('error', e));
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
dispose() {
|
|
79
|
+
_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
|
|
80
|
+
}
|
|
81
|
+
async captureSnapshot(page, callId, snapshotName, element) {
|
|
82
|
+
// Prepare expression synchronously.
|
|
83
|
+
const expression = `window["${this._snapshotStreamer}"].captureSnapshot(${JSON.stringify(snapshotName)})`;
|
|
84
|
+
|
|
85
|
+
// In a best-effort manner, without waiting for it, mark target element.
|
|
86
|
+
element === null || element === void 0 || element.callFunctionNoReply((element, callId) => {
|
|
87
|
+
const customEvent = new CustomEvent('__playwright_target__', {
|
|
88
|
+
bubbles: true,
|
|
89
|
+
cancelable: true,
|
|
90
|
+
detail: callId,
|
|
91
|
+
composed: true
|
|
92
|
+
});
|
|
93
|
+
element.dispatchEvent(customEvent);
|
|
94
|
+
}, callId);
|
|
95
|
+
|
|
96
|
+
// In each frame, in a non-stalling manner, capture the snapshots.
|
|
97
|
+
const snapshots = page.frames().map(async frame => {
|
|
98
|
+
const data = await frame.nonStallingRawEvaluateInExistingMainContext(expression).catch(e => _debugLogger.debugLogger.log('error', e));
|
|
99
|
+
// Something went wrong -> bail out, our snapshots are best-efforty.
|
|
100
|
+
if (!data || !this._started) return;
|
|
101
|
+
const snapshot = {
|
|
102
|
+
callId,
|
|
103
|
+
snapshotName,
|
|
104
|
+
pageId: page.guid,
|
|
105
|
+
frameId: frame.guid,
|
|
106
|
+
frameUrl: data.url,
|
|
107
|
+
doctype: data.doctype,
|
|
108
|
+
html: data.html,
|
|
109
|
+
viewport: data.viewport,
|
|
110
|
+
timestamp: (0, _utils.monotonicTime)(),
|
|
111
|
+
collectionTime: data.collectionTime,
|
|
112
|
+
resourceOverrides: [],
|
|
113
|
+
isMainFrame: page.mainFrame() === frame
|
|
114
|
+
};
|
|
115
|
+
for (const {
|
|
116
|
+
url,
|
|
117
|
+
content,
|
|
118
|
+
contentType
|
|
119
|
+
} of data.resourceOverrides) {
|
|
120
|
+
if (typeof content === 'string') {
|
|
121
|
+
const buffer = Buffer.from(content);
|
|
122
|
+
const sha1 = (0, _utils.calculateSha1)(buffer) + '.' + (_utilsBundle.mime.getExtension(contentType) || 'dat');
|
|
123
|
+
this._delegate.onSnapshotterBlob({
|
|
124
|
+
sha1,
|
|
125
|
+
buffer
|
|
126
|
+
});
|
|
127
|
+
snapshot.resourceOverrides.push({
|
|
128
|
+
url,
|
|
129
|
+
sha1
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
snapshot.resourceOverrides.push({
|
|
133
|
+
url,
|
|
134
|
+
ref: content
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this._delegate.onFrameSnapshot(snapshot);
|
|
139
|
+
});
|
|
140
|
+
await Promise.all(snapshots);
|
|
141
|
+
}
|
|
142
|
+
_onPage(page) {
|
|
143
|
+
// Annotate frame hierarchy so that snapshots could include frame ids.
|
|
144
|
+
for (const frame of page.frames()) this._annotateFrameHierarchy(frame);
|
|
145
|
+
this._eventListeners.push(_eventsHelper.eventsHelper.addEventListener(page, _page.Page.Events.FrameAttached, frame => this._annotateFrameHierarchy(frame)));
|
|
146
|
+
}
|
|
147
|
+
async _annotateFrameHierarchy(frame) {
|
|
148
|
+
try {
|
|
149
|
+
const frameElement = await frame.frameElement();
|
|
150
|
+
const parent = frame.parentFrame();
|
|
151
|
+
if (!parent) return;
|
|
152
|
+
const context = await parent._mainContext();
|
|
153
|
+
await (context === null || context === void 0 ? void 0 : context.evaluate(({
|
|
154
|
+
snapshotStreamer,
|
|
155
|
+
frameElement,
|
|
156
|
+
frameId
|
|
157
|
+
}) => {
|
|
158
|
+
window[snapshotStreamer].markIframe(frameElement, frameId);
|
|
159
|
+
}, {
|
|
160
|
+
snapshotStreamer: this._snapshotStreamer,
|
|
161
|
+
frameElement,
|
|
162
|
+
frameId: frame.guid
|
|
163
|
+
}));
|
|
164
|
+
frameElement.dispose();
|
|
165
|
+
} catch (e) {}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
exports.Snapshotter = Snapshotter;
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.frameSnapshotStreamer = frameSnapshotStreamer;
|
|
7
|
+
/**
|
|
8
|
+
* Copyright (c) Microsoft Corporation.
|
|
9
|
+
*
|
|
10
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
11
|
+
* you may not use this file except in compliance with the License.
|
|
12
|
+
* You may obtain a copy of the License at
|
|
13
|
+
*
|
|
14
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
15
|
+
*
|
|
16
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
17
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
18
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
19
|
+
* See the License for the specific language governing permissions and
|
|
20
|
+
* limitations under the License.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
function frameSnapshotStreamer(snapshotStreamer, removeNoScript) {
|
|
24
|
+
// Communication with Playwright.
|
|
25
|
+
if (window[snapshotStreamer]) return;
|
|
26
|
+
|
|
27
|
+
// Attributes present in the snapshot.
|
|
28
|
+
const kShadowAttribute = '__playwright_shadow_root_';
|
|
29
|
+
const kValueAttribute = '__playwright_value_';
|
|
30
|
+
const kCheckedAttribute = '__playwright_checked_';
|
|
31
|
+
const kSelectedAttribute = '__playwright_selected_';
|
|
32
|
+
const kScrollTopAttribute = '__playwright_scroll_top_';
|
|
33
|
+
const kScrollLeftAttribute = '__playwright_scroll_left_';
|
|
34
|
+
const kStyleSheetAttribute = '__playwright_style_sheet_';
|
|
35
|
+
const kTargetAttribute = '__playwright_target__';
|
|
36
|
+
const kCustomElementsAttribute = '__playwright_custom_elements__';
|
|
37
|
+
const kCurrentSrcAttribute = '__playwright_current_src__';
|
|
38
|
+
|
|
39
|
+
// Symbols for our own info on Nodes/StyleSheets.
|
|
40
|
+
const kSnapshotFrameId = Symbol('__playwright_snapshot_frameid_');
|
|
41
|
+
const kCachedData = Symbol('__playwright_snapshot_cache_');
|
|
42
|
+
const kEndOfList = Symbol('__playwright_end_of_list_');
|
|
43
|
+
function resetCachedData(obj) {
|
|
44
|
+
delete obj[kCachedData];
|
|
45
|
+
}
|
|
46
|
+
function ensureCachedData(obj) {
|
|
47
|
+
if (!obj[kCachedData]) obj[kCachedData] = {};
|
|
48
|
+
return obj[kCachedData];
|
|
49
|
+
}
|
|
50
|
+
function removeHash(url) {
|
|
51
|
+
try {
|
|
52
|
+
const u = new URL(url);
|
|
53
|
+
u.hash = '';
|
|
54
|
+
return u.toString();
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return url;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
class Streamer {
|
|
60
|
+
constructor() {
|
|
61
|
+
this._lastSnapshotNumber = 0;
|
|
62
|
+
this._staleStyleSheets = new Set();
|
|
63
|
+
this._readingStyleSheet = false;
|
|
64
|
+
// To avoid invalidating due to our own reads.
|
|
65
|
+
this._fakeBase = void 0;
|
|
66
|
+
this._observer = void 0;
|
|
67
|
+
const invalidateCSSGroupingRule = rule => {
|
|
68
|
+
if (rule.parentStyleSheet) this._invalidateStyleSheet(rule.parentStyleSheet);
|
|
69
|
+
};
|
|
70
|
+
this._interceptNativeMethod(window.CSSStyleSheet.prototype, 'insertRule', sheet => this._invalidateStyleSheet(sheet));
|
|
71
|
+
this._interceptNativeMethod(window.CSSStyleSheet.prototype, 'deleteRule', sheet => this._invalidateStyleSheet(sheet));
|
|
72
|
+
this._interceptNativeMethod(window.CSSStyleSheet.prototype, 'addRule', sheet => this._invalidateStyleSheet(sheet));
|
|
73
|
+
this._interceptNativeMethod(window.CSSStyleSheet.prototype, 'removeRule', sheet => this._invalidateStyleSheet(sheet));
|
|
74
|
+
this._interceptNativeGetter(window.CSSStyleSheet.prototype, 'rules', sheet => this._invalidateStyleSheet(sheet));
|
|
75
|
+
this._interceptNativeGetter(window.CSSStyleSheet.prototype, 'cssRules', sheet => this._invalidateStyleSheet(sheet));
|
|
76
|
+
this._interceptNativeMethod(window.CSSStyleSheet.prototype, 'replaceSync', sheet => this._invalidateStyleSheet(sheet));
|
|
77
|
+
this._interceptNativeMethod(window.CSSGroupingRule.prototype, 'insertRule', invalidateCSSGroupingRule);
|
|
78
|
+
this._interceptNativeMethod(window.CSSGroupingRule.prototype, 'deleteRule', invalidateCSSGroupingRule);
|
|
79
|
+
this._interceptNativeGetter(window.CSSGroupingRule.prototype, 'cssRules', invalidateCSSGroupingRule);
|
|
80
|
+
this._interceptNativeAsyncMethod(window.CSSStyleSheet.prototype, 'replace', sheet => this._invalidateStyleSheet(sheet));
|
|
81
|
+
this._fakeBase = document.createElement('base');
|
|
82
|
+
this._observer = new MutationObserver(list => this._handleMutations(list));
|
|
83
|
+
const observerConfig = {
|
|
84
|
+
attributes: true,
|
|
85
|
+
subtree: true
|
|
86
|
+
};
|
|
87
|
+
this._observer.observe(document, observerConfig);
|
|
88
|
+
this._refreshListenersWhenNeeded();
|
|
89
|
+
}
|
|
90
|
+
_refreshListenersWhenNeeded() {
|
|
91
|
+
this._refreshListeners();
|
|
92
|
+
const customEventName = '__playwright_snapshotter_global_listeners_check__';
|
|
93
|
+
let seenEvent = false;
|
|
94
|
+
const handleCustomEvent = () => seenEvent = true;
|
|
95
|
+
window.addEventListener(customEventName, handleCustomEvent);
|
|
96
|
+
const observer = new MutationObserver(entries => {
|
|
97
|
+
// Check for new documentElement in case we need to reinstall document listeners.
|
|
98
|
+
const newDocumentElement = entries.some(entry => Array.from(entry.addedNodes).includes(document.documentElement));
|
|
99
|
+
if (newDocumentElement) {
|
|
100
|
+
// New documentElement - let's check whether listeners are still here.
|
|
101
|
+
seenEvent = false;
|
|
102
|
+
window.dispatchEvent(new CustomEvent(customEventName));
|
|
103
|
+
if (!seenEvent) {
|
|
104
|
+
// Listener did not fire. Reattach the listener and notify.
|
|
105
|
+
window.addEventListener(customEventName, handleCustomEvent);
|
|
106
|
+
this._refreshListeners();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
observer.observe(document, {
|
|
111
|
+
childList: true
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
_refreshListeners() {
|
|
115
|
+
document.addEventListener('__playwright_target__', event => {
|
|
116
|
+
if (!event.detail) return;
|
|
117
|
+
const callId = event.detail;
|
|
118
|
+
event.composedPath()[0].__playwright_target__ = callId;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
_interceptNativeMethod(obj, method, cb) {
|
|
122
|
+
const native = obj[method];
|
|
123
|
+
if (!native) return;
|
|
124
|
+
obj[method] = function (...args) {
|
|
125
|
+
const result = native.call(this, ...args);
|
|
126
|
+
cb(this, result);
|
|
127
|
+
return result;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
_interceptNativeAsyncMethod(obj, method, cb) {
|
|
131
|
+
const native = obj[method];
|
|
132
|
+
if (!native) return;
|
|
133
|
+
obj[method] = async function (...args) {
|
|
134
|
+
const result = await native.call(this, ...args);
|
|
135
|
+
cb(this, result);
|
|
136
|
+
return result;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
_interceptNativeGetter(obj, prop, cb) {
|
|
140
|
+
const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
|
|
141
|
+
Object.defineProperty(obj, prop, {
|
|
142
|
+
...descriptor,
|
|
143
|
+
get: function () {
|
|
144
|
+
const result = descriptor.get.call(this);
|
|
145
|
+
cb(this, result);
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
_handleMutations(list) {
|
|
151
|
+
for (const mutation of list) ensureCachedData(mutation.target).attributesCached = undefined;
|
|
152
|
+
}
|
|
153
|
+
_invalidateStyleSheet(sheet) {
|
|
154
|
+
if (this._readingStyleSheet) return;
|
|
155
|
+
this._staleStyleSheets.add(sheet);
|
|
156
|
+
}
|
|
157
|
+
_updateStyleElementStyleSheetTextIfNeeded(sheet, forceText) {
|
|
158
|
+
const data = ensureCachedData(sheet);
|
|
159
|
+
if (this._staleStyleSheets.has(sheet) || forceText && data.cssText === undefined) {
|
|
160
|
+
this._staleStyleSheets.delete(sheet);
|
|
161
|
+
try {
|
|
162
|
+
data.cssText = this._getSheetText(sheet);
|
|
163
|
+
} catch (e) {
|
|
164
|
+
// Sometimes we cannot access cross-origin stylesheets.
|
|
165
|
+
data.cssText = '';
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return data.cssText;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Returns either content, ref, or no override.
|
|
172
|
+
_updateLinkStyleSheetTextIfNeeded(sheet, snapshotNumber) {
|
|
173
|
+
const data = ensureCachedData(sheet);
|
|
174
|
+
if (this._staleStyleSheets.has(sheet)) {
|
|
175
|
+
this._staleStyleSheets.delete(sheet);
|
|
176
|
+
try {
|
|
177
|
+
data.cssText = this._getSheetText(sheet);
|
|
178
|
+
data.cssRef = snapshotNumber;
|
|
179
|
+
return data.cssText;
|
|
180
|
+
} catch (e) {
|
|
181
|
+
// Sometimes we cannot access cross-origin stylesheets.
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return data.cssRef === undefined ? undefined : snapshotNumber - data.cssRef;
|
|
185
|
+
}
|
|
186
|
+
markIframe(iframeElement, frameId) {
|
|
187
|
+
iframeElement[kSnapshotFrameId] = frameId;
|
|
188
|
+
}
|
|
189
|
+
reset() {
|
|
190
|
+
this._staleStyleSheets.clear();
|
|
191
|
+
const visitNode = node => {
|
|
192
|
+
resetCachedData(node);
|
|
193
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
194
|
+
const element = node;
|
|
195
|
+
if (element.shadowRoot) visitNode(element.shadowRoot);
|
|
196
|
+
}
|
|
197
|
+
for (let child = node.firstChild; child; child = child.nextSibling) visitNode(child);
|
|
198
|
+
};
|
|
199
|
+
visitNode(document.documentElement);
|
|
200
|
+
visitNode(this._fakeBase);
|
|
201
|
+
}
|
|
202
|
+
__sanitizeMetaAttribute(name, value, httpEquiv) {
|
|
203
|
+
if (name === 'charset') return 'utf-8';
|
|
204
|
+
if (httpEquiv.toLowerCase() !== 'content-type' || name !== 'content') return value;
|
|
205
|
+
const [type, ...params] = value.split(';');
|
|
206
|
+
if (type !== 'text/html' || params.length <= 0) return value;
|
|
207
|
+
const charsetParamIdx = params.findIndex(param => param.trim().startsWith('charset='));
|
|
208
|
+
if (charsetParamIdx > -1) params[charsetParamIdx] = 'charset=utf-8';
|
|
209
|
+
return `${type}; ${params.join('; ')}`;
|
|
210
|
+
}
|
|
211
|
+
_sanitizeUrl(url) {
|
|
212
|
+
if (url.startsWith('javascript:') || url.startsWith('vbscript:')) return '';
|
|
213
|
+
return url;
|
|
214
|
+
}
|
|
215
|
+
_sanitizeSrcSet(srcset) {
|
|
216
|
+
return srcset.split(',').map(src => {
|
|
217
|
+
src = src.trim();
|
|
218
|
+
const spaceIndex = src.lastIndexOf(' ');
|
|
219
|
+
if (spaceIndex === -1) return this._sanitizeUrl(src);
|
|
220
|
+
return this._sanitizeUrl(src.substring(0, spaceIndex).trim()) + src.substring(spaceIndex);
|
|
221
|
+
}).join(', ');
|
|
222
|
+
}
|
|
223
|
+
_resolveUrl(base, url) {
|
|
224
|
+
if (url === '') return '';
|
|
225
|
+
try {
|
|
226
|
+
return new URL(url, base).href;
|
|
227
|
+
} catch (e) {
|
|
228
|
+
return url;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
_getSheetBase(sheet) {
|
|
232
|
+
let rootSheet = sheet;
|
|
233
|
+
while (rootSheet.parentStyleSheet) rootSheet = rootSheet.parentStyleSheet;
|
|
234
|
+
if (rootSheet.ownerNode) return rootSheet.ownerNode.baseURI;
|
|
235
|
+
return document.baseURI;
|
|
236
|
+
}
|
|
237
|
+
_getSheetText(sheet) {
|
|
238
|
+
this._readingStyleSheet = true;
|
|
239
|
+
try {
|
|
240
|
+
const rules = [];
|
|
241
|
+
for (const rule of sheet.cssRules) rules.push(rule.cssText);
|
|
242
|
+
return rules.join('\n');
|
|
243
|
+
} finally {
|
|
244
|
+
this._readingStyleSheet = false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
captureSnapshot() {
|
|
248
|
+
const timestamp = performance.now();
|
|
249
|
+
const snapshotNumber = ++this._lastSnapshotNumber;
|
|
250
|
+
let nodeCounter = 0;
|
|
251
|
+
let shadowDomNesting = 0;
|
|
252
|
+
let headNesting = 0;
|
|
253
|
+
|
|
254
|
+
// Ensure we are up to date.
|
|
255
|
+
this._handleMutations(this._observer.takeRecords());
|
|
256
|
+
const definedCustomElements = new Set();
|
|
257
|
+
const visitNode = node => {
|
|
258
|
+
const nodeType = node.nodeType;
|
|
259
|
+
const nodeName = nodeType === Node.DOCUMENT_FRAGMENT_NODE ? 'template' : node.nodeName;
|
|
260
|
+
if (nodeType !== Node.ELEMENT_NODE && nodeType !== Node.DOCUMENT_FRAGMENT_NODE && nodeType !== Node.TEXT_NODE) return;
|
|
261
|
+
if (nodeName === 'SCRIPT') return;
|
|
262
|
+
// Don't preload resources.
|
|
263
|
+
if (nodeName === 'LINK' && nodeType === Node.ELEMENT_NODE) {
|
|
264
|
+
var _getAttribute;
|
|
265
|
+
const rel = (_getAttribute = node.getAttribute('rel')) === null || _getAttribute === void 0 ? void 0 : _getAttribute.toLowerCase();
|
|
266
|
+
if (rel === 'preload' || rel === 'prefetch') return;
|
|
267
|
+
}
|
|
268
|
+
if (removeNoScript && nodeName === 'NOSCRIPT') return;
|
|
269
|
+
if (nodeName === 'META' && node.httpEquiv.toLowerCase() === 'content-security-policy') return;
|
|
270
|
+
// Skip iframes which are inside document's head as they are not visible.
|
|
271
|
+
// See https://github.com/microsoft/playwright/issues/12005.
|
|
272
|
+
if ((nodeName === 'IFRAME' || nodeName === 'FRAME') && headNesting) return;
|
|
273
|
+
const data = ensureCachedData(node);
|
|
274
|
+
const values = [];
|
|
275
|
+
let equals = !!data.cached;
|
|
276
|
+
let extraNodes = 0;
|
|
277
|
+
const expectValue = value => {
|
|
278
|
+
equals = equals && data.cached[values.length] === value;
|
|
279
|
+
values.push(value);
|
|
280
|
+
};
|
|
281
|
+
const checkAndReturn = n => {
|
|
282
|
+
data.attributesCached = true;
|
|
283
|
+
if (equals) return {
|
|
284
|
+
equals: true,
|
|
285
|
+
n: [[snapshotNumber - data.ref[0], data.ref[1]]]
|
|
286
|
+
};
|
|
287
|
+
nodeCounter += extraNodes;
|
|
288
|
+
data.ref = [snapshotNumber, nodeCounter++];
|
|
289
|
+
data.cached = values;
|
|
290
|
+
return {
|
|
291
|
+
equals: false,
|
|
292
|
+
n
|
|
293
|
+
};
|
|
294
|
+
};
|
|
295
|
+
if (nodeType === Node.TEXT_NODE) {
|
|
296
|
+
const value = node.nodeValue || '';
|
|
297
|
+
expectValue(value);
|
|
298
|
+
return checkAndReturn(value);
|
|
299
|
+
}
|
|
300
|
+
if (nodeName === 'STYLE') {
|
|
301
|
+
const sheet = node.sheet;
|
|
302
|
+
let cssText;
|
|
303
|
+
if (sheet) cssText = this._updateStyleElementStyleSheetTextIfNeeded(sheet);
|
|
304
|
+
cssText = cssText || node.textContent || '';
|
|
305
|
+
expectValue(cssText);
|
|
306
|
+
// Compensate for the extra 'cssText' text node.
|
|
307
|
+
extraNodes++;
|
|
308
|
+
return checkAndReturn([nodeName, {}, cssText]);
|
|
309
|
+
}
|
|
310
|
+
const attrs = {};
|
|
311
|
+
const result = [nodeName, attrs];
|
|
312
|
+
const visitChild = child => {
|
|
313
|
+
const snapshot = visitNode(child);
|
|
314
|
+
if (snapshot) {
|
|
315
|
+
result.push(snapshot.n);
|
|
316
|
+
expectValue(child);
|
|
317
|
+
equals = equals && snapshot.equals;
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const visitChildStyleSheet = child => {
|
|
321
|
+
const snapshot = visitStyleSheet(child);
|
|
322
|
+
if (snapshot) {
|
|
323
|
+
result.push(snapshot.n);
|
|
324
|
+
expectValue(child);
|
|
325
|
+
equals = equals && snapshot.equals;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
if (nodeType === Node.DOCUMENT_FRAGMENT_NODE) attrs[kShadowAttribute] = 'open';
|
|
329
|
+
if (nodeType === Node.ELEMENT_NODE) {
|
|
330
|
+
var _window$customElement;
|
|
331
|
+
const element = node;
|
|
332
|
+
if (element.localName.includes('-') && (_window$customElement = window.customElements) !== null && _window$customElement !== void 0 && _window$customElement.get(element.localName)) definedCustomElements.add(element.localName);
|
|
333
|
+
if (nodeName === 'INPUT' || nodeName === 'TEXTAREA') {
|
|
334
|
+
const value = element.value;
|
|
335
|
+
expectValue(kValueAttribute);
|
|
336
|
+
expectValue(value);
|
|
337
|
+
attrs[kValueAttribute] = value;
|
|
338
|
+
}
|
|
339
|
+
if (nodeName === 'INPUT' && ['checkbox', 'radio'].includes(element.type)) {
|
|
340
|
+
const value = element.checked ? 'true' : 'false';
|
|
341
|
+
expectValue(kCheckedAttribute);
|
|
342
|
+
expectValue(value);
|
|
343
|
+
attrs[kCheckedAttribute] = value;
|
|
344
|
+
}
|
|
345
|
+
if (nodeName === 'OPTION') {
|
|
346
|
+
const value = element.selected ? 'true' : 'false';
|
|
347
|
+
expectValue(kSelectedAttribute);
|
|
348
|
+
expectValue(value);
|
|
349
|
+
attrs[kSelectedAttribute] = value;
|
|
350
|
+
}
|
|
351
|
+
if (element.scrollTop) {
|
|
352
|
+
expectValue(kScrollTopAttribute);
|
|
353
|
+
expectValue(element.scrollTop);
|
|
354
|
+
attrs[kScrollTopAttribute] = '' + element.scrollTop;
|
|
355
|
+
}
|
|
356
|
+
if (element.scrollLeft) {
|
|
357
|
+
expectValue(kScrollLeftAttribute);
|
|
358
|
+
expectValue(element.scrollLeft);
|
|
359
|
+
attrs[kScrollLeftAttribute] = '' + element.scrollLeft;
|
|
360
|
+
}
|
|
361
|
+
if (element.shadowRoot) {
|
|
362
|
+
++shadowDomNesting;
|
|
363
|
+
visitChild(element.shadowRoot);
|
|
364
|
+
--shadowDomNesting;
|
|
365
|
+
}
|
|
366
|
+
if ('__playwright_target__' in element) {
|
|
367
|
+
expectValue(kTargetAttribute);
|
|
368
|
+
expectValue(element['__playwright_target__']);
|
|
369
|
+
attrs[kTargetAttribute] = element['__playwright_target__'];
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (nodeName === 'HEAD') {
|
|
373
|
+
++headNesting;
|
|
374
|
+
// Insert fake <base> first, to ensure all <link> elements use the proper base uri.
|
|
375
|
+
this._fakeBase.setAttribute('href', document.baseURI);
|
|
376
|
+
visitChild(this._fakeBase);
|
|
377
|
+
}
|
|
378
|
+
for (let child = node.firstChild; child; child = child.nextSibling) visitChild(child);
|
|
379
|
+
if (nodeName === 'HEAD') --headNesting;
|
|
380
|
+
expectValue(kEndOfList);
|
|
381
|
+
let documentOrShadowRoot = null;
|
|
382
|
+
if (node.ownerDocument.documentElement === node) documentOrShadowRoot = node.ownerDocument;else if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) documentOrShadowRoot = node;
|
|
383
|
+
if (documentOrShadowRoot) {
|
|
384
|
+
for (const sheet of documentOrShadowRoot.adoptedStyleSheets || []) visitChildStyleSheet(sheet);
|
|
385
|
+
expectValue(kEndOfList);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Process iframe src attribute before bailing out since it depends on a symbol, not the DOM.
|
|
389
|
+
if (nodeName === 'IFRAME' || nodeName === 'FRAME') {
|
|
390
|
+
const element = node;
|
|
391
|
+
const frameId = element[kSnapshotFrameId];
|
|
392
|
+
const name = 'src';
|
|
393
|
+
const value = frameId ? `/snapshot/${frameId}` : '';
|
|
394
|
+
expectValue(name);
|
|
395
|
+
expectValue(value);
|
|
396
|
+
attrs[name] = value;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Process custom elements before bailing out since they depend on JS, not the DOM.
|
|
400
|
+
if (nodeName === 'BODY' && definedCustomElements.size) {
|
|
401
|
+
const value = [...definedCustomElements].join(',');
|
|
402
|
+
expectValue(kCustomElementsAttribute);
|
|
403
|
+
expectValue(value);
|
|
404
|
+
attrs[kCustomElementsAttribute] = value;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Process currentSrc before bailing out since it depends on JS, not the DOM.
|
|
408
|
+
if (nodeName === 'IMG' || nodeName === 'PICTURE') {
|
|
409
|
+
const value = nodeName === 'PICTURE' ? '' : this._sanitizeUrl(node.currentSrc);
|
|
410
|
+
expectValue(kCurrentSrcAttribute);
|
|
411
|
+
expectValue(value);
|
|
412
|
+
attrs[kCurrentSrcAttribute] = value;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// We can skip attributes comparison because nothing else has changed,
|
|
416
|
+
// and mutation observer didn't tell us about the attributes.
|
|
417
|
+
if (equals && data.attributesCached && !shadowDomNesting) return checkAndReturn(result);
|
|
418
|
+
if (nodeType === Node.ELEMENT_NODE) {
|
|
419
|
+
const element = node;
|
|
420
|
+
for (let i = 0; i < element.attributes.length; i++) {
|
|
421
|
+
const name = element.attributes[i].name;
|
|
422
|
+
if (nodeName === 'LINK' && name === 'integrity') continue;
|
|
423
|
+
if (nodeName === 'IFRAME' && (name === 'src' || name === 'srcdoc' || name === 'sandbox')) continue;
|
|
424
|
+
if (nodeName === 'FRAME' && name === 'src') continue;
|
|
425
|
+
let value = element.attributes[i].value;
|
|
426
|
+
if (nodeName === 'META') value = this.__sanitizeMetaAttribute(name, value, node.httpEquiv);else if (name === 'src' && nodeName === 'IMG') value = this._sanitizeUrl(value);else if (name === 'srcset' && nodeName === 'IMG') value = this._sanitizeSrcSet(value);else if (name === 'srcset' && nodeName === 'SOURCE') value = this._sanitizeSrcSet(value);else if (name === 'href' && nodeName === 'LINK') value = this._sanitizeUrl(value);else if (name.startsWith('on')) value = '';
|
|
427
|
+
expectValue(name);
|
|
428
|
+
expectValue(value);
|
|
429
|
+
attrs[name] = value;
|
|
430
|
+
}
|
|
431
|
+
expectValue(kEndOfList);
|
|
432
|
+
}
|
|
433
|
+
if (result.length === 2 && !Object.keys(attrs).length) result.pop(); // Remove empty attrs when there are no children.
|
|
434
|
+
return checkAndReturn(result);
|
|
435
|
+
};
|
|
436
|
+
const visitStyleSheet = sheet => {
|
|
437
|
+
const data = ensureCachedData(sheet);
|
|
438
|
+
const oldCSSText = data.cssText;
|
|
439
|
+
const cssText = this._updateStyleElementStyleSheetTextIfNeeded(sheet, true /* forceText */);
|
|
440
|
+
if (cssText === oldCSSText) return {
|
|
441
|
+
equals: true,
|
|
442
|
+
n: [[snapshotNumber - data.ref[0], data.ref[1]]]
|
|
443
|
+
};
|
|
444
|
+
data.ref = [snapshotNumber, nodeCounter++];
|
|
445
|
+
return {
|
|
446
|
+
equals: false,
|
|
447
|
+
n: ['template', {
|
|
448
|
+
[kStyleSheetAttribute]: cssText
|
|
449
|
+
}]
|
|
450
|
+
};
|
|
451
|
+
};
|
|
452
|
+
let html;
|
|
453
|
+
if (document.documentElement) {
|
|
454
|
+
const {
|
|
455
|
+
n
|
|
456
|
+
} = visitNode(document.documentElement);
|
|
457
|
+
html = n;
|
|
458
|
+
} else {
|
|
459
|
+
html = ['html'];
|
|
460
|
+
}
|
|
461
|
+
const result = {
|
|
462
|
+
html,
|
|
463
|
+
doctype: document.doctype ? document.doctype.name : undefined,
|
|
464
|
+
resourceOverrides: [],
|
|
465
|
+
viewport: {
|
|
466
|
+
width: window.innerWidth,
|
|
467
|
+
height: window.innerHeight
|
|
468
|
+
},
|
|
469
|
+
url: location.href,
|
|
470
|
+
timestamp,
|
|
471
|
+
collectionTime: 0
|
|
472
|
+
};
|
|
473
|
+
for (const sheet of this._staleStyleSheets) {
|
|
474
|
+
if (sheet.href === null) continue;
|
|
475
|
+
const content = this._updateLinkStyleSheetTextIfNeeded(sheet, snapshotNumber);
|
|
476
|
+
if (content === undefined) {
|
|
477
|
+
// Unable to capture stylesheet contents.
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const base = this._getSheetBase(sheet);
|
|
481
|
+
const url = removeHash(this._resolveUrl(base, sheet.href));
|
|
482
|
+
result.resourceOverrides.push({
|
|
483
|
+
url,
|
|
484
|
+
content,
|
|
485
|
+
contentType: 'text/css'
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
result.collectionTime = performance.now() - result.timestamp;
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
window[snapshotStreamer] = new Streamer();
|
|
493
|
+
}
|