playwright-core 1.54.0-alpha-2025-07-08 → 1.54.0-beta-1752075907000
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/browsers.json +6 -6
- package/lib/client/browserContext.js +19 -5
- package/lib/client/page.js +4 -4
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- package/lib/protocol/validator.js +8 -1
- package/lib/server/browserContext.js +2 -1
- package/lib/server/chromium/chromium.js +0 -2
- package/lib/server/codegen/csharp.js +1 -1
- package/lib/server/codegen/java.js +1 -1
- package/lib/server/codegen/javascript.js +1 -1
- package/lib/server/codegen/python.js +1 -1
- package/lib/server/debugController.js +2 -2
- package/lib/server/deviceDescriptorsSource.json +81 -81
- package/lib/server/dispatchers/browserContextDispatcher.js +14 -0
- package/lib/server/recorder/recorderApp.js +31 -2
- package/lib/server/recorder/recorderSignalProcessor.js +20 -8
- package/lib/server/recorder/recorderUtils.js +16 -5
- package/lib/server/recorder.js +16 -11
- package/lib/server/utils/comparators.js +2 -2
- package/lib/server/webkit/wkBrowser.js +1 -1
- package/lib/utils/isomorphic/protocolMetainfo.js +1 -0
- package/lib/vite/htmlReport/index.html +14 -18
- package/lib/vite/traceViewer/assets/{codeMirrorModule-B2cH4C1Z.js → codeMirrorModule-Djh-rPQr.js} +1 -1
- package/lib/vite/traceViewer/assets/defaultSettingsView-BsQs1KiL.js +256 -0
- package/lib/vite/traceViewer/{index.CPrh2bDb.js → index.LwN9z-Hp.js} +1 -1
- package/lib/vite/traceViewer/index.html +2 -2
- package/lib/vite/traceViewer/{uiMode.zJf6t5Og.js → uiMode.DyB42ep8.js} +1 -1
- package/lib/vite/traceViewer/uiMode.html +2 -2
- package/package.json +1 -1
- package/types/types.d.ts +0 -7
- package/lib/vite/traceViewer/assets/defaultSettingsView-DzmHcS17.js +0 -256
|
@@ -50,6 +50,7 @@ var import_webSocketRouteDispatcher = require("./webSocketRouteDispatcher");
|
|
|
50
50
|
var import_writableStreamDispatcher = require("./writableStreamDispatcher");
|
|
51
51
|
var import_crypto = require("../utils/crypto");
|
|
52
52
|
var import_urlMatch = require("../../utils/isomorphic/urlMatch");
|
|
53
|
+
var import_recorder = require("../recorder");
|
|
53
54
|
var import_recorderApp = require("../recorder/recorderApp");
|
|
54
55
|
class BrowserContextDispatcher extends import_dispatcher.Dispatcher {
|
|
55
56
|
constructor(parentScope, context) {
|
|
@@ -177,6 +178,9 @@ class BrowserContextDispatcher extends import_dispatcher.Dispatcher {
|
|
|
177
178
|
page: import_pageDispatcher.PageDispatcher.fromNullable(this, request.frame()?._page.initializedOrUndefined())
|
|
178
179
|
});
|
|
179
180
|
});
|
|
181
|
+
this.addObjectListener(import_browserContext.BrowserContext.Events.RecorderEvent, ({ event, data, page }) => {
|
|
182
|
+
this._dispatchEvent("recorderEvent", { event, data, page: import_pageDispatcher.PageDispatcher.from(this, page) });
|
|
183
|
+
});
|
|
180
184
|
}
|
|
181
185
|
static from(parentScope, context) {
|
|
182
186
|
const result = parentScope.connection.existingDispatcher(context);
|
|
@@ -288,8 +292,18 @@ class BrowserContextDispatcher extends import_dispatcher.Dispatcher {
|
|
|
288
292
|
await this._context.close(params);
|
|
289
293
|
}
|
|
290
294
|
async enableRecorder(params, progress) {
|
|
295
|
+
const recorder = await import_recorder.Recorder.forContext(this._context, params);
|
|
296
|
+
if (params.recorderMode === "api") {
|
|
297
|
+
await import_recorderApp.ProgrammaticRecorderApp.run(this._context, recorder);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
291
300
|
await import_recorderApp.RecorderApp.show(this._context, params);
|
|
292
301
|
}
|
|
302
|
+
async disableRecorder(params, progress) {
|
|
303
|
+
const recorder = import_recorder.Recorder.existingForContext(this._context);
|
|
304
|
+
if (recorder)
|
|
305
|
+
recorder.setMode("none");
|
|
306
|
+
}
|
|
293
307
|
async pause(params, progress) {
|
|
294
308
|
}
|
|
295
309
|
async newCDPSession(params, progress) {
|
|
@@ -28,6 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var recorderApp_exports = {};
|
|
30
30
|
__export(recorderApp_exports, {
|
|
31
|
+
ProgrammaticRecorderApp: () => ProgrammaticRecorderApp,
|
|
31
32
|
RecorderApp: () => RecorderApp
|
|
32
33
|
});
|
|
33
34
|
module.exports = __toCommonJS(recorderApp_exports);
|
|
@@ -45,6 +46,7 @@ var import_recorderUtils = require("./recorderUtils");
|
|
|
45
46
|
var import_language = require("../codegen/language");
|
|
46
47
|
var import_recorder = require("../recorder");
|
|
47
48
|
var import_time = require("../../utils/isomorphic/time");
|
|
49
|
+
var import_browserContext = require("../browserContext");
|
|
48
50
|
class RecorderApp {
|
|
49
51
|
constructor(recorder, params, page, wsEndpointForTest) {
|
|
50
52
|
this._throttledOutputFile = null;
|
|
@@ -149,6 +151,10 @@ class RecorderApp {
|
|
|
149
151
|
if (process.env.PW_CODEGEN_NO_INSPECTOR)
|
|
150
152
|
return;
|
|
151
153
|
const recorder = await import_recorder.Recorder.forContext(context, params);
|
|
154
|
+
if (params.recorderMode === "api") {
|
|
155
|
+
await ProgrammaticRecorderApp.run(context, recorder);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
152
158
|
await RecorderApp._show(recorder, context, params);
|
|
153
159
|
}
|
|
154
160
|
async close() {
|
|
@@ -232,9 +238,9 @@ class RecorderApp {
|
|
|
232
238
|
this._updateActions();
|
|
233
239
|
}
|
|
234
240
|
_onSignalAdded(signal) {
|
|
235
|
-
const lastAction = this._actions
|
|
241
|
+
const lastAction = this._actions.findLast((a) => a.frame.pageGuid === signal.frame.pageGuid);
|
|
236
242
|
if (lastAction)
|
|
237
|
-
lastAction.action.signals.push(signal);
|
|
243
|
+
lastAction.action.signals.push(signal.signal);
|
|
238
244
|
this._updateActions();
|
|
239
245
|
}
|
|
240
246
|
_onPageNavigated(url) {
|
|
@@ -322,8 +328,31 @@ class RecorderApp {
|
|
|
322
328
|
this._pushAllSources();
|
|
323
329
|
}
|
|
324
330
|
}
|
|
331
|
+
class ProgrammaticRecorderApp {
|
|
332
|
+
static async run(inspectedContext, recorder) {
|
|
333
|
+
let lastAction = null;
|
|
334
|
+
recorder.on(import_recorder.RecorderEvent.ActionAdded, (action) => {
|
|
335
|
+
const page = findPageByGuid(inspectedContext, action.frame.pageGuid);
|
|
336
|
+
if (!page)
|
|
337
|
+
return;
|
|
338
|
+
if (!lastAction || !(0, import_recorderUtils.shouldMergeAction)(action, lastAction))
|
|
339
|
+
inspectedContext.emit(import_browserContext.BrowserContext.Events.RecorderEvent, { event: "actionAdded", data: action, page });
|
|
340
|
+
else
|
|
341
|
+
inspectedContext.emit(import_browserContext.BrowserContext.Events.RecorderEvent, { event: "actionUpdated", data: action, page });
|
|
342
|
+
lastAction = action;
|
|
343
|
+
});
|
|
344
|
+
recorder.on(import_recorder.RecorderEvent.SignalAdded, (signal) => {
|
|
345
|
+
const page = findPageByGuid(inspectedContext, signal.frame.pageGuid);
|
|
346
|
+
inspectedContext.emit(import_browserContext.BrowserContext.Events.RecorderEvent, { event: "signalAdded", data: signal, page });
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
function findPageByGuid(context, guid) {
|
|
351
|
+
return context.pages().find((p) => p.guid === guid);
|
|
352
|
+
}
|
|
325
353
|
const recorderAppSymbol = Symbol("recorderApp");
|
|
326
354
|
// Annotate the CommonJS export names for ESM import in node:
|
|
327
355
|
0 && (module.exports = {
|
|
356
|
+
ProgrammaticRecorderApp,
|
|
328
357
|
RecorderApp
|
|
329
358
|
});
|
|
@@ -21,21 +21,21 @@ __export(recorderSignalProcessor_exports, {
|
|
|
21
21
|
RecorderSignalProcessor: () => RecorderSignalProcessor
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(recorderSignalProcessor_exports);
|
|
24
|
-
var import_events = require("events");
|
|
25
24
|
var import_debug = require("../utils/debug");
|
|
26
25
|
var import_time = require("../../utils/isomorphic/time");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
var import_recorderUtils = require("./recorderUtils");
|
|
27
|
+
class RecorderSignalProcessor {
|
|
28
|
+
constructor(actionSink) {
|
|
30
29
|
this._lastAction = null;
|
|
30
|
+
this._delegate = actionSink;
|
|
31
31
|
}
|
|
32
|
-
addAction(actionInContext
|
|
32
|
+
addAction(actionInContext) {
|
|
33
33
|
this._lastAction = actionInContext;
|
|
34
|
-
this.
|
|
34
|
+
this._delegate.addAction(actionInContext);
|
|
35
35
|
}
|
|
36
36
|
signal(pageAlias, frame, signal) {
|
|
37
|
+
const timestamp = (0, import_time.monotonicTime)();
|
|
37
38
|
if (signal.name === "navigation" && frame._page.mainFrame() === frame) {
|
|
38
|
-
const timestamp = (0, import_time.monotonicTime)();
|
|
39
39
|
const lastAction = this._lastAction;
|
|
40
40
|
const signalThreshold = (0, import_debug.isUnderTest)() ? 500 : 5e3;
|
|
41
41
|
let generateGoto = false;
|
|
@@ -48,6 +48,7 @@ class RecorderSignalProcessor extends import_events.EventEmitter {
|
|
|
48
48
|
if (generateGoto) {
|
|
49
49
|
this.addAction({
|
|
50
50
|
frame: {
|
|
51
|
+
pageGuid: frame._page.guid,
|
|
51
52
|
pageAlias,
|
|
52
53
|
framePath: []
|
|
53
54
|
},
|
|
@@ -62,7 +63,18 @@ class RecorderSignalProcessor extends import_events.EventEmitter {
|
|
|
62
63
|
}
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
+
(0, import_recorderUtils.generateFrameSelector)(frame).then((framePath) => {
|
|
67
|
+
const signalInContext = {
|
|
68
|
+
frame: {
|
|
69
|
+
pageGuid: frame._page.guid,
|
|
70
|
+
pageAlias,
|
|
71
|
+
framePath
|
|
72
|
+
},
|
|
73
|
+
signal,
|
|
74
|
+
timestamp
|
|
75
|
+
};
|
|
76
|
+
this._delegate.addSignal(signalInContext);
|
|
77
|
+
});
|
|
66
78
|
}
|
|
67
79
|
}
|
|
68
80
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -23,7 +23,8 @@ __export(recorderUtils_exports, {
|
|
|
23
23
|
frameForAction: () => frameForAction,
|
|
24
24
|
generateFrameSelector: () => generateFrameSelector,
|
|
25
25
|
mainFrameForAction: () => mainFrameForAction,
|
|
26
|
-
metadataToCallLog: () => metadataToCallLog
|
|
26
|
+
metadataToCallLog: () => metadataToCallLog,
|
|
27
|
+
shouldMergeAction: () => shouldMergeAction
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(recorderUtils_exports);
|
|
29
30
|
var import_protocolFormatter = require("../../utils/isomorphic/protocolFormatter");
|
|
@@ -74,13 +75,22 @@ async function frameForAction(pageAliases, actionInContext, action) {
|
|
|
74
75
|
throw new Error("Internal error: frame not found");
|
|
75
76
|
return result.frame;
|
|
76
77
|
}
|
|
78
|
+
function isSameAction(a, b) {
|
|
79
|
+
return a.action.name === b.action.name && a.frame.pageAlias === b.frame.pageAlias && a.frame.framePath.join("|") === b.frame.framePath.join("|");
|
|
80
|
+
}
|
|
81
|
+
function isSameSelector(action, lastAction) {
|
|
82
|
+
return "selector" in action.action && "selector" in lastAction.action && action.action.selector === lastAction.action.selector;
|
|
83
|
+
}
|
|
84
|
+
function shouldMergeAction(action, lastAction) {
|
|
85
|
+
if (!lastAction)
|
|
86
|
+
return false;
|
|
87
|
+
return isSameAction(action, lastAction) && (action.action.name === "navigate" || action.action.name === "fill" && isSameSelector(action, lastAction));
|
|
88
|
+
}
|
|
77
89
|
function collapseActions(actions) {
|
|
78
90
|
const result = [];
|
|
79
91
|
for (const action of actions) {
|
|
80
92
|
const lastAction = result[result.length - 1];
|
|
81
|
-
const
|
|
82
|
-
const isSameSelector = lastAction && "selector" in lastAction.action && "selector" in action.action && action.action.selector === lastAction.action.selector;
|
|
83
|
-
const shouldMerge = isSameAction && (action.action.name === "navigate" || action.action.name === "fill" && isSameSelector);
|
|
93
|
+
const shouldMerge = shouldMergeAction(action, lastAction);
|
|
84
94
|
if (!shouldMerge) {
|
|
85
95
|
result.push(action);
|
|
86
96
|
continue;
|
|
@@ -131,5 +141,6 @@ async function generateFrameSelectorInParent(parent, frame) {
|
|
|
131
141
|
frameForAction,
|
|
132
142
|
generateFrameSelector,
|
|
133
143
|
mainFrameForAction,
|
|
134
|
-
metadataToCallLog
|
|
144
|
+
metadataToCallLog,
|
|
145
|
+
shouldMergeAction
|
|
135
146
|
});
|
package/lib/server/recorder.js
CHANGED
|
@@ -79,16 +79,17 @@ class Recorder extends import_events.default {
|
|
|
79
79
|
this._context = context;
|
|
80
80
|
this._params = params;
|
|
81
81
|
this._mode = params.mode || "none";
|
|
82
|
-
this._recorderMode = params.recorderMode ?? "
|
|
82
|
+
this._recorderMode = params.recorderMode ?? "default";
|
|
83
83
|
this.handleSIGINT = params.handleSIGINT;
|
|
84
|
-
this._signalProcessor = new import_recorderSignalProcessor.RecorderSignalProcessor(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
this._signalProcessor = new import_recorderSignalProcessor.RecorderSignalProcessor({
|
|
85
|
+
addAction: (actionInContext) => {
|
|
86
|
+
if (this._enabled)
|
|
87
|
+
this.emit(RecorderEvent.ActionAdded, actionInContext);
|
|
88
|
+
},
|
|
89
|
+
addSignal: (signal) => {
|
|
90
|
+
if (this._enabled)
|
|
91
|
+
this.emit(RecorderEvent.SignalAdded, signal);
|
|
92
|
+
}
|
|
92
93
|
});
|
|
93
94
|
context.on(import_browserContext.BrowserContext.Events.BeforeClose, () => {
|
|
94
95
|
this.emit(RecorderEvent.ContextClosed);
|
|
@@ -112,6 +113,9 @@ class Recorder extends import_events.default {
|
|
|
112
113
|
}
|
|
113
114
|
return recorderPromise;
|
|
114
115
|
}
|
|
116
|
+
static existingForContext(context) {
|
|
117
|
+
return context[recorderSymbol];
|
|
118
|
+
}
|
|
115
119
|
static async _create(context, params = {}) {
|
|
116
120
|
const recorder = new Recorder(context, params);
|
|
117
121
|
await recorder._install();
|
|
@@ -142,7 +146,6 @@ class Recorder extends import_events.default {
|
|
|
142
146
|
}
|
|
143
147
|
const uiState = {
|
|
144
148
|
mode: this._mode,
|
|
145
|
-
recorderMode: this._recorderMode,
|
|
146
149
|
actionPoint,
|
|
147
150
|
actionSelector,
|
|
148
151
|
ariaTemplate: this._highlightedElement.ariaTemplate,
|
|
@@ -188,7 +191,7 @@ class Recorder extends import_events.default {
|
|
|
188
191
|
false,
|
|
189
192
|
(source, action) => this._recordAction(source.frame, action)
|
|
190
193
|
);
|
|
191
|
-
await this._context.extendInjectedScript(rawRecorderSource.source);
|
|
194
|
+
await this._context.extendInjectedScript(rawRecorderSource.source, { recorderMode: this._recorderMode });
|
|
192
195
|
});
|
|
193
196
|
if (this._debugger.isPaused())
|
|
194
197
|
this._pausedStateChanged();
|
|
@@ -412,12 +415,14 @@ class Recorder extends import_events.default {
|
|
|
412
415
|
}
|
|
413
416
|
_describeMainFrame(page) {
|
|
414
417
|
return {
|
|
418
|
+
pageGuid: page.guid,
|
|
415
419
|
pageAlias: this._pageAliases.get(page),
|
|
416
420
|
framePath: []
|
|
417
421
|
};
|
|
418
422
|
}
|
|
419
423
|
async _describeFrame(frame) {
|
|
420
424
|
return {
|
|
425
|
+
pageGuid: frame._page.guid,
|
|
421
426
|
pageAlias: this._pageAliases.get(frame._page),
|
|
422
427
|
framePath: await (0, import_recorderUtils.generateFrameSelector)(frame)
|
|
423
428
|
};
|
|
@@ -121,9 +121,9 @@ function compareText(actual, expectedBuffer) {
|
|
|
121
121
|
const lines = import_utilsBundle2.diff.createPatch("file", expected, actual, void 0, void 0, { context: 5 }).split("\n");
|
|
122
122
|
const coloredLines = lines.slice(4).map((line) => {
|
|
123
123
|
if (line.startsWith("-"))
|
|
124
|
-
return import_utilsBundle2.colors.red(line);
|
|
125
|
-
if (line.startsWith("+"))
|
|
126
124
|
return import_utilsBundle2.colors.green(line);
|
|
125
|
+
if (line.startsWith("+"))
|
|
126
|
+
return import_utilsBundle2.colors.red(line);
|
|
127
127
|
if (line.startsWith("@@"))
|
|
128
128
|
return import_utilsBundle2.colors.dim(line);
|
|
129
129
|
return line;
|
|
@@ -39,7 +39,7 @@ var network = __toESM(require("../network"));
|
|
|
39
39
|
var import_wkConnection = require("./wkConnection");
|
|
40
40
|
var import_wkPage = require("./wkPage");
|
|
41
41
|
var import_errors = require("../errors");
|
|
42
|
-
const BROWSER_VERSION = "
|
|
42
|
+
const BROWSER_VERSION = "26.0";
|
|
43
43
|
const DEFAULT_USER_AGENT = `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/${BROWSER_VERSION} Safari/605.1.15`;
|
|
44
44
|
class WKBrowser extends import_browser.Browser {
|
|
45
45
|
constructor(parent, transport, options) {
|
|
@@ -93,6 +93,7 @@ const methodMetainfo = /* @__PURE__ */ new Map([
|
|
|
93
93
|
["BrowserContext.storageState", { title: "Get storage state" }],
|
|
94
94
|
["BrowserContext.pause", { title: "Pause" }],
|
|
95
95
|
["BrowserContext.enableRecorder", { internal: true }],
|
|
96
|
+
["BrowserContext.disableRecorder", { internal: true }],
|
|
96
97
|
["BrowserContext.newCDPSession", { internal: true }],
|
|
97
98
|
["BrowserContext.harStart", { internal: true }],
|
|
98
99
|
["BrowserContext.harExport", { internal: true }],
|