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.
Files changed (32) hide show
  1. package/browsers.json +6 -6
  2. package/lib/client/browserContext.js +19 -5
  3. package/lib/client/page.js +4 -4
  4. package/lib/generated/injectedScriptSource.js +1 -1
  5. package/lib/generated/pollingRecorderSource.js +1 -1
  6. package/lib/protocol/validator.js +8 -1
  7. package/lib/server/browserContext.js +2 -1
  8. package/lib/server/chromium/chromium.js +0 -2
  9. package/lib/server/codegen/csharp.js +1 -1
  10. package/lib/server/codegen/java.js +1 -1
  11. package/lib/server/codegen/javascript.js +1 -1
  12. package/lib/server/codegen/python.js +1 -1
  13. package/lib/server/debugController.js +2 -2
  14. package/lib/server/deviceDescriptorsSource.json +81 -81
  15. package/lib/server/dispatchers/browserContextDispatcher.js +14 -0
  16. package/lib/server/recorder/recorderApp.js +31 -2
  17. package/lib/server/recorder/recorderSignalProcessor.js +20 -8
  18. package/lib/server/recorder/recorderUtils.js +16 -5
  19. package/lib/server/recorder.js +16 -11
  20. package/lib/server/utils/comparators.js +2 -2
  21. package/lib/server/webkit/wkBrowser.js +1 -1
  22. package/lib/utils/isomorphic/protocolMetainfo.js +1 -0
  23. package/lib/vite/htmlReport/index.html +14 -18
  24. package/lib/vite/traceViewer/assets/{codeMirrorModule-B2cH4C1Z.js → codeMirrorModule-Djh-rPQr.js} +1 -1
  25. package/lib/vite/traceViewer/assets/defaultSettingsView-BsQs1KiL.js +256 -0
  26. package/lib/vite/traceViewer/{index.CPrh2bDb.js → index.LwN9z-Hp.js} +1 -1
  27. package/lib/vite/traceViewer/index.html +2 -2
  28. package/lib/vite/traceViewer/{uiMode.zJf6t5Og.js → uiMode.DyB42ep8.js} +1 -1
  29. package/lib/vite/traceViewer/uiMode.html +2 -2
  30. package/package.json +1 -1
  31. package/types/types.d.ts +0 -7
  32. 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[this._actions.length - 1];
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
- class RecorderSignalProcessor extends import_events.EventEmitter {
28
- constructor() {
29
- super(...arguments);
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, callback) {
32
+ addAction(actionInContext) {
33
33
  this._lastAction = actionInContext;
34
- this.emit("action", actionInContext);
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
- this.emit("signal", signal);
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 isSameAction = lastAction && lastAction.action.name === action.action.name && lastAction.frame.pageAlias === action.frame.pageAlias && lastAction.frame.framePath.join("|") === action.frame.framePath.join("|");
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
  });
@@ -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 ?? "perform";
82
+ this._recorderMode = params.recorderMode ?? "default";
83
83
  this.handleSIGINT = params.handleSIGINT;
84
- this._signalProcessor = new import_recorderSignalProcessor.RecorderSignalProcessor();
85
- this._signalProcessor.on("action", (actionInContext) => {
86
- if (this._enabled)
87
- this.emit(RecorderEvent.ActionAdded, actionInContext);
88
- });
89
- this._signalProcessor.on("signal", (signal) => {
90
- if (this._enabled)
91
- this.emit(RecorderEvent.SignalAdded, signal);
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 = "18.5";
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 }],