patchright-core 1.55.3 → 1.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/bin/install_webkit_wsl.ps1 +35 -0
  2. package/browsers.json +13 -13
  3. package/lib/browserServerImpl.js +3 -6
  4. package/lib/client/browser.js +0 -10
  5. package/lib/client/browserContext.js +2 -8
  6. package/lib/client/channelOwner.js +0 -7
  7. package/lib/client/consoleMessage.js +2 -3
  8. package/lib/client/electron.js +1 -1
  9. package/lib/client/events.js +1 -0
  10. package/lib/client/network.js +3 -0
  11. package/lib/client/page.js +13 -1
  12. package/lib/generated/bindingsControllerSource.js +1 -1
  13. package/lib/generated/injectedScriptSource.js +1 -1
  14. package/lib/generated/pollingRecorderSource.js +1 -1
  15. package/lib/generated/utilityScriptSource.js +1 -1
  16. package/lib/protocol/validator.js +26 -15
  17. package/lib/remote/playwrightServer.js +12 -14
  18. package/lib/server/bidi/bidiBrowser.js +54 -10
  19. package/lib/server/bidi/bidiChromium.js +1 -1
  20. package/lib/server/bidi/bidiConnection.js +31 -6
  21. package/lib/server/bidi/bidiExecutionContext.js +4 -4
  22. package/lib/server/bidi/bidiFirefox.js +16 -1
  23. package/lib/server/bidi/bidiNetworkManager.js +82 -16
  24. package/lib/server/bidi/bidiPage.js +84 -18
  25. package/lib/server/browserType.js +3 -3
  26. package/lib/server/chromium/chromium.js +1 -1
  27. package/lib/server/chromium/chromiumSwitches.js +3 -1
  28. package/lib/server/chromium/crBrowser.js +4 -34
  29. package/lib/server/chromium/crPage.js +22 -31
  30. package/lib/server/codegen/csharp.js +19 -26
  31. package/lib/server/codegen/java.js +4 -0
  32. package/lib/server/codegen/javascript.js +3 -1
  33. package/lib/server/codegen/python.js +2 -0
  34. package/lib/server/debugController.js +8 -36
  35. package/lib/server/deviceDescriptorsSource.json +62 -62
  36. package/lib/server/dispatchers/androidDispatcher.js +17 -0
  37. package/lib/server/dispatchers/browserContextDispatcher.js +1 -15
  38. package/lib/server/dispatchers/networkDispatchers.js +6 -3
  39. package/lib/server/dispatchers/pageDispatcher.js +24 -0
  40. package/lib/server/dom.js +8 -3
  41. package/lib/server/firefox/ffPage.js +1 -2
  42. package/lib/server/firefox/firefox.js +1 -1
  43. package/lib/server/frames.js +8 -3
  44. package/lib/server/har/harTracer.js +7 -8
  45. package/lib/server/network.js +12 -0
  46. package/lib/server/page.js +39 -17
  47. package/lib/server/recorder/chat.js +2 -2
  48. package/lib/server/recorder/recorderRunner.js +4 -0
  49. package/lib/server/registry/browserFetcher.js +3 -3
  50. package/lib/server/registry/index.js +27 -0
  51. package/lib/server/trace/recorder/snapshotter.js +13 -2
  52. package/lib/server/trace/recorder/snapshotterInjected.js +3 -1
  53. package/lib/server/utils/comparators.js +2 -2
  54. package/lib/server/utils/env.js +7 -2
  55. package/lib/server/utils/wsServer.js +2 -7
  56. package/lib/server/webkit/webkit.js +24 -8
  57. package/lib/server/webkit/wkBrowser.js +7 -3
  58. package/lib/server/webkit/wkPage.js +7 -8
  59. package/lib/server/webkit/wsl/webkit-wsl-transport-client.js +74 -0
  60. package/lib/server/webkit/wsl/webkit-wsl-transport-server.js +113 -0
  61. package/lib/utils/isomorphic/ariaSnapshot.js +12 -10
  62. package/lib/utils/isomorphic/protocolMetainfo.js +3 -0
  63. package/lib/utils/isomorphic/urlMatch.js +3 -8
  64. package/lib/utilsBundle.js +3 -0
  65. package/lib/utilsBundleImpl/index.js +80 -80
  66. package/lib/vite/htmlReport/index.html +37 -28
  67. package/lib/vite/recorder/assets/codeMirrorModule-RJCXzfmE.js +24 -0
  68. package/lib/vite/recorder/assets/index-Ri0uHF7I.css +1 -0
  69. package/lib/vite/recorder/assets/index-Y-X2TGJv.js +193 -0
  70. package/lib/vite/recorder/index.html +2 -2
  71. package/lib/vite/traceViewer/assets/codeMirrorModule-rbQPefq7.js +24 -0
  72. package/lib/vite/traceViewer/assets/defaultSettingsView-CLbol9XR.js +265 -0
  73. package/lib/vite/traceViewer/assets/xtermModule-CsJ4vdCR.js +9 -0
  74. package/lib/vite/traceViewer/defaultSettingsView.TQ8_7ybu.css +1 -0
  75. package/lib/vite/traceViewer/index.I8N9v4jT.css +1 -0
  76. package/lib/vite/traceViewer/index.html +4 -4
  77. package/lib/vite/traceViewer/index.zIVi6mN9.js +2 -0
  78. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  79. package/lib/vite/traceViewer/uiMode.B_CpmIpF.js +5 -0
  80. package/lib/vite/traceViewer/uiMode.Btcz36p_.css +1 -0
  81. package/lib/vite/traceViewer/uiMode.html +4 -4
  82. package/lib/vite/traceViewer/{xtermModule.Beg8tuEN.css → xtermModule.DYP7pi_n.css} +1 -1
  83. package/package.json +2 -4
  84. package/types/protocol.d.ts +7084 -6870
  85. package/types/types.d.ts +59 -53
  86. package/lib/vite/recorder/assets/codeMirrorModule-DzQ0k89p.js +0 -24
  87. package/lib/vite/recorder/assets/index-CI4HQ-Zb.css +0 -1
  88. package/lib/vite/recorder/assets/index-D7C7daHH.js +0 -184
  89. package/lib/vite/traceViewer/assets/codeMirrorModule-DsmF_DpA.js +0 -24
  90. package/lib/vite/traceViewer/assets/defaultSettingsView-Cd59AFK5.js +0 -256
  91. package/lib/vite/traceViewer/assets/xtermModule-BoAIEibi.js +0 -9
  92. package/lib/vite/traceViewer/defaultSettingsView.DVJHpiGt.css +0 -1
  93. package/lib/vite/traceViewer/index.BFsek2M6.css +0 -1
  94. package/lib/vite/traceViewer/index.BivEwfRr.js +0 -2
  95. package/lib/vite/traceViewer/uiMode.BDvz7Y9W.js +0 -5
  96. package/lib/vite/traceViewer/uiMode.BatfzHMG.css +0 -1
