First Commit
This commit is contained in:
136
node_modules/playwright-core/lib/server/trace/recorder/snapshotter.js
generated
vendored
Normal file
136
node_modules/playwright-core/lib/server/trace/recorder/snapshotter.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var snapshotter_exports = {};
|
||||
__export(snapshotter_exports, {
|
||||
Snapshotter: () => Snapshotter
|
||||
});
|
||||
module.exports = __toCommonJS(snapshotter_exports);
|
||||
var import_snapshotterInjected = require("./snapshotterInjected");
|
||||
var import_time = require("../../../utils/isomorphic/time");
|
||||
var import_crypto = require("../../utils/crypto");
|
||||
var import_debugLogger = require("../../utils/debugLogger");
|
||||
var import_eventsHelper = require("../../utils/eventsHelper");
|
||||
var import_utilsBundle = require("../../../utilsBundle");
|
||||
var import_browserContext = require("../../browserContext");
|
||||
var import_page = require("../../page");
|
||||
class Snapshotter {
|
||||
constructor(context, delegate) {
|
||||
this._eventListeners = [];
|
||||
this._started = false;
|
||||
this._context = context;
|
||||
this._delegate = delegate;
|
||||
const guid = (0, import_crypto.createGuid)();
|
||||
this._snapshotStreamer = "__playwright_snapshot_streamer_" + guid;
|
||||
}
|
||||
started() {
|
||||
return this._started;
|
||||
}
|
||||
async start() {
|
||||
this._started = true;
|
||||
if (!this._initScript)
|
||||
await this._initialize();
|
||||
await this.reset();
|
||||
}
|
||||
async reset() {
|
||||
if (this._started)
|
||||
await this._context.safeNonStallingEvaluateInAllFrames(`window["${this._snapshotStreamer}"].reset()`, "main");
|
||||
}
|
||||
stop() {
|
||||
this._started = false;
|
||||
}
|
||||
async resetForReuse() {
|
||||
if (this._initScript) {
|
||||
import_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
|
||||
await this._context.removeInitScripts([this._initScript]);
|
||||
this._initScript = void 0;
|
||||
}
|
||||
}
|
||||
async _initialize() {
|
||||
for (const page of this._context.pages())
|
||||
this._onPage(page);
|
||||
this._eventListeners = [
|
||||
import_eventsHelper.eventsHelper.addEventListener(this._context, import_browserContext.BrowserContext.Events.Page, this._onPage.bind(this))
|
||||
];
|
||||
const { javaScriptEnabled } = this._context._options;
|
||||
const initScriptSource = `(${import_snapshotterInjected.frameSnapshotStreamer})("${this._snapshotStreamer}", ${javaScriptEnabled || javaScriptEnabled === void 0})`;
|
||||
this._initScript = await this._context.addInitScript(void 0, initScriptSource);
|
||||
await this._context.safeNonStallingEvaluateInAllFrames(initScriptSource, "main");
|
||||
}
|
||||
dispose() {
|
||||
import_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
|
||||
}
|
||||
async captureSnapshot(page, callId, snapshotName) {
|
||||
const expression = `window["${this._snapshotStreamer}"].captureSnapshot(${JSON.stringify(snapshotName)})`;
|
||||
const snapshots = page.frames().map(async (frame) => {
|
||||
const data = await frame.nonStallingRawEvaluateInExistingMainContext(expression).catch((e) => import_debugLogger.debugLogger.log("error", e));
|
||||
if (!data || !this._started)
|
||||
return;
|
||||
const snapshot = {
|
||||
callId,
|
||||
snapshotName,
|
||||
pageId: page.guid,
|
||||
frameId: frame.guid,
|
||||
frameUrl: data.url,
|
||||
doctype: data.doctype,
|
||||
html: data.html,
|
||||
viewport: data.viewport,
|
||||
timestamp: (0, import_time.monotonicTime)(),
|
||||
wallTime: data.wallTime,
|
||||
collectionTime: data.collectionTime,
|
||||
resourceOverrides: [],
|
||||
isMainFrame: page.mainFrame() === frame
|
||||
};
|
||||
for (const { url, content, contentType } of data.resourceOverrides) {
|
||||
if (typeof content === "string") {
|
||||
const buffer = Buffer.from(content);
|
||||
const sha1 = (0, import_crypto.calculateSha1)(buffer) + "." + (import_utilsBundle.mime.getExtension(contentType) || "dat");
|
||||
this._delegate.onSnapshotterBlob({ sha1, buffer });
|
||||
snapshot.resourceOverrides.push({ url, sha1 });
|
||||
} else {
|
||||
snapshot.resourceOverrides.push({ url, ref: content });
|
||||
}
|
||||
}
|
||||
this._delegate.onFrameSnapshot(snapshot);
|
||||
});
|
||||
await Promise.all(snapshots);
|
||||
}
|
||||
_onPage(page) {
|
||||
for (const frame of page.frames())
|
||||
this._annotateFrameHierarchy(frame);
|
||||
this._eventListeners.push(import_eventsHelper.eventsHelper.addEventListener(page, import_page.Page.Events.FrameAttached, (frame) => this._annotateFrameHierarchy(frame)));
|
||||
}
|
||||
async _annotateFrameHierarchy(frame) {
|
||||
try {
|
||||
const frameElement = await frame.frameElement();
|
||||
const parent = frame.parentFrame();
|
||||
if (!parent)
|
||||
return;
|
||||
const context = await parent._mainContext();
|
||||
await context?.evaluate(({ snapshotStreamer, frameElement: frameElement2, frameId }) => {
|
||||
window[snapshotStreamer].markIframe(frameElement2, frameId);
|
||||
}, { snapshotStreamer: this._snapshotStreamer, frameElement, frameId: frame.guid });
|
||||
frameElement.dispose();
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
Snapshotter
|
||||
});
|
539
node_modules/playwright-core/lib/server/trace/recorder/snapshotterInjected.js
generated
vendored
Normal file
539
node_modules/playwright-core/lib/server/trace/recorder/snapshotterInjected.js
generated
vendored
Normal file
@@ -0,0 +1,539 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var snapshotterInjected_exports = {};
|
||||
__export(snapshotterInjected_exports, {
|
||||
frameSnapshotStreamer: () => frameSnapshotStreamer
|
||||
});
|
||||
module.exports = __toCommonJS(snapshotterInjected_exports);
|
||||
function frameSnapshotStreamer(snapshotStreamer, removeNoScript) {
|
||||
if (window[snapshotStreamer])
|
||||
return;
|
||||
const kShadowAttribute = "__playwright_shadow_root_";
|
||||
const kValueAttribute = "__playwright_value_";
|
||||
const kCheckedAttribute = "__playwright_checked_";
|
||||
const kSelectedAttribute = "__playwright_selected_";
|
||||
const kScrollTopAttribute = "__playwright_scroll_top_";
|
||||
const kScrollLeftAttribute = "__playwright_scroll_left_";
|
||||
const kStyleSheetAttribute = "__playwright_style_sheet_";
|
||||
const kTargetAttribute = "__playwright_target__";
|
||||
const kCustomElementsAttribute = "__playwright_custom_elements__";
|
||||
const kCurrentSrcAttribute = "__playwright_current_src__";
|
||||
const kBoundingRectAttribute = "__playwright_bounding_rect__";
|
||||
const kPopoverOpenAttribute = "__playwright_popover_open_";
|
||||
const kDialogOpenAttribute = "__playwright_dialog_open_";
|
||||
const kSnapshotFrameId = Symbol("__playwright_snapshot_frameid_");
|
||||
const kCachedData = Symbol("__playwright_snapshot_cache_");
|
||||
const kEndOfList = Symbol("__playwright_end_of_list_");
|
||||
function resetCachedData(obj) {
|
||||
delete obj[kCachedData];
|
||||
}
|
||||
function ensureCachedData(obj) {
|
||||
if (!obj[kCachedData])
|
||||
obj[kCachedData] = {};
|
||||
return obj[kCachedData];
|
||||
}
|
||||
function removeHash(url) {
|
||||
try {
|
||||
const u = new URL(url);
|
||||
u.hash = "";
|
||||
return u.toString();
|
||||
} catch (e) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
class Streamer {
|
||||
constructor() {
|
||||
this._lastSnapshotNumber = 0;
|
||||
this._staleStyleSheets = /* @__PURE__ */ new Set();
|
||||
this._readingStyleSheet = false;
|
||||
const invalidateCSSGroupingRule = (rule) => {
|
||||
if (rule.parentStyleSheet)
|
||||
this._invalidateStyleSheet(rule.parentStyleSheet);
|
||||
};
|
||||
this._interceptNativeMethod(window.CSSStyleSheet.prototype, "insertRule", (sheet) => this._invalidateStyleSheet(sheet));
|
||||
this._interceptNativeMethod(window.CSSStyleSheet.prototype, "deleteRule", (sheet) => this._invalidateStyleSheet(sheet));
|
||||
this._interceptNativeMethod(window.CSSStyleSheet.prototype, "addRule", (sheet) => this._invalidateStyleSheet(sheet));
|
||||
this._interceptNativeMethod(window.CSSStyleSheet.prototype, "removeRule", (sheet) => this._invalidateStyleSheet(sheet));
|
||||
this._interceptNativeGetter(window.CSSStyleSheet.prototype, "rules", (sheet) => this._invalidateStyleSheet(sheet));
|
||||
this._interceptNativeGetter(window.CSSStyleSheet.prototype, "cssRules", (sheet) => this._invalidateStyleSheet(sheet));
|
||||
this._interceptNativeMethod(window.CSSStyleSheet.prototype, "replaceSync", (sheet) => this._invalidateStyleSheet(sheet));
|
||||
this._interceptNativeMethod(window.CSSGroupingRule.prototype, "insertRule", invalidateCSSGroupingRule);
|
||||
this._interceptNativeMethod(window.CSSGroupingRule.prototype, "deleteRule", invalidateCSSGroupingRule);
|
||||
this._interceptNativeGetter(window.CSSGroupingRule.prototype, "cssRules", invalidateCSSGroupingRule);
|
||||
this._interceptNativeAsyncMethod(window.CSSStyleSheet.prototype, "replace", (sheet) => this._invalidateStyleSheet(sheet));
|
||||
this._fakeBase = document.createElement("base");
|
||||
this._observer = new MutationObserver((list) => this._handleMutations(list));
|
||||
const observerConfig = { attributes: true, subtree: true };
|
||||
this._observer.observe(document, observerConfig);
|
||||
this._refreshListenersWhenNeeded();
|
||||
}
|
||||
_refreshListenersWhenNeeded() {
|
||||
this._refreshListeners();
|
||||
const customEventName = "__playwright_snapshotter_global_listeners_check__";
|
||||
let seenEvent = false;
|
||||
const handleCustomEvent = () => seenEvent = true;
|
||||
window.addEventListener(customEventName, handleCustomEvent);
|
||||
const observer = new MutationObserver((entries) => {
|
||||
const newDocumentElement = entries.some((entry) => Array.from(entry.addedNodes).includes(document.documentElement));
|
||||
if (newDocumentElement) {
|
||||
seenEvent = false;
|
||||
window.dispatchEvent(new CustomEvent(customEventName));
|
||||
if (!seenEvent) {
|
||||
window.addEventListener(customEventName, handleCustomEvent);
|
||||
this._refreshListeners();
|
||||
}
|
||||
}
|
||||
});
|
||||
observer.observe(document, { childList: true });
|
||||
}
|
||||
_refreshListeners() {
|
||||
document.addEventListener("__playwright_mark_target__", (event) => {
|
||||
if (!event.detail)
|
||||
return;
|
||||
const callId = event.detail;
|
||||
event.composedPath()[0].__playwright_target__ = callId;
|
||||
});
|
||||
document.addEventListener("__playwright_unmark_target__", (event) => {
|
||||
if (!event.detail)
|
||||
return;
|
||||
const callId = event.detail;
|
||||
if (event.composedPath()[0].__playwright_target__ === callId)
|
||||
delete event.composedPath()[0].__playwright_target__;
|
||||
});
|
||||
}
|
||||
_interceptNativeMethod(obj, method, cb) {
|
||||
const native = obj[method];
|
||||
if (!native)
|
||||
return;
|
||||
obj[method] = function(...args) {
|
||||
const result = native.call(this, ...args);
|
||||
cb(this, result);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
_interceptNativeAsyncMethod(obj, method, cb) {
|
||||
const native = obj[method];
|
||||
if (!native)
|
||||
return;
|
||||
obj[method] = async function(...args) {
|
||||
const result = await native.call(this, ...args);
|
||||
cb(this, result);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
_interceptNativeGetter(obj, prop, cb) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
|
||||
Object.defineProperty(obj, prop, {
|
||||
...descriptor,
|
||||
get: function() {
|
||||
const result = descriptor.get.call(this);
|
||||
cb(this, result);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
_handleMutations(list) {
|
||||
for (const mutation of list)
|
||||
ensureCachedData(mutation.target).attributesCached = void 0;
|
||||
}
|
||||
_invalidateStyleSheet(sheet) {
|
||||
if (this._readingStyleSheet)
|
||||
return;
|
||||
this._staleStyleSheets.add(sheet);
|
||||
}
|
||||
_updateStyleElementStyleSheetTextIfNeeded(sheet, forceText) {
|
||||
const data = ensureCachedData(sheet);
|
||||
if (this._staleStyleSheets.has(sheet) || forceText && data.cssText === void 0) {
|
||||
this._staleStyleSheets.delete(sheet);
|
||||
try {
|
||||
data.cssText = this._getSheetText(sheet);
|
||||
} catch (e) {
|
||||
data.cssText = "";
|
||||
}
|
||||
}
|
||||
return data.cssText;
|
||||
}
|
||||
// Returns either content, ref, or no override.
|
||||
_updateLinkStyleSheetTextIfNeeded(sheet, snapshotNumber) {
|
||||
const data = ensureCachedData(sheet);
|
||||
if (this._staleStyleSheets.has(sheet)) {
|
||||
this._staleStyleSheets.delete(sheet);
|
||||
try {
|
||||
data.cssText = this._getSheetText(sheet);
|
||||
data.cssRef = snapshotNumber;
|
||||
return data.cssText;
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
return data.cssRef === void 0 ? void 0 : snapshotNumber - data.cssRef;
|
||||
}
|
||||
markIframe(iframeElement, frameId) {
|
||||
iframeElement[kSnapshotFrameId] = frameId;
|
||||
}
|
||||
reset() {
|
||||
this._staleStyleSheets.clear();
|
||||
const visitNode = (node) => {
|
||||
resetCachedData(node);
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
const element = node;
|
||||
if (element.shadowRoot)
|
||||
visitNode(element.shadowRoot);
|
||||
}
|
||||
for (let child = node.firstChild; child; child = child.nextSibling)
|
||||
visitNode(child);
|
||||
};
|
||||
visitNode(document.documentElement);
|
||||
visitNode(this._fakeBase);
|
||||
}
|
||||
__sanitizeMetaAttribute(name, value, httpEquiv) {
|
||||
if (name === "charset")
|
||||
return "utf-8";
|
||||
if (httpEquiv.toLowerCase() !== "content-type" || name !== "content")
|
||||
return value;
|
||||
const [type, ...params] = value.split(";");
|
||||
if (type !== "text/html" || params.length <= 0)
|
||||
return value;
|
||||
const charsetParamIdx = params.findIndex((param) => param.trim().startsWith("charset="));
|
||||
if (charsetParamIdx > -1)
|
||||
params[charsetParamIdx] = "charset=utf-8";
|
||||
return `${type}; ${params.join("; ")}`;
|
||||
}
|
||||
_sanitizeUrl(url) {
|
||||
if (url.startsWith("javascript:") || url.startsWith("vbscript:"))
|
||||
return "";
|
||||
return url;
|
||||
}
|
||||
_sanitizeSrcSet(srcset) {
|
||||
return srcset.split(",").map((src) => {
|
||||
src = src.trim();
|
||||
const spaceIndex = src.lastIndexOf(" ");
|
||||
if (spaceIndex === -1)
|
||||
return this._sanitizeUrl(src);
|
||||
return this._sanitizeUrl(src.substring(0, spaceIndex).trim()) + src.substring(spaceIndex);
|
||||
}).join(", ");
|
||||
}
|
||||
_resolveUrl(base, url) {
|
||||
if (url === "")
|
||||
return "";
|
||||
try {
|
||||
return new URL(url, base).href;
|
||||
} catch (e) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
_getSheetBase(sheet) {
|
||||
let rootSheet = sheet;
|
||||
while (rootSheet.parentStyleSheet)
|
||||
rootSheet = rootSheet.parentStyleSheet;
|
||||
if (rootSheet.ownerNode)
|
||||
return rootSheet.ownerNode.baseURI;
|
||||
return document.baseURI;
|
||||
}
|
||||
_getSheetText(sheet) {
|
||||
this._readingStyleSheet = true;
|
||||
try {
|
||||
const rules = [];
|
||||
for (const rule of sheet.cssRules)
|
||||
rules.push(rule.cssText);
|
||||
return rules.join("\n");
|
||||
} finally {
|
||||
this._readingStyleSheet = false;
|
||||
}
|
||||
}
|
||||
captureSnapshot() {
|
||||
const timestamp = performance.now();
|
||||
const snapshotNumber = ++this._lastSnapshotNumber;
|
||||
let nodeCounter = 0;
|
||||
let shadowDomNesting = 0;
|
||||
let headNesting = 0;
|
||||
this._handleMutations(this._observer.takeRecords());
|
||||
const definedCustomElements = /* @__PURE__ */ new Set();
|
||||
const visitNode = (node) => {
|
||||
const nodeType = node.nodeType;
|
||||
const nodeName = nodeType === Node.DOCUMENT_FRAGMENT_NODE ? "template" : node.nodeName;
|
||||
if (nodeType !== Node.ELEMENT_NODE && nodeType !== Node.DOCUMENT_FRAGMENT_NODE && nodeType !== Node.TEXT_NODE)
|
||||
return;
|
||||
if (nodeName === "SCRIPT")
|
||||
return;
|
||||
if (nodeName === "LINK" && nodeType === Node.ELEMENT_NODE) {
|
||||
const rel = node.getAttribute("rel")?.toLowerCase();
|
||||
if (rel === "preload" || rel === "prefetch")
|
||||
return;
|
||||
}
|
||||
if (removeNoScript && nodeName === "NOSCRIPT")
|
||||
return;
|
||||
if (nodeName === "META" && node.httpEquiv.toLowerCase() === "content-security-policy")
|
||||
return;
|
||||
if ((nodeName === "IFRAME" || nodeName === "FRAME") && headNesting)
|
||||
return;
|
||||
const data = ensureCachedData(node);
|
||||
const values = [];
|
||||
let equals = !!data.cached;
|
||||
let extraNodes = 0;
|
||||
const expectValue = (value) => {
|
||||
equals = equals && data.cached[values.length] === value;
|
||||
values.push(value);
|
||||
};
|
||||
const checkAndReturn = (n) => {
|
||||
data.attributesCached = true;
|
||||
if (equals)
|
||||
return { equals: true, n: [[snapshotNumber - data.ref[0], data.ref[1]]] };
|
||||
nodeCounter += extraNodes;
|
||||
data.ref = [snapshotNumber, nodeCounter++];
|
||||
data.cached = values;
|
||||
return { equals: false, n };
|
||||
};
|
||||
if (nodeType === Node.TEXT_NODE) {
|
||||
const value = node.nodeValue || "";
|
||||
expectValue(value);
|
||||
return checkAndReturn(value);
|
||||
}
|
||||
if (nodeName === "STYLE") {
|
||||
const sheet = node.sheet;
|
||||
let cssText;
|
||||
if (sheet)
|
||||
cssText = this._updateStyleElementStyleSheetTextIfNeeded(sheet);
|
||||
cssText = cssText || node.textContent || "";
|
||||
expectValue(cssText);
|
||||
extraNodes++;
|
||||
return checkAndReturn([nodeName, {}, cssText]);
|
||||
}
|
||||
const attrs = {};
|
||||
const result2 = [nodeName, attrs];
|
||||
const visitChild = (child) => {
|
||||
const snapshot = visitNode(child);
|
||||
if (snapshot) {
|
||||
result2.push(snapshot.n);
|
||||
expectValue(child);
|
||||
equals = equals && snapshot.equals;
|
||||
}
|
||||
};
|
||||
const visitChildStyleSheet = (child) => {
|
||||
const snapshot = visitStyleSheet(child);
|
||||
if (snapshot) {
|
||||
result2.push(snapshot.n);
|
||||
expectValue(child);
|
||||
equals = equals && snapshot.equals;
|
||||
}
|
||||
};
|
||||
if (nodeType === Node.DOCUMENT_FRAGMENT_NODE)
|
||||
attrs[kShadowAttribute] = "open";
|
||||
if (nodeType === Node.ELEMENT_NODE) {
|
||||
const element = node;
|
||||
if (element.localName.includes("-") && window.customElements?.get(element.localName))
|
||||
definedCustomElements.add(element.localName);
|
||||
if (nodeName === "INPUT" || nodeName === "TEXTAREA") {
|
||||
const value = element.value;
|
||||
expectValue(kValueAttribute);
|
||||
expectValue(value);
|
||||
attrs[kValueAttribute] = value;
|
||||
}
|
||||
if (nodeName === "INPUT" && ["checkbox", "radio"].includes(element.type)) {
|
||||
const value = element.checked ? "true" : "false";
|
||||
expectValue(kCheckedAttribute);
|
||||
expectValue(value);
|
||||
attrs[kCheckedAttribute] = value;
|
||||
}
|
||||
if (nodeName === "OPTION") {
|
||||
const value = element.selected ? "true" : "false";
|
||||
expectValue(kSelectedAttribute);
|
||||
expectValue(value);
|
||||
attrs[kSelectedAttribute] = value;
|
||||
}
|
||||
if (nodeName === "CANVAS" || nodeName === "IFRAME" || nodeName === "FRAME") {
|
||||
const boundingRect = element.getBoundingClientRect();
|
||||
const value = JSON.stringify({
|
||||
left: boundingRect.left,
|
||||
top: boundingRect.top,
|
||||
right: boundingRect.right,
|
||||
bottom: boundingRect.bottom
|
||||
});
|
||||
expectValue(kBoundingRectAttribute);
|
||||
expectValue(value);
|
||||
attrs[kBoundingRectAttribute] = value;
|
||||
}
|
||||
if (element.popover && element.matches && element.matches(":popover-open")) {
|
||||
const value = "true";
|
||||
expectValue(kPopoverOpenAttribute);
|
||||
expectValue(value);
|
||||
attrs[kPopoverOpenAttribute] = value;
|
||||
}
|
||||
if (nodeName === "DIALOG" && element.open) {
|
||||
const value = element.matches(":modal") ? "modal" : "true";
|
||||
expectValue(kDialogOpenAttribute);
|
||||
expectValue(value);
|
||||
attrs[kDialogOpenAttribute] = value;
|
||||
}
|
||||
if (element.scrollTop) {
|
||||
expectValue(kScrollTopAttribute);
|
||||
expectValue(element.scrollTop);
|
||||
attrs[kScrollTopAttribute] = "" + element.scrollTop;
|
||||
}
|
||||
if (element.scrollLeft) {
|
||||
expectValue(kScrollLeftAttribute);
|
||||
expectValue(element.scrollLeft);
|
||||
attrs[kScrollLeftAttribute] = "" + element.scrollLeft;
|
||||
}
|
||||
if (element.shadowRoot) {
|
||||
++shadowDomNesting;
|
||||
visitChild(element.shadowRoot);
|
||||
--shadowDomNesting;
|
||||
}
|
||||
if ("__playwright_target__" in element) {
|
||||
expectValue(kTargetAttribute);
|
||||
expectValue(element["__playwright_target__"]);
|
||||
attrs[kTargetAttribute] = element["__playwright_target__"];
|
||||
}
|
||||
}
|
||||
if (nodeName === "HEAD") {
|
||||
++headNesting;
|
||||
this._fakeBase.setAttribute("href", document.baseURI);
|
||||
visitChild(this._fakeBase);
|
||||
}
|
||||
for (let child = node.firstChild; child; child = child.nextSibling)
|
||||
visitChild(child);
|
||||
if (nodeName === "HEAD")
|
||||
--headNesting;
|
||||
expectValue(kEndOfList);
|
||||
let documentOrShadowRoot = null;
|
||||
if (node.ownerDocument.documentElement === node)
|
||||
documentOrShadowRoot = node.ownerDocument;
|
||||
else if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE)
|
||||
documentOrShadowRoot = node;
|
||||
if (documentOrShadowRoot) {
|
||||
for (const sheet of documentOrShadowRoot.adoptedStyleSheets || [])
|
||||
visitChildStyleSheet(sheet);
|
||||
expectValue(kEndOfList);
|
||||
}
|
||||
if (nodeName === "IFRAME" || nodeName === "FRAME") {
|
||||
const element = node;
|
||||
const frameId = element[kSnapshotFrameId];
|
||||
const name = "src";
|
||||
const value = frameId ? `/snapshot/${frameId}` : "";
|
||||
expectValue(name);
|
||||
expectValue(value);
|
||||
attrs[name] = value;
|
||||
}
|
||||
if (nodeName === "BODY" && definedCustomElements.size) {
|
||||
const value = [...definedCustomElements].join(",");
|
||||
expectValue(kCustomElementsAttribute);
|
||||
expectValue(value);
|
||||
attrs[kCustomElementsAttribute] = value;
|
||||
}
|
||||
if (nodeName === "IMG" || nodeName === "PICTURE") {
|
||||
const value = nodeName === "PICTURE" ? "" : this._sanitizeUrl(node.currentSrc);
|
||||
expectValue(kCurrentSrcAttribute);
|
||||
expectValue(value);
|
||||
attrs[kCurrentSrcAttribute] = value;
|
||||
}
|
||||
if (equals && data.attributesCached && !shadowDomNesting)
|
||||
return checkAndReturn(result2);
|
||||
if (nodeType === Node.ELEMENT_NODE) {
|
||||
const element = node;
|
||||
for (let i = 0; i < element.attributes.length; i++) {
|
||||
const name = element.attributes[i].name;
|
||||
if (nodeName === "LINK" && name === "integrity")
|
||||
continue;
|
||||
if (nodeName === "IFRAME" && (name === "src" || name === "srcdoc" || name === "sandbox"))
|
||||
continue;
|
||||
if (nodeName === "FRAME" && name === "src")
|
||||
continue;
|
||||
if (nodeName === "DIALOG" && name === "open")
|
||||
continue;
|
||||
let value = element.attributes[i].value;
|
||||
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 = "";
|
||||
expectValue(name);
|
||||
expectValue(value);
|
||||
attrs[name] = value;
|
||||
}
|
||||
expectValue(kEndOfList);
|
||||
}
|
||||
if (result2.length === 2 && !Object.keys(attrs).length)
|
||||
result2.pop();
|
||||
return checkAndReturn(result2);
|
||||
};
|
||||
const visitStyleSheet = (sheet) => {
|
||||
const data = ensureCachedData(sheet);
|
||||
const oldCSSText = data.cssText;
|
||||
const cssText = this._updateStyleElementStyleSheetTextIfNeeded(
|
||||
sheet,
|
||||
true
|
||||
/* forceText */
|
||||
);
|
||||
if (cssText === oldCSSText)
|
||||
return { equals: true, n: [[snapshotNumber - data.ref[0], data.ref[1]]] };
|
||||
data.ref = [snapshotNumber, nodeCounter++];
|
||||
return {
|
||||
equals: false,
|
||||
n: ["template", {
|
||||
[kStyleSheetAttribute]: cssText
|
||||
}]
|
||||
};
|
||||
};
|
||||
let html;
|
||||
if (document.documentElement) {
|
||||
const { n } = visitNode(document.documentElement);
|
||||
html = n;
|
||||
} else {
|
||||
html = ["html"];
|
||||
}
|
||||
const result = {
|
||||
html,
|
||||
doctype: document.doctype ? document.doctype.name : void 0,
|
||||
resourceOverrides: [],
|
||||
viewport: {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
},
|
||||
url: location.href,
|
||||
wallTime: Date.now(),
|
||||
collectionTime: 0
|
||||
};
|
||||
for (const sheet of this._staleStyleSheets) {
|
||||
if (sheet.href === null)
|
||||
continue;
|
||||
const content = this._updateLinkStyleSheetTextIfNeeded(sheet, snapshotNumber);
|
||||
if (content === void 0) {
|
||||
continue;
|
||||
}
|
||||
const base = this._getSheetBase(sheet);
|
||||
const url = removeHash(this._resolveUrl(base, sheet.href));
|
||||
result.resourceOverrides.push({ url, content, contentType: "text/css" });
|
||||
}
|
||||
result.collectionTime = performance.now() - timestamp;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
window[snapshotStreamer] = new Streamer();
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
frameSnapshotStreamer
|
||||
});
|
602
node_modules/playwright-core/lib/server/trace/recorder/tracing.js
generated
vendored
Normal file
602
node_modules/playwright-core/lib/server/trace/recorder/tracing.js
generated
vendored
Normal file
@@ -0,0 +1,602 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var tracing_exports = {};
|
||||
__export(tracing_exports, {
|
||||
Tracing: () => Tracing
|
||||
});
|
||||
module.exports = __toCommonJS(tracing_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_os = __toESM(require("os"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_snapshotter = require("./snapshotter");
|
||||
var import_protocolMetainfo = require("../../../utils/isomorphic/protocolMetainfo");
|
||||
var import_assert = require("../../../utils/isomorphic/assert");
|
||||
var import_time = require("../../../utils/isomorphic/time");
|
||||
var import_eventsHelper = require("../../utils/eventsHelper");
|
||||
var import_crypto = require("../../utils/crypto");
|
||||
var import_artifact = require("../../artifact");
|
||||
var import_browserContext = require("../../browserContext");
|
||||
var import_dispatcher = require("../../dispatchers/dispatcher");
|
||||
var import_errors = require("../../errors");
|
||||
var import_fileUtils = require("../../utils/fileUtils");
|
||||
var import_harTracer = require("../../har/harTracer");
|
||||
var import_instrumentation = require("../../instrumentation");
|
||||
var import_page = require("../../page");
|
||||
var import_progress = require("../../progress");
|
||||
const version = 8;
|
||||
const kScreencastOptions = { width: 800, height: 600, quality: 90 };
|
||||
class Tracing extends import_instrumentation.SdkObject {
|
||||
constructor(context, tracesDir) {
|
||||
super(context, "tracing");
|
||||
this._fs = new import_fileUtils.SerializedFS();
|
||||
this._screencastListeners = [];
|
||||
this._eventListeners = [];
|
||||
this._isStopping = false;
|
||||
this._allResources = /* @__PURE__ */ new Set();
|
||||
this._pendingHarEntries = /* @__PURE__ */ new Set();
|
||||
this._context = context;
|
||||
this._precreatedTracesDir = tracesDir;
|
||||
this._harTracer = new import_harTracer.HarTracer(context, null, this, {
|
||||
content: "attach",
|
||||
includeTraceInfo: true,
|
||||
recordRequestOverrides: false,
|
||||
waitForContentOnStop: false
|
||||
});
|
||||
const testIdAttributeName = "selectors" in context ? context.selectors().testIdAttributeName() : void 0;
|
||||
this._contextCreatedEvent = {
|
||||
version,
|
||||
type: "context-options",
|
||||
origin: "library",
|
||||
browserName: "",
|
||||
options: {},
|
||||
platform: process.platform,
|
||||
wallTime: 0,
|
||||
monotonicTime: 0,
|
||||
sdkLanguage: this._sdkLanguage(),
|
||||
testIdAttributeName,
|
||||
contextId: context.guid
|
||||
};
|
||||
if (context instanceof import_browserContext.BrowserContext) {
|
||||
this._snapshotter = new import_snapshotter.Snapshotter(context, this);
|
||||
(0, import_assert.assert)(tracesDir, "tracesDir must be specified for BrowserContext");
|
||||
this._contextCreatedEvent.browserName = context._browser.options.name;
|
||||
this._contextCreatedEvent.channel = context._browser.options.channel;
|
||||
this._contextCreatedEvent.options = context._options;
|
||||
}
|
||||
}
|
||||
_sdkLanguage() {
|
||||
return this._context instanceof import_browserContext.BrowserContext ? this._context._browser.sdkLanguage() : this._context.attribution.playwright.options.sdkLanguage;
|
||||
}
|
||||
async resetForReuse(progress) {
|
||||
await this.stopChunk(progress, { mode: "discard" }).catch(() => {
|
||||
});
|
||||
await this.stop(progress);
|
||||
if (this._snapshotter)
|
||||
await progress.race(this._snapshotter.resetForReuse());
|
||||
}
|
||||
start(options) {
|
||||
if (this._isStopping)
|
||||
throw new Error("Cannot start tracing while stopping");
|
||||
if (this._state)
|
||||
throw new Error("Tracing has been already started");
|
||||
this._contextCreatedEvent.sdkLanguage = this._sdkLanguage();
|
||||
const traceName = options.name || (0, import_crypto.createGuid)();
|
||||
const tracesDir = this._createTracesDirIfNeeded();
|
||||
this._state = {
|
||||
options,
|
||||
traceName,
|
||||
tracesDir,
|
||||
traceFile: import_path.default.join(tracesDir, traceName + ".trace"),
|
||||
networkFile: import_path.default.join(tracesDir, traceName + ".network"),
|
||||
resourcesDir: import_path.default.join(tracesDir, "resources"),
|
||||
chunkOrdinal: 0,
|
||||
traceSha1s: /* @__PURE__ */ new Set(),
|
||||
networkSha1s: /* @__PURE__ */ new Set(),
|
||||
recording: false,
|
||||
callIds: /* @__PURE__ */ new Set(),
|
||||
groupStack: []
|
||||
};
|
||||
this._fs.mkdir(this._state.resourcesDir);
|
||||
this._fs.writeFile(this._state.networkFile, "");
|
||||
if (options.snapshots)
|
||||
this._harTracer.start({ omitScripts: !options.live });
|
||||
}
|
||||
async startChunk(progress, options = {}) {
|
||||
if (this._state && this._state.recording)
|
||||
await this.stopChunk(progress, { mode: "discard" });
|
||||
if (!this._state)
|
||||
throw new Error("Must start tracing before starting a new chunk");
|
||||
if (this._isStopping)
|
||||
throw new Error("Cannot start a trace chunk while stopping");
|
||||
this._state.recording = true;
|
||||
this._state.callIds.clear();
|
||||
const preserveNetworkResources = this._context instanceof import_browserContext.BrowserContext;
|
||||
if (options.name && options.name !== this._state.traceName)
|
||||
this._changeTraceName(this._state, options.name, preserveNetworkResources);
|
||||
else
|
||||
this._allocateNewTraceFile(this._state);
|
||||
if (!preserveNetworkResources)
|
||||
this._fs.writeFile(this._state.networkFile, "");
|
||||
this._fs.mkdir(import_path.default.dirname(this._state.traceFile));
|
||||
const event = {
|
||||
...this._contextCreatedEvent,
|
||||
title: options.title,
|
||||
wallTime: Date.now(),
|
||||
monotonicTime: (0, import_time.monotonicTime)()
|
||||
};
|
||||
this._appendTraceEvent(event);
|
||||
this._context.instrumentation.addListener(this, this._context);
|
||||
this._eventListeners.push(
|
||||
import_eventsHelper.eventsHelper.addEventListener(this._context, import_browserContext.BrowserContext.Events.Console, this._onConsoleMessage.bind(this)),
|
||||
import_eventsHelper.eventsHelper.addEventListener(this._context, import_browserContext.BrowserContext.Events.PageError, this._onPageError.bind(this))
|
||||
);
|
||||
if (this._state.options.screenshots)
|
||||
this._startScreencast();
|
||||
if (this._state.options.snapshots)
|
||||
await this._snapshotter?.start();
|
||||
return { traceName: this._state.traceName };
|
||||
}
|
||||
_currentGroupId() {
|
||||
return this._state?.groupStack.length ? this._state.groupStack[this._state.groupStack.length - 1] : void 0;
|
||||
}
|
||||
group(name, location, metadata) {
|
||||
if (!this._state)
|
||||
return;
|
||||
const stackFrames = [];
|
||||
const { file, line, column } = location ?? metadata.location ?? {};
|
||||
if (file) {
|
||||
stackFrames.push({
|
||||
file,
|
||||
line: line ?? 0,
|
||||
column: column ?? 0
|
||||
});
|
||||
}
|
||||
const event = {
|
||||
type: "before",
|
||||
callId: metadata.id,
|
||||
startTime: metadata.startTime,
|
||||
title: name,
|
||||
class: "Tracing",
|
||||
method: "tracingGroup",
|
||||
params: {},
|
||||
stepId: metadata.stepId,
|
||||
stack: stackFrames
|
||||
};
|
||||
if (this._currentGroupId())
|
||||
event.parentId = this._currentGroupId();
|
||||
this._state.groupStack.push(event.callId);
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
groupEnd() {
|
||||
if (!this._state)
|
||||
return;
|
||||
const callId = this._state.groupStack.pop();
|
||||
if (!callId)
|
||||
return;
|
||||
const event = {
|
||||
type: "after",
|
||||
callId,
|
||||
endTime: (0, import_time.monotonicTime)()
|
||||
};
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
_startScreencast() {
|
||||
if (!(this._context instanceof import_browserContext.BrowserContext))
|
||||
return;
|
||||
for (const page of this._context.pages())
|
||||
this._startScreencastInPage(page);
|
||||
this._screencastListeners.push(
|
||||
import_eventsHelper.eventsHelper.addEventListener(this._context, import_browserContext.BrowserContext.Events.Page, this._startScreencastInPage.bind(this))
|
||||
);
|
||||
}
|
||||
_stopScreencast() {
|
||||
import_eventsHelper.eventsHelper.removeEventListeners(this._screencastListeners);
|
||||
if (!(this._context instanceof import_browserContext.BrowserContext))
|
||||
return;
|
||||
for (const page of this._context.pages())
|
||||
page.setScreencastOptions(null);
|
||||
}
|
||||
_allocateNewTraceFile(state) {
|
||||
const suffix = state.chunkOrdinal ? `-chunk${state.chunkOrdinal}` : ``;
|
||||
state.chunkOrdinal++;
|
||||
state.traceFile = import_path.default.join(state.tracesDir, `${state.traceName}${suffix}.trace`);
|
||||
}
|
||||
_changeTraceName(state, name, preserveNetworkResources) {
|
||||
state.traceName = name;
|
||||
state.chunkOrdinal = 0;
|
||||
this._allocateNewTraceFile(state);
|
||||
const newNetworkFile = import_path.default.join(state.tracesDir, name + ".network");
|
||||
if (preserveNetworkResources)
|
||||
this._fs.copyFile(state.networkFile, newNetworkFile);
|
||||
state.networkFile = newNetworkFile;
|
||||
}
|
||||
async stop(progress) {
|
||||
if (!this._state)
|
||||
return;
|
||||
if (this._isStopping)
|
||||
throw new Error(`Tracing is already stopping`);
|
||||
if (this._state.recording)
|
||||
throw new Error(`Must stop trace file before stopping tracing`);
|
||||
this._closeAllGroups();
|
||||
this._harTracer.stop();
|
||||
this.flushHarEntries();
|
||||
const promise = progress ? progress.race(this._fs.syncAndGetError()) : this._fs.syncAndGetError();
|
||||
await promise.finally(() => {
|
||||
this._state = void 0;
|
||||
});
|
||||
}
|
||||
async deleteTmpTracesDir() {
|
||||
if (this._tracesTmpDir)
|
||||
await (0, import_fileUtils.removeFolders)([this._tracesTmpDir]);
|
||||
}
|
||||
_createTracesDirIfNeeded() {
|
||||
if (this._precreatedTracesDir)
|
||||
return this._precreatedTracesDir;
|
||||
this._tracesTmpDir = import_fs.default.mkdtempSync(import_path.default.join(import_os.default.tmpdir(), "playwright-tracing-"));
|
||||
return this._tracesTmpDir;
|
||||
}
|
||||
abort() {
|
||||
this._snapshotter?.dispose();
|
||||
this._harTracer.stop();
|
||||
}
|
||||
async flush() {
|
||||
this.abort();
|
||||
await this._fs.syncAndGetError();
|
||||
}
|
||||
_closeAllGroups() {
|
||||
while (this._currentGroupId())
|
||||
this.groupEnd();
|
||||
}
|
||||
async stopChunk(progress, params) {
|
||||
if (this._isStopping)
|
||||
throw new Error(`Tracing is already stopping`);
|
||||
this._isStopping = true;
|
||||
if (!this._state || !this._state.recording) {
|
||||
this._isStopping = false;
|
||||
if (params.mode !== "discard")
|
||||
throw new Error(`Must start tracing before stopping`);
|
||||
return {};
|
||||
}
|
||||
this._closeAllGroups();
|
||||
this._context.instrumentation.removeListener(this);
|
||||
import_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
|
||||
if (this._state.options.screenshots)
|
||||
this._stopScreencast();
|
||||
if (this._state.options.snapshots)
|
||||
this._snapshotter?.stop();
|
||||
this.flushHarEntries();
|
||||
const newNetworkFile = import_path.default.join(this._state.tracesDir, this._state.traceName + `-pwnetcopy-${this._state.chunkOrdinal}.network`);
|
||||
const entries = [];
|
||||
entries.push({ name: "trace.trace", value: this._state.traceFile });
|
||||
entries.push({ name: "trace.network", value: newNetworkFile });
|
||||
for (const sha1 of /* @__PURE__ */ new Set([...this._state.traceSha1s, ...this._state.networkSha1s]))
|
||||
entries.push({ name: import_path.default.join("resources", sha1), value: import_path.default.join(this._state.resourcesDir, sha1) });
|
||||
this._state.traceSha1s = /* @__PURE__ */ new Set();
|
||||
if (params.mode === "discard") {
|
||||
this._isStopping = false;
|
||||
this._state.recording = false;
|
||||
return {};
|
||||
}
|
||||
this._fs.copyFile(this._state.networkFile, newNetworkFile);
|
||||
const zipFileName = this._state.traceFile + ".zip";
|
||||
if (params.mode === "archive")
|
||||
this._fs.zip(entries, zipFileName);
|
||||
const promise = progress ? progress.race(this._fs.syncAndGetError()) : this._fs.syncAndGetError();
|
||||
const error = await promise.catch((e) => e);
|
||||
this._isStopping = false;
|
||||
if (this._state)
|
||||
this._state.recording = false;
|
||||
if (error) {
|
||||
if (!(0, import_progress.isAbortError)(error) && this._context instanceof import_browserContext.BrowserContext && !this._context._browser.isConnected())
|
||||
return {};
|
||||
throw error;
|
||||
}
|
||||
if (params.mode === "entries")
|
||||
return { entries };
|
||||
const artifact = new import_artifact.Artifact(this._context, zipFileName);
|
||||
artifact.reportFinished();
|
||||
return { artifact };
|
||||
}
|
||||
async _captureSnapshot(snapshotName, sdkObject, metadata) {
|
||||
if (!this._snapshotter)
|
||||
return;
|
||||
if (!sdkObject.attribution.page)
|
||||
return;
|
||||
if (!this._snapshotter.started())
|
||||
return;
|
||||
if (!shouldCaptureSnapshot(metadata))
|
||||
return;
|
||||
await this._snapshotter.captureSnapshot(sdkObject.attribution.page, metadata.id, snapshotName).catch(() => {
|
||||
});
|
||||
}
|
||||
onBeforeCall(sdkObject, metadata) {
|
||||
const event = createBeforeActionTraceEvent(metadata, this._currentGroupId());
|
||||
if (!event)
|
||||
return Promise.resolve();
|
||||
sdkObject.attribution.page?.temporarilyDisableTracingScreencastThrottling();
|
||||
event.beforeSnapshot = `before@${metadata.id}`;
|
||||
this._state?.callIds.add(metadata.id);
|
||||
this._appendTraceEvent(event);
|
||||
return this._captureSnapshot(event.beforeSnapshot, sdkObject, metadata);
|
||||
}
|
||||
onBeforeInputAction(sdkObject, metadata) {
|
||||
if (!this._state?.callIds.has(metadata.id))
|
||||
return Promise.resolve();
|
||||
const event = createInputActionTraceEvent(metadata);
|
||||
if (!event)
|
||||
return Promise.resolve();
|
||||
sdkObject.attribution.page?.temporarilyDisableTracingScreencastThrottling();
|
||||
event.inputSnapshot = `input@${metadata.id}`;
|
||||
this._appendTraceEvent(event);
|
||||
return this._captureSnapshot(event.inputSnapshot, sdkObject, metadata);
|
||||
}
|
||||
onCallLog(sdkObject, metadata, logName, message) {
|
||||
if (!this._state?.callIds.has(metadata.id))
|
||||
return;
|
||||
if (metadata.internal)
|
||||
return;
|
||||
if (logName !== "api")
|
||||
return;
|
||||
const event = createActionLogTraceEvent(metadata, message);
|
||||
if (event)
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
async onAfterCall(sdkObject, metadata) {
|
||||
if (!this._state?.callIds.has(metadata.id))
|
||||
return;
|
||||
this._state?.callIds.delete(metadata.id);
|
||||
const event = createAfterActionTraceEvent(metadata);
|
||||
if (!event)
|
||||
return;
|
||||
sdkObject.attribution.page?.temporarilyDisableTracingScreencastThrottling();
|
||||
event.afterSnapshot = `after@${metadata.id}`;
|
||||
this._appendTraceEvent(event);
|
||||
return this._captureSnapshot(event.afterSnapshot, sdkObject, metadata);
|
||||
}
|
||||
onEntryStarted(entry) {
|
||||
this._pendingHarEntries.add(entry);
|
||||
}
|
||||
onEntryFinished(entry) {
|
||||
this._pendingHarEntries.delete(entry);
|
||||
const event = { type: "resource-snapshot", snapshot: entry };
|
||||
const visited = visitTraceEvent(event, this._state.networkSha1s);
|
||||
this._fs.appendFile(
|
||||
this._state.networkFile,
|
||||
JSON.stringify(visited) + "\n",
|
||||
true
|
||||
/* flush */
|
||||
);
|
||||
}
|
||||
flushHarEntries() {
|
||||
const harLines = [];
|
||||
for (const entry of this._pendingHarEntries) {
|
||||
const event = { type: "resource-snapshot", snapshot: entry };
|
||||
const visited = visitTraceEvent(event, this._state.networkSha1s);
|
||||
harLines.push(JSON.stringify(visited));
|
||||
}
|
||||
this._pendingHarEntries.clear();
|
||||
if (harLines.length)
|
||||
this._fs.appendFile(
|
||||
this._state.networkFile,
|
||||
harLines.join("\n") + "\n",
|
||||
true
|
||||
/* flush */
|
||||
);
|
||||
}
|
||||
onContentBlob(sha1, buffer) {
|
||||
this._appendResource(sha1, buffer);
|
||||
}
|
||||
onSnapshotterBlob(blob) {
|
||||
this._appendResource(blob.sha1, blob.buffer);
|
||||
}
|
||||
onFrameSnapshot(snapshot) {
|
||||
this._appendTraceEvent({ type: "frame-snapshot", snapshot });
|
||||
}
|
||||
_onConsoleMessage(message) {
|
||||
const event = {
|
||||
type: "console",
|
||||
messageType: message.type(),
|
||||
text: message.text(),
|
||||
args: message.args().map((a) => ({ preview: a.toString(), value: a.rawValue() })),
|
||||
location: message.location(),
|
||||
time: (0, import_time.monotonicTime)(),
|
||||
pageId: message.page()?.guid
|
||||
};
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
onDialog(dialog) {
|
||||
const event = {
|
||||
type: "event",
|
||||
time: (0, import_time.monotonicTime)(),
|
||||
class: "BrowserContext",
|
||||
method: "dialog",
|
||||
params: { pageId: dialog.page().guid, type: dialog.type(), message: dialog.message(), defaultValue: dialog.defaultValue() }
|
||||
};
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
onDownload(page, download) {
|
||||
const event = {
|
||||
type: "event",
|
||||
time: (0, import_time.monotonicTime)(),
|
||||
class: "BrowserContext",
|
||||
method: "download",
|
||||
params: { pageId: page.guid, url: download.url, suggestedFilename: download.suggestedFilename() }
|
||||
};
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
onPageOpen(page) {
|
||||
const event = {
|
||||
type: "event",
|
||||
time: (0, import_time.monotonicTime)(),
|
||||
class: "BrowserContext",
|
||||
method: "page",
|
||||
params: { pageId: page.guid, openerPageId: page.opener()?.guid }
|
||||
};
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
onPageClose(page) {
|
||||
const event = {
|
||||
type: "event",
|
||||
time: (0, import_time.monotonicTime)(),
|
||||
class: "BrowserContext",
|
||||
method: "pageClosed",
|
||||
params: { pageId: page.guid }
|
||||
};
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
_onPageError(error, page) {
|
||||
const event = {
|
||||
type: "event",
|
||||
time: (0, import_time.monotonicTime)(),
|
||||
class: "BrowserContext",
|
||||
method: "pageError",
|
||||
params: { error: (0, import_errors.serializeError)(error) },
|
||||
pageId: page.guid
|
||||
};
|
||||
this._appendTraceEvent(event);
|
||||
}
|
||||
_startScreencastInPage(page) {
|
||||
page.setScreencastOptions(kScreencastOptions);
|
||||
const prefix = page.guid;
|
||||
this._screencastListeners.push(
|
||||
import_eventsHelper.eventsHelper.addEventListener(page, import_page.Page.Events.ScreencastFrame, (params) => {
|
||||
const suffix = params.timestamp || Date.now();
|
||||
const sha1 = `${prefix}-${suffix}.jpeg`;
|
||||
const event = {
|
||||
type: "screencast-frame",
|
||||
pageId: page.guid,
|
||||
sha1,
|
||||
width: params.width,
|
||||
height: params.height,
|
||||
timestamp: (0, import_time.monotonicTime)(),
|
||||
frameSwapWallTime: params.frameSwapWallTime
|
||||
};
|
||||
this._appendResource(sha1, params.buffer);
|
||||
this._appendTraceEvent(event);
|
||||
})
|
||||
);
|
||||
}
|
||||
_appendTraceEvent(event) {
|
||||
const visited = visitTraceEvent(event, this._state.traceSha1s);
|
||||
const flush = this._state.options.live || event.type !== "event" && event.type !== "console" && event.type !== "log";
|
||||
this._fs.appendFile(this._state.traceFile, JSON.stringify(visited) + "\n", flush);
|
||||
}
|
||||
_appendResource(sha1, buffer) {
|
||||
if (this._allResources.has(sha1))
|
||||
return;
|
||||
this._allResources.add(sha1);
|
||||
const resourcePath = import_path.default.join(this._state.resourcesDir, sha1);
|
||||
this._fs.writeFile(
|
||||
resourcePath,
|
||||
buffer,
|
||||
true
|
||||
/* skipIfExists */
|
||||
);
|
||||
}
|
||||
}
|
||||
function visitTraceEvent(object, sha1s) {
|
||||
if (Array.isArray(object))
|
||||
return object.map((o) => visitTraceEvent(o, sha1s));
|
||||
if (object instanceof import_dispatcher.Dispatcher)
|
||||
return `<${object._type}>`;
|
||||
if (object instanceof Buffer)
|
||||
return `<Buffer>`;
|
||||
if (object instanceof Date)
|
||||
return object;
|
||||
if (typeof object === "object") {
|
||||
const result = {};
|
||||
for (const key in object) {
|
||||
if (key === "sha1" || key === "_sha1" || key.endsWith("Sha1")) {
|
||||
const sha1 = object[key];
|
||||
if (sha1)
|
||||
sha1s.add(sha1);
|
||||
}
|
||||
result[key] = visitTraceEvent(object[key], sha1s);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
function shouldCaptureSnapshot(metadata) {
|
||||
const metainfo = import_protocolMetainfo.methodMetainfo.get(metadata.type + "." + metadata.method);
|
||||
return !!metainfo?.snapshot;
|
||||
}
|
||||
function createBeforeActionTraceEvent(metadata, parentId) {
|
||||
if (metadata.internal || metadata.method.startsWith("tracing"))
|
||||
return null;
|
||||
const event = {
|
||||
type: "before",
|
||||
callId: metadata.id,
|
||||
startTime: metadata.startTime,
|
||||
title: metadata.title,
|
||||
class: metadata.type,
|
||||
method: metadata.method,
|
||||
params: metadata.params,
|
||||
stepId: metadata.stepId,
|
||||
pageId: metadata.pageId
|
||||
};
|
||||
if (parentId)
|
||||
event.parentId = parentId;
|
||||
return event;
|
||||
}
|
||||
function createInputActionTraceEvent(metadata) {
|
||||
if (metadata.internal || metadata.method.startsWith("tracing"))
|
||||
return null;
|
||||
return {
|
||||
type: "input",
|
||||
callId: metadata.id,
|
||||
point: metadata.point
|
||||
};
|
||||
}
|
||||
function createActionLogTraceEvent(metadata, message) {
|
||||
if (metadata.internal || metadata.method.startsWith("tracing"))
|
||||
return null;
|
||||
return {
|
||||
type: "log",
|
||||
callId: metadata.id,
|
||||
time: (0, import_time.monotonicTime)(),
|
||||
message
|
||||
};
|
||||
}
|
||||
function createAfterActionTraceEvent(metadata) {
|
||||
if (metadata.internal || metadata.method.startsWith("tracing"))
|
||||
return null;
|
||||
return {
|
||||
type: "after",
|
||||
callId: metadata.id,
|
||||
endTime: metadata.endTime,
|
||||
error: metadata.error?.error,
|
||||
result: metadata.result,
|
||||
point: metadata.point
|
||||
};
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
Tracing
|
||||
});
|
87
node_modules/playwright-core/lib/server/trace/test/inMemorySnapshotter.js
generated
vendored
Normal file
87
node_modules/playwright-core/lib/server/trace/test/inMemorySnapshotter.js
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var inMemorySnapshotter_exports = {};
|
||||
__export(inMemorySnapshotter_exports, {
|
||||
InMemorySnapshotter: () => InMemorySnapshotter
|
||||
});
|
||||
module.exports = __toCommonJS(inMemorySnapshotter_exports);
|
||||
var import_snapshotStorage = require("../../../../../trace-viewer/src/sw/snapshotStorage");
|
||||
var import_utils = require("../../../utils");
|
||||
var import_harTracer = require("../../har/harTracer");
|
||||
var import_snapshotter = require("../recorder/snapshotter");
|
||||
class InMemorySnapshotter {
|
||||
constructor(context) {
|
||||
this._blobs = /* @__PURE__ */ new Map();
|
||||
this._snapshotReadyPromises = /* @__PURE__ */ new Map();
|
||||
this._snapshotCount = 0;
|
||||
this._snapshotter = new import_snapshotter.Snapshotter(context, this);
|
||||
this._harTracer = new import_harTracer.HarTracer(context, null, this, { content: "attach", includeTraceInfo: true, recordRequestOverrides: false, waitForContentOnStop: false });
|
||||
this._storage = new import_snapshotStorage.SnapshotStorage();
|
||||
}
|
||||
async initialize() {
|
||||
await this._snapshotter.start();
|
||||
this._harTracer.start({ omitScripts: true });
|
||||
}
|
||||
async reset() {
|
||||
await this._snapshotter.reset();
|
||||
await this._harTracer.flush();
|
||||
this._harTracer.stop();
|
||||
this._harTracer.start({ omitScripts: true });
|
||||
}
|
||||
async dispose() {
|
||||
this._snapshotter.dispose();
|
||||
await this._harTracer.flush();
|
||||
this._harTracer.stop();
|
||||
}
|
||||
async captureSnapshot(page, callId, snapshotName) {
|
||||
if (this._snapshotReadyPromises.has(snapshotName))
|
||||
throw new Error("Duplicate snapshot name: " + snapshotName);
|
||||
this._snapshotter.captureSnapshot(page, callId, snapshotName).catch(() => {
|
||||
});
|
||||
const promise = new import_utils.ManualPromise();
|
||||
this._snapshotReadyPromises.set(snapshotName, promise);
|
||||
return promise;
|
||||
}
|
||||
onEntryStarted(entry) {
|
||||
}
|
||||
onEntryFinished(entry) {
|
||||
this._storage.addResource("", entry);
|
||||
}
|
||||
onContentBlob(sha1, buffer) {
|
||||
this._blobs.set(sha1, buffer);
|
||||
}
|
||||
onSnapshotterBlob(blob) {
|
||||
this._blobs.set(blob.sha1, blob.buffer);
|
||||
}
|
||||
onFrameSnapshot(snapshot) {
|
||||
++this._snapshotCount;
|
||||
const renderer = this._storage.addFrameSnapshot("", snapshot, []);
|
||||
this._snapshotReadyPromises.get(snapshot.snapshotName || "")?.resolve(renderer);
|
||||
}
|
||||
async resourceContentForTest(sha1) {
|
||||
return this._blobs.get(sha1);
|
||||
}
|
||||
snapshotCount() {
|
||||
return this._snapshotCount;
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
InMemorySnapshotter
|
||||
});
|
240
node_modules/playwright-core/lib/server/trace/viewer/traceViewer.js
generated
vendored
Normal file
240
node_modules/playwright-core/lib/server/trace/viewer/traceViewer.js
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var traceViewer_exports = {};
|
||||
__export(traceViewer_exports, {
|
||||
installRootRedirect: () => installRootRedirect,
|
||||
openTraceInBrowser: () => openTraceInBrowser,
|
||||
openTraceViewerApp: () => openTraceViewerApp,
|
||||
runTraceInBrowser: () => runTraceInBrowser,
|
||||
runTraceViewerApp: () => runTraceViewerApp,
|
||||
startTraceViewerServer: () => startTraceViewerServer
|
||||
});
|
||||
module.exports = __toCommonJS(traceViewer_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("../../../utils");
|
||||
var import_utils2 = require("../../../utils");
|
||||
var import_httpServer = require("../../utils/httpServer");
|
||||
var import_utilsBundle = require("../../../utilsBundle");
|
||||
var import_launchApp = require("../../launchApp");
|
||||
var import_launchApp2 = require("../../launchApp");
|
||||
var import_playwright = require("../../playwright");
|
||||
var import_progress = require("../../progress");
|
||||
function validateTraceUrls(traceUrls) {
|
||||
for (const traceUrl of traceUrls) {
|
||||
let traceFile = traceUrl;
|
||||
if (traceUrl.endsWith(".json"))
|
||||
traceFile = traceUrl.substring(0, traceUrl.length - ".json".length);
|
||||
if (!traceUrl.startsWith("http://") && !traceUrl.startsWith("https://") && !import_fs.default.existsSync(traceFile) && !import_fs.default.existsSync(traceFile + ".trace"))
|
||||
throw new Error(`Trace file ${traceUrl} does not exist!`);
|
||||
}
|
||||
}
|
||||
async function startTraceViewerServer(options) {
|
||||
const server = new import_httpServer.HttpServer();
|
||||
server.routePrefix("/trace", (request, response) => {
|
||||
const url = new URL("http://localhost" + request.url);
|
||||
const relativePath = url.pathname.slice("/trace".length);
|
||||
if (process.env.PW_HMR) {
|
||||
response.appendHeader("Access-Control-Allow-Origin", "http://localhost:44223");
|
||||
}
|
||||
if (relativePath.endsWith("/stall.js"))
|
||||
return true;
|
||||
if (relativePath.startsWith("/file")) {
|
||||
try {
|
||||
const filePath = url.searchParams.get("path");
|
||||
if (import_fs.default.existsSync(filePath))
|
||||
return server.serveFile(request, response, url.searchParams.get("path"));
|
||||
if (filePath.endsWith(".json")) {
|
||||
const traceName = filePath.substring(0, filePath.length - ".json".length);
|
||||
response.statusCode = 200;
|
||||
response.setHeader("Content-Type", "application/json");
|
||||
response.end(JSON.stringify(traceDescriptor(traceName)));
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
response.statusCode = 404;
|
||||
response.end();
|
||||
return true;
|
||||
}
|
||||
const absolutePath = import_path.default.join(__dirname, "..", "..", "..", "vite", "traceViewer", ...relativePath.split("/"));
|
||||
return server.serveFile(request, response, absolutePath);
|
||||
});
|
||||
const transport = options?.transport || (options?.isServer ? new StdinServer() : void 0);
|
||||
if (transport)
|
||||
server.createWebSocket(transport);
|
||||
const { host, port } = options || {};
|
||||
await server.start({ preferredPort: port, host });
|
||||
return server;
|
||||
}
|
||||
async function installRootRedirect(server, traceUrls, options) {
|
||||
const params = new URLSearchParams();
|
||||
if (import_path.default.sep !== import_path.default.posix.sep)
|
||||
params.set("pathSeparator", import_path.default.sep);
|
||||
for (const traceUrl of traceUrls)
|
||||
params.append("trace", traceUrl);
|
||||
if (server.wsGuid())
|
||||
params.append("ws", server.wsGuid());
|
||||
if (options?.isServer)
|
||||
params.append("isServer", "");
|
||||
if ((0, import_utils2.isUnderTest)())
|
||||
params.append("isUnderTest", "true");
|
||||
for (const arg of options.args || [])
|
||||
params.append("arg", arg);
|
||||
if (options.grep)
|
||||
params.append("grep", options.grep);
|
||||
if (options.grepInvert)
|
||||
params.append("grepInvert", options.grepInvert);
|
||||
for (const project of options.project || [])
|
||||
params.append("project", project);
|
||||
for (const reporter of options.reporter || [])
|
||||
params.append("reporter", reporter);
|
||||
let baseUrl = ".";
|
||||
if (process.env.PW_HMR) {
|
||||
baseUrl = "http://localhost:44223";
|
||||
params.set("server", server.urlPrefix("precise"));
|
||||
}
|
||||
const urlPath = `${baseUrl}/trace/${options.webApp || "index.html"}?${params.toString()}`;
|
||||
server.routePath("/", (_, response) => {
|
||||
response.statusCode = 302;
|
||||
response.setHeader("Location", urlPath);
|
||||
response.end();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
async function runTraceViewerApp(traceUrls, browserName, options, exitOnClose) {
|
||||
validateTraceUrls(traceUrls);
|
||||
const server = await startTraceViewerServer(options);
|
||||
await installRootRedirect(server, traceUrls, options);
|
||||
const page = await openTraceViewerApp(server.urlPrefix("precise"), browserName, options);
|
||||
if (exitOnClose)
|
||||
page.on("close", () => (0, import_utils.gracefullyProcessExitDoNotHang)(0));
|
||||
return page;
|
||||
}
|
||||
async function runTraceInBrowser(traceUrls, options) {
|
||||
validateTraceUrls(traceUrls);
|
||||
const server = await startTraceViewerServer(options);
|
||||
await installRootRedirect(server, traceUrls, options);
|
||||
await openTraceInBrowser(server.urlPrefix("human-readable"));
|
||||
}
|
||||
async function openTraceViewerApp(url, browserName, options) {
|
||||
const traceViewerPlaywright = (0, import_playwright.createPlaywright)({ sdkLanguage: "javascript", isInternalPlaywright: true });
|
||||
const traceViewerBrowser = (0, import_utils2.isUnderTest)() ? "chromium" : browserName;
|
||||
const { context, page } = await (0, import_launchApp2.launchApp)(traceViewerPlaywright[traceViewerBrowser], {
|
||||
sdkLanguage: traceViewerPlaywright.options.sdkLanguage,
|
||||
windowSize: { width: 1280, height: 800 },
|
||||
persistentContextOptions: {
|
||||
...options?.persistentContextOptions,
|
||||
cdpPort: (0, import_utils2.isUnderTest)() ? 0 : void 0,
|
||||
headless: !!options?.headless,
|
||||
colorScheme: (0, import_utils2.isUnderTest)() ? "light" : void 0
|
||||
}
|
||||
});
|
||||
const controller = new import_progress.ProgressController();
|
||||
await controller.run(async (progress) => {
|
||||
await context._browser._defaultContext._loadDefaultContextAsIs(progress);
|
||||
if (process.env.PWTEST_PRINT_WS_ENDPOINT) {
|
||||
process.stderr.write("DevTools listening on: " + context._browser.options.wsEndpoint + "\n");
|
||||
}
|
||||
if (!(0, import_utils2.isUnderTest)())
|
||||
await (0, import_launchApp.syncLocalStorageWithSettings)(page, "traceviewer");
|
||||
if ((0, import_utils2.isUnderTest)())
|
||||
page.on("close", () => context.close({ reason: "Trace viewer closed" }).catch(() => {
|
||||
}));
|
||||
await page.mainFrame().goto(progress, url);
|
||||
});
|
||||
return page;
|
||||
}
|
||||
async function openTraceInBrowser(url) {
|
||||
console.log("\nListening on " + url);
|
||||
if (!(0, import_utils2.isUnderTest)())
|
||||
await (0, import_utilsBundle.open)(url.replace("0.0.0.0", "localhost")).catch(() => {
|
||||
});
|
||||
}
|
||||
class StdinServer {
|
||||
constructor() {
|
||||
process.stdin.on("data", (data) => {
|
||||
const url = data.toString().trim();
|
||||
if (url === this._traceUrl)
|
||||
return;
|
||||
if (url.endsWith(".json"))
|
||||
this._pollLoadTrace(url);
|
||||
else
|
||||
this._loadTrace(url);
|
||||
});
|
||||
process.stdin.on("close", () => (0, import_utils.gracefullyProcessExitDoNotHang)(0));
|
||||
}
|
||||
onconnect() {
|
||||
}
|
||||
async dispatch(method, params) {
|
||||
if (method === "initialize") {
|
||||
if (this._traceUrl)
|
||||
this._loadTrace(this._traceUrl);
|
||||
}
|
||||
}
|
||||
onclose() {
|
||||
}
|
||||
_loadTrace(traceUrl) {
|
||||
this._traceUrl = traceUrl;
|
||||
clearTimeout(this._pollTimer);
|
||||
this.sendEvent?.("loadTraceRequested", { traceUrl });
|
||||
}
|
||||
_pollLoadTrace(url) {
|
||||
this._loadTrace(url);
|
||||
this._pollTimer = setTimeout(() => {
|
||||
this._pollLoadTrace(url);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
function traceDescriptor(traceName) {
|
||||
const result = {
|
||||
entries: []
|
||||
};
|
||||
const traceDir = import_path.default.dirname(traceName);
|
||||
const traceFile = import_path.default.basename(traceName);
|
||||
for (const name of import_fs.default.readdirSync(traceDir)) {
|
||||
if (name.startsWith(traceFile))
|
||||
result.entries.push({ name, path: import_path.default.join(traceDir, name) });
|
||||
}
|
||||
const resourcesDir = import_path.default.join(traceDir, "resources");
|
||||
if (import_fs.default.existsSync(resourcesDir)) {
|
||||
for (const name of import_fs.default.readdirSync(resourcesDir))
|
||||
result.entries.push({ name: "resources/" + name, path: import_path.default.join(resourcesDir, name) });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
installRootRedirect,
|
||||
openTraceInBrowser,
|
||||
openTraceViewerApp,
|
||||
runTraceInBrowser,
|
||||
runTraceViewerApp,
|
||||
startTraceViewerServer
|
||||
});
|
Reference in New Issue
Block a user