@@ -51,7 +51,6 @@ class CRBrowser extends import_browser.Browser {
51
51
  this._clientRootSessionPromise = null;
52
52
  this._contexts = /* @__PURE__ */ new Map();
53
53
  this._crPages = /* @__PURE__ */ new Map();
54
- this._backgroundPages = /* @__PURE__ */ new Map();
55
54
  this._serviceWorkers = /* @__PURE__ */ new Map();
56
55
  this._version = "";
57
56
  this._tracingRecording = false;
@@ -133,7 +132,7 @@ class CRBrowser extends import_browser.Browser {
133
132
  async _waitForAllPagesToBeInitialized() {
134
133
  await Promise.all([...this._crPages.values()].map((crPage) => crPage._page.waitForInitializedOrError()));
135
134
  }
136
- _onAttachedToTarget({ targetInfo, sessionId }) {
135
+ _onAttachedToTarget({ targetInfo, sessionId, waitingForDebugger }) {
137
136
  if (targetInfo.type === "browser")
138
137
  return;
139
138
  const session = this._session.createChildSession(sessionId);
@@ -153,16 +152,10 @@ class CRBrowser extends import_browser.Browser {
153
152
  return;
154
153
  }
155
154
  (0, import_assert.assert)(!this._crPages.has(targetInfo.targetId), "Duplicate target " + targetInfo.targetId);
156
- (0, import_assert.assert)(!this._backgroundPages.has(targetInfo.targetId), "Duplicate target " + targetInfo.targetId);
157
155
  (0, import_assert.assert)(!this._serviceWorkers.has(targetInfo.targetId), "Duplicate target " + targetInfo.targetId);
158
- if (targetInfo.type === "background_page") {
159
- const backgroundPage = new import_crPage.CRPage(session, targetInfo.targetId, context, null, { hasUIWindow: false, isBackgroundPage: true });
160
- this._backgroundPages.set(targetInfo.targetId, backgroundPage);
161
- return;
162
- }
163
156
  if (targetInfo.type === "page" || treatOtherAsPage) {
164
157
  const opener = targetInfo.openerId ? this._crPages.get(targetInfo.openerId) || null : null;
165
- const crPage = new import_crPage.CRPage(session, targetInfo.targetId, context, opener, { hasUIWindow: targetInfo.type === "page", isBackgroundPage: false });
158
+ const crPage = new import_crPage.CRPage(session, targetInfo.targetId, context, opener, { hasUIWindow: targetInfo.type === "page" });
166
159
  this._crPages.set(targetInfo.targetId, crPage);
167
160
  return;
168
161
  }
@@ -183,12 +176,6 @@ class CRBrowser extends import_browser.Browser {
183
176
  crPage.didClose();
184
177
  return;
185
178
  }
186
- const backgroundPage = this._backgroundPages.get(targetId);
187
- if (backgroundPage) {
188
- this._backgroundPages.delete(targetId);
189
- backgroundPage.didClose();
190
- return;
191
- }
192
179
  const serviceWorker = this._serviceWorkers.get(targetId);
193
180
  if (serviceWorker) {
194
181
  this._serviceWorkers.delete(targetId);
@@ -200,9 +187,6 @@ class CRBrowser extends import_browser.Browser {
200
187
  for (const crPage of this._crPages.values())
201
188
  crPage.didClose();
202
189
  this._crPages.clear();
203
- for (const backgroundPage of this._backgroundPages.values())
204
- backgroundPage.didClose();
205
- this._backgroundPages.clear();
206
190
  for (const serviceWorker of this._serviceWorkers.values())
207
191
  serviceWorker.didClose();
208
192
  this._serviceWorkers.clear();
@@ -295,7 +279,6 @@ class CRBrowser extends import_browser.Browser {
295
279
  class CRBrowserContext extends import_browserContext.BrowserContext {
296
280
  static {
297
281
  this.CREvents = {
298
- BackgroundPage: "backgroundpage",
299
282
  ServiceWorker: "serviceworker"
300
283
  };
301
284
  }
@@ -396,7 +379,8 @@ class CRBrowserContext extends import_browserContext.BrowserContext {
396
379
  // chrome-specific permissions we have.
397
380
  ["midi-sysex", "midiSysex"],
398
381
  ["storage-access", "storageAccess"],
399
- ["local-fonts", "localFonts"]
382
+ ["local-fonts", "localFonts"],
383
+ ["local-network-access", "localNetworkAccess"]
400
384
  ]);
401
385
  const filtered = permissions.map((permission) => {
402
386
  const protocolPermission = webPermissionToProtocol.get(permission);
@@ -480,12 +464,6 @@ class CRBrowserContext extends import_browserContext.BrowserContext {
480
464
  await Promise.all(this._crPages().map((crPage) => crPage._mainFrameSession._stopVideoRecording()));
481
465
  }
482
466
  onClosePersistent() {
483
- for (const [targetId, backgroundPage] of this._browser._backgroundPages.entries()) {
484
- if (backgroundPage._browserContext === this && backgroundPage._page.initializedOrUndefined()) {
485
- backgroundPage.didClose();
486
- this._browser._backgroundPages.delete(targetId);
487
- }
488
- }
489
467
  }
490
468
  async clearCache() {
491
469
  for (const page of this._crPages())
@@ -497,14 +475,6 @@ class CRBrowserContext extends import_browserContext.BrowserContext {
497
475
  browserContextId: this._browserContextId
498
476
  });
499
477
  }
500
- backgroundPages() {
501
- const result = [];
502
- for (const backgroundPage of this._browser._backgroundPages.values()) {
503
- if (backgroundPage._browserContext === this && backgroundPage._page.initializedOrUndefined())
504
- result.push(backgroundPage._page);
505
- }
506
- return result;
507
- }
508
478
  serviceWorkers() {
509
479
  return Array.from(this._browser._serviceWorkers.values()).filter((serviceWorker) => serviceWorker.browserContext === this);
510
480
  }
@@ -45,7 +45,6 @@ var network = __toESM(require("../network"));
45
45
  var import_page = require("../page");
46
46
  var import_registry = require("../registry");
47
47
  var import_crAccessibility = require("./crAccessibility");
48
- var import_crBrowser = require("./crBrowser");
49
48
  var import_crCoverage = require("./crCoverage");
50
49
  var import_crDragDrop = require("./crDragDrop");
51
50
  var import_crExecutionContext = require("./crExecutionContext");
@@ -55,7 +54,6 @@ var import_crPdf = require("./crPdf");
55
54
  var import_crProtocolHelper = require("./crProtocolHelper");
56
55
  var import_defaultFontFamilies = require("./defaultFontFamilies");
57
56
  var import_videoRecorder = require("./videoRecorder");
58
- var import_browserContext = require("../browserContext");
59
57
  var import_errors = require("../errors");
60
58
  var import_protocolError = require("../protocolError");
61
59
  class CRPage {
@@ -69,7 +67,6 @@ class CRPage {
69
67
  this._nextWindowOpenPopupFeatures = [];
70
68
  this._targetId = targetId;
71
69
  this._opener = opener;
72
- this._isBackgroundPage = bits.isBackgroundPage;
73
70
  const dragManager = new import_crDragDrop.DragManager(this);
74
71
  this.rawKeyboard = new import_crInput.RawKeyboardImpl(client, browserContext._browser._platform() === "mac", dragManager);
75
72
  this.rawMouse = new import_crInput.RawMouseImpl(this, client, dragManager);
@@ -93,10 +90,9 @@ class CRPage {
93
90
  if (viewportSize)
94
91
  this._page.setEmulatedSizeFromWindowOpen({ viewport: viewportSize, screen: viewportSize });
95
92
  }
96
- const createdEvent = this._isBackgroundPage ? import_crBrowser.CRBrowserContext.CREvents.BackgroundPage : import_browserContext.BrowserContext.Events.Page;
97
93
  this._mainFrameSession._initialize(bits.hasUIWindow).then(
98
- () => this._page.reportAsNew(this._opener?._page, void 0, createdEvent),
99
- (error) => this._page.reportAsNew(this._opener?._page, error, createdEvent)
94
+ () => this._page.reportAsNew(this._opener?._page, void 0),
95
+ (error) => this._page.reportAsNew(this._opener?._page, error)
100
96
  );
101
97
  }
102
98
  static mainFrameSession(page) {
@@ -371,13 +367,13 @@ class FrameSession {
371
367
  import_eventsHelper.eventsHelper.addEventListener(this._client, "Runtime.exceptionThrown", (exception) => this._handleException(exception.exceptionDetails)),
372
368
  import_eventsHelper.eventsHelper.addEventListener(this._client, "Runtime.executionContextCreated", (event) => this._onExecutionContextCreated(event.context)),
373
369
  import_eventsHelper.eventsHelper.addEventListener(this._client, "Runtime.executionContextDestroyed", (event) => this._onExecutionContextDestroyed(event.executionContextId)),
374
- import_eventsHelper.eventsHelper.addEventListener(this._client, "Runtime.executionContextsCleared", (event) => this._onExecutionContextsCleared()),
375
- import_eventsHelper.eventsHelper.addEventListener(this._client, "Target.attachedToTarget", (event) => this._onAttachedToTarget(event)),
376
- import_eventsHelper.eventsHelper.addEventListener(this._client, "Target.detachedFromTarget", (event) => this._onDetachedFromTarget(event))
370
+ import_eventsHelper.eventsHelper.addEventListener(this._client, "Runtime.executionContextsCleared", (event) => this._onExecutionContextsCleared())
377
371
  ]);
378
372
  }
379
373
  _addBrowserListeners() {
380
374
  this._eventListeners.push(...[
375
+ import_eventsHelper.eventsHelper.addEventListener(this._client, "Target.attachedToTarget", (event) => this._onAttachedToTarget(event)),
376
+ import_eventsHelper.eventsHelper.addEventListener(this._client, "Target.detachedFromTarget", (event) => this._onDetachedFromTarget(event)),
381
377
  import_eventsHelper.eventsHelper.addEventListener(this._client, "Inspector.targetCrashed", (event) => this._onTargetCrashed()),
382
378
  import_eventsHelper.eventsHelper.addEventListener(this._client, "Page.screencastFrame", (event) => this._onScreencastFrame(event)),
383
379
  import_eventsHelper.eventsHelper.addEventListener(this._client, "Page.windowOpen", (event) => this._onWindowOpen(event))
@@ -409,6 +405,7 @@ class FrameSession {
409
405
  if (!this._isMainFrame())
410
406
  this._addRendererListeners();
411
407
  this._addBrowserListeners();
408
+ this._bufferedAttachedToTargetEvents = [];
412
409
  const promises = [
413
410
  this._client.send("Page.enable"),
414
411
  this._client.send("Page.getFrameTree").then(({ frameTree }) => {
@@ -416,6 +413,10 @@ class FrameSession {
416
413
  this._handleFrameTree(frameTree);
417
414
  this._addRendererListeners();
418
415
  }
416
+ const attachedToTargetEvents = this._bufferedAttachedToTargetEvents || [];
417
+ this._bufferedAttachedToTargetEvents = void 0;
418
+ for (const event of attachedToTargetEvents)
419
+ this._onAttachedToTarget(event);
419
420
  const isInitialEmptyPage = this._isMainFrame() && this._page.mainFrame().url() === ":";
420
421
  if (isInitialEmptyPage) {
421
422
  lifecycleEventsEnabled.catch((e) => {
@@ -444,16 +445,7 @@ class FrameSession {
444
445
  worldName: this._crPage.utilityWorldName
445
446
  }),
446
447
  this._crPage._networkManager.addSession(this._client, void 0, this._isMainFrame()),
447
- this._client.send("Target.setAutoAttach", {
448
- autoAttach: true,
449
- waitForDebuggerOnStart: true,
450
- flatten: true,
451
- filter: [
452
- { type: "iframe" },
453
- { type: "worker" },
454
- { type: "service_worker", exclude: !process.env.PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS }
455
- ]
456
- })
448
+ this._client.send("Target.setAutoAttach", { autoAttach: true, waitForDebuggerOnStart: true, flatten: true })
457
449
  ];
458
450
  if (!this._page.isStorageStatePage) {
459
451
  if (this._crPage._browserContext.needsPlaywrightBinding())
@@ -644,10 +636,17 @@ class FrameSession {
644
636
  this._onExecutionContextDestroyed(contextId);
645
637
  }
646
638
  async _onAttachedToTarget(event) {
639
+ if (this._bufferedAttachedToTargetEvents) {
640
+ this._bufferedAttachedToTargetEvents.push(event);
641
+ return;
642
+ }
647
643
  const session = this._client.createChildSession(event.sessionId);
648
644
  if (event.targetInfo.type === "iframe") {
649
645
  const targetId = event.targetInfo.targetId;
650
- const frame = this._page.frameManager.frame(targetId);
646
+ let frame = this._page.frameManager.frame(targetId);
647
+ if (!frame && event.targetInfo.parentFrameId) {
648
+ frame = this._page.frameManager.frameAttached(targetId, event.targetInfo.parentFrameId);
649
+ }
651
650
  if (!frame)
652
651
  return;
653
652
  this._page.frameManager.removeChildFramesRecursively(frame);
@@ -684,22 +683,14 @@ class FrameSession {
684
683
  this._crPage._networkManager.addSession(session, this._page.frameManager.frame(this._targetId) ?? void 0).catch(() => {
685
684
  });
686
685
  session._sendMayFail("Runtime.runIfWaitingForDebugger");
687
- session._sendMayFail("Target.setAutoAttach", {
688
- autoAttach: true,
689
- waitForDebuggerOnStart: true,
690
- flatten: true,
691
- filter: [
692
- { type: "worker" },
693
- { type: "service_worker", exclude: !process.env.PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS }
694
- ]
695
- });
686
+ session._sendMayFail("Target.setAutoAttach", { autoAttach: true, waitForDebuggerOnStart: true, flatten: true });
696
687
  session.on("Target.attachedToTarget", (event2) => this._onAttachedToTarget(event2));
697
688
  session.on("Target.detachedFromTarget", (event2) => this._onDetachedFromTarget(event2));
698
689
  session.on("Runtime.consoleAPICalled", (event2) => {
699
690
  const args = event2.args.map((o) => (0, import_crExecutionContext.createHandle)(worker.existingExecutionContext, o));
700
691
  this._page.addConsoleMessage(event2.type, args, (0, import_crProtocolHelper.toConsoleMessageLocation)(event2.stackTrace));
701
692
  });
702
- session.on("Runtime.exceptionThrown", (exception) => this._page.emitOnContextOnceInitialized(import_browserContext.BrowserContext.Events.PageError, (0, import_crProtocolHelper.exceptionToError)(exception.exceptionDetails), this._page));
693
+ session.on("Runtime.exceptionThrown", (exception) => this._page.addPageError((0, import_crProtocolHelper.exceptionToError)(exception.exceptionDetails)));
703
694
  }
704
695
  _onDetachedFromTarget(event) {
705
696
  const workerSession = this._workerSessions.get(event.sessionId);
@@ -758,7 +749,7 @@ class FrameSession {
758
749
  ));
759
750
  }
760
751
  _handleException(exceptionDetails) {
761
- this._page.emitOnContextOnceInitialized(import_browserContext.BrowserContext.Events.PageError, (0, import_crProtocolHelper.exceptionToError)(exceptionDetails), this._page);
752
+ this._page.addPageError((0, import_crProtocolHelper.exceptionToError)(exceptionDetails));
762
753
  }
763
754
  async _onTargetCrashed() {
764
755
  this._client._markAsCrashed();
@@ -109,9 +109,13 @@ class CSharpLanguageGenerator {
109
109
  const options = (0, import_language.toClickOptionsForSourceCode)(action);
110
110
  if (!Object.entries(options).length)
111
111
  return `await ${subject}.${this._asLocator(action.selector)}.${method}Async();`;
112
- const optionsString = formatObject(options, " ", "Locator" + method + "Options");
112
+ const optionsString = formatObject(options, " ");
113
113
  return `await ${subject}.${this._asLocator(action.selector)}.${method}Async(${optionsString});`;
114
114
  }
115
+ case "hover": {
116
+ const optionsString = action.position ? formatObject({ position: action.position }, " ") : "";
117
+ return `await ${subject}.${this._asLocator(action.selector)}.HoverAsync(${optionsString});`;
118
+ }
115
119
  case "check":
116
120
  return `await ${subject}.${this._asLocator(action.selector)}.CheckAsync();`;
117
121
  case "uncheck":
@@ -159,11 +163,11 @@ class CSharpLanguageGenerator {
159
163
  using System.Threading.Tasks;
160
164
 
161
165
  using var playwright = await Playwright.CreateAsync();
162
- await using var browser = await playwright.${toPascal(options.browserName)}.LaunchAsync(${formatObject(options.launchOptions, " ", "BrowserTypeLaunchOptions")});
166
+ await using var browser = await playwright.${toPascal(options.browserName)}.LaunchAsync(${formatObject(options.launchOptions, " ")});
163
167
  var context = await browser.NewContextAsync(${formatContextOptions(options.contextOptions, options.deviceName)});`);
164
168
  if (options.contextOptions.recordHar) {
165
169
  const url = options.contextOptions.recordHar.urlFilter;
166
- formatter.add(` await context.RouteFromHARAsync(${quote(options.contextOptions.recordHar.path)}${url ? `, ${formatObject({ url }, " ", "BrowserContextRouteFromHAROptions")}` : ""});`);
170
+ formatter.add(` await context.RouteFromHARAsync(${quote(options.contextOptions.recordHar.path)}${url ? `, ${formatObject({ url }, " ")}` : ""});`);
167
171
  }
168
172
  formatter.newLine();
169
173
  return formatter.format();
@@ -191,14 +195,14 @@ class CSharpLanguageGenerator {
191
195
  {`);
192
196
  if (options.contextOptions.recordHar) {
193
197
  const url = options.contextOptions.recordHar.urlFilter;
194
- formatter.add(` await Context.RouteFromHARAsync(${quote(options.contextOptions.recordHar.path)}${url ? `, ${formatObject({ url }, " ", "BrowserContextRouteFromHAROptions")}` : ""});`);
198
+ formatter.add(` await Context.RouteFromHARAsync(${quote(options.contextOptions.recordHar.path)}${url ? `, ${formatObject({ url }, " ")}` : ""});`);
195
199
  }
196
200
  return formatter.format();
197
201
  }
198
202
  generateFooter(saveStorage) {
199
203
  const offset = this._mode === "library" ? "" : " ";
200
204
  let storageStateLine = saveStorage ? `
201
- ${offset}await context.StorageStateAsync(new BrowserContextStorageStateOptions
205
+ ${offset}await context.StorageStateAsync(new()
202
206
  ${offset}{
203
207
  ${offset} Path = ${quote(saveStorage)}
204
208
  ${offset}});
@@ -212,8 +216,8 @@ ${offset}});
212
216
  }
213
217
  function formatObject(value, indent = " ", name = "") {
214
218
  if (typeof value === "string") {
215
- if (["permissions", "colorScheme", "modifiers", "button", "recordHarContent", "recordHarMode", "serviceWorkers"].includes(name))
216
- return `${getClassName(name)}.${toPascal(value)}`;
219
+ if (["colorScheme", "modifiers", "button", "recordHarContent", "recordHarMode", "serviceWorkers"].includes(name))
220
+ return `${getEnumName(name)}.${toPascal(value)}`;
217
221
  return quote(value);
218
222
  }
219
223
  if (Array.isArray(value))
@@ -221,35 +225,24 @@ function formatObject(value, indent = " ", name = "") {
221
225
  if (typeof value === "object") {
222
226
  const keys = Object.keys(value).filter((key) => value[key] !== void 0).sort();
223
227
  if (!keys.length)
224
- return name ? `new ${getClassName(name)}` : "";
228
+ return `new()`;
225
229
  const tokens = [];
226
230
  for (const key of keys) {
227
231
  const property = getPropertyName(key);
228
232
  tokens.push(`${property} = ${formatObject(value[key], indent, key)},`);
229
233
  }
230
- if (name)
231
- return `new ${getClassName(name)}
234
+ return `new()
232
235
  {
233
236
  ${indent}${tokens.join(`
234
237
  ${indent}`)}
235
- ${indent}}`;
236
- return `{
237
- ${indent}${tokens.join(`
238
- ${indent}`)}
239
238
  ${indent}}`;
240
239
  }
241
240
  if (name === "latitude" || name === "longitude")
242
241
  return String(value) + "m";
243
242
  return String(value);
244
243
  }
245
- function getClassName(value) {
244
+ function getEnumName(value) {
246
245
  switch (value) {
247
- case "viewport":
248
- return "ViewportSize";
249
- case "proxy":
250
- return "ProxySettings";
251
- case "permissions":
252
- return "ContextPermission";
253
246
  case "modifiers":
254
247
  return "KeyboardModifier";
255
248
  case "button":
@@ -278,18 +271,18 @@ function toPascal(value) {
278
271
  return value[0].toUpperCase() + value.slice(1);
279
272
  }
280
273
  function formatContextOptions(contextOptions, deviceName) {
281
- let options = { ...contextOptions };
274
+ const options = { ...contextOptions };
282
275
  delete options.recordHar;
283
276
  const device = deviceName && import_deviceDescriptors.deviceDescriptors[deviceName];
284
277
  if (!device) {
285
278
  if (!Object.entries(options).length)
286
279
  return "";
287
- return formatObject(options, " ", "BrowserNewContextOptions");
280
+ return formatObject(options, " ");
288
281
  }
289
- options = (0, import_language.sanitizeDeviceOptions)(device, options);
290
- if (!Object.entries(options).length)
282
+ if (!Object.entries((0, import_language.sanitizeDeviceOptions)(device, options)).length)
291
283
  return `playwright.Devices[${quote(deviceName)}]`;
292
- return formatObject(options, " ", `BrowserNewContextOptions(playwright.Devices[${quote(deviceName)}])`);
284
+ delete options["defaultBrowserType"];
285
+ return formatObject(options, " ");
293
286
  }
294
287
  class CSharpFormatter {
295
288
  constructor(offset = 0) {
@@ -91,6 +91,10 @@ class JavaLanguageGenerator {
91
91
  const optionsText = formatClickOptions(options);
92
92
  return `${subject}.${this._asLocator(action.selector, inFrameLocator)}.${method}(${optionsText});`;
93
93
  }
94
+ case "hover": {
95
+ const optionsText = action.position ? `new Locator.HoverOptions().setPosition(${action.position.x}, ${action.position.y})` : "";
96
+ return `${subject}.${this._asLocator(action.selector, inFrameLocator)}.hover(${optionsText});`;
97
+ }
94
98
  case "check":
95
99
  return `${subject}.${this._asLocator(action.selector, inFrameLocator)}.check();`;
96
100
  case "uncheck":
@@ -81,6 +81,8 @@ class JavaScriptLanguageGenerator {
81
81
  const optionsString = formatOptions(options, false);
82
82
  return `await ${subject}.${this._asLocator(action.selector)}.${method}(${optionsString});`;
83
83
  }
84
+ case "hover":
85
+ return `await ${subject}.${this._asLocator(action.selector)}.hover(${formatOptions({ position: action.position }, false)});`;
84
86
  case "check":
85
87
  return `await ${subject}.${this._asLocator(action.selector)}.check();`;
86
88
  case "uncheck":
@@ -166,7 +168,7 @@ ${useText ? "\ntest.use(" + useText + ");\n" : ""}
166
168
  }
167
169
  }
168
170
  function formatOptions(value, hasArguments) {
169
- const keys = Object.keys(value);
171
+ const keys = Object.keys(value).filter((key) => value[key] !== void 0);
170
172
  if (!keys.length)
171
173
  return "";
172
174
  return (hasArguments ? ", " : "") + formatObject(value);
@@ -83,6 +83,8 @@ class PythonLanguageGenerator {
83
83
  const optionsString = formatOptions(options, false);
84
84
  return `${subject}.${this._asLocator(action.selector)}.${method}(${optionsString})`;
85
85
  }
86
+ case "hover":
87
+ return `${subject}.${this._asLocator(action.selector)}.hover(${formatOptions({ position: action.position }, false)})`;
86
88
  case "check":
87
89
  return `${subject}.${this._asLocator(action.selector)}.check()`;
88
90
  case "uncheck":
@@ -31,13 +31,9 @@ var import_locatorParser = require("../utils/isomorphic/locatorParser");
31
31
  var import_language = require("./codegen/language");
32
32
  var import_recorderUtils = require("./recorder/recorderUtils");
33
33
  var import_javascript = require("./codegen/javascript");
34
- var import_frames = require("./frames");
35
- var import_page = require("./page");
36
34
  class DebugController extends import_instrumentation.SdkObject {
37
35
  constructor(playwright) {
38
36
  super({ attribution: { isInternalPlaywright: true }, instrumentation: (0, import_instrumentation.createInstrumentation)() }, void 0, "DebugController");
39
- this._reportState = false;
40
- this._disposeListeners = /* @__PURE__ */ new Set();
41
37
  this._sdkLanguage = "javascript";
42
38
  this._generateAutoExpect = false;
43
39
  this._playwright = playwright;
@@ -58,28 +54,16 @@ class DebugController extends import_instrumentation.SdkObject {
58
54
  this.setReportStateChanged(false);
59
55
  }
60
56
  setReportStateChanged(enabled) {
61
- if (this._reportState === enabled)
62
- return;
63
- this._reportState = enabled;
64
- if (enabled) {
65
- const listener = {
66
- onPageOpen: (page) => {
67
- this._emitSnapshot(false);
68
- const handleNavigation = () => this._emitSnapshot(false);
69
- page.mainFrame().on(import_frames.Frame.Events.InternalNavigation, handleNavigation);
70
- const dispose = () => page.mainFrame().off(import_frames.Frame.Events.InternalNavigation, handleNavigation);
71
- this._disposeListeners.add(dispose);
72
- page.on(import_page.Page.Events.Close, () => this._disposeListeners.delete(dispose));
73
- },
57
+ if (enabled && !this._trackHierarchyListener) {
58
+ this._trackHierarchyListener = {
59
+ onPageOpen: () => this._emitSnapshot(false),
74
60
  onPageClose: () => this._emitSnapshot(false)
75
61
  };
76
- this._playwright.instrumentation.addListener(listener, null);
77
- this._disposeListeners.add(() => this._playwright.instrumentation.removeListener(listener));
62
+ this._playwright.instrumentation.addListener(this._trackHierarchyListener, null);
78
63
  this._emitSnapshot(true);
79
- } else {
80
- for (const dispose of this._disposeListeners)
81
- dispose();
82
- this._disposeListeners.clear();
64
+ } else if (!enabled && this._trackHierarchyListener) {
65
+ this._playwright.instrumentation.removeListener(this._trackHierarchyListener);
66
+ this._trackHierarchyListener = void 0;
83
67
  }
84
68
  }
85
69
  async setRecorderMode(progress, params) {
@@ -137,19 +121,7 @@ class DebugController extends import_instrumentation.SdkObject {
137
121
  const pageCount = this._playwright.allPages().length;
138
122
  if (initial && !pageCount)
139
123
  return;
140
- this.emit(DebugController.Events.StateChanged, {
141
- pageCount,
142
- browsers: this._playwright.allBrowsers().map((browser) => ({
143
- id: browser.guid,
144
- name: browser.options.name,
145
- channel: browser.options.channel,
146
- contexts: browser.contexts().map((context) => ({
147
- pages: context.pages().map((page) => ({
148
- url: page.mainFrame().url()
149
- }))
150
- }))
151
- }))
152
- });
124
+ this.emit(DebugController.Events.StateChanged, { pageCount });
153
125
  }
154
126
  async _allRecorders() {
155
127
  const contexts = /* @__PURE__ */ new Set();