rebrowser-playwright-core 1.47.100 → 1.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +1 -1
  2. package/ThirdPartyNotices.txt +70 -384
  3. package/bin/reinstall_chrome_beta_linux.sh +10 -8
  4. package/bin/reinstall_chrome_stable_linux.sh +10 -8
  5. package/bin/reinstall_msedge_beta_linux.sh +11 -9
  6. package/bin/reinstall_msedge_dev_linux.sh +11 -9
  7. package/bin/reinstall_msedge_stable_linux.sh +11 -9
  8. package/browsers.json +24 -12
  9. package/lib/cli/program.js +49 -19
  10. package/lib/client/api.js +6 -0
  11. package/lib/client/browserContext.js +20 -2
  12. package/lib/client/channelOwner.js +6 -2
  13. package/lib/client/connection.js +3 -0
  14. package/lib/client/fetch.js +16 -21
  15. package/lib/client/jsHandle.js +0 -8
  16. package/lib/client/localUtils.js +1 -0
  17. package/lib/client/locator.js +7 -0
  18. package/lib/client/network.js +180 -17
  19. package/lib/client/page.js +25 -2
  20. package/lib/client/playwright.js +6 -3
  21. package/lib/client/tracing.js +29 -20
  22. package/lib/client/waiter.js +15 -11
  23. package/lib/generated/consoleApiSource.js +1 -1
  24. package/lib/generated/injectedScriptSource.js +1 -1
  25. package/lib/generated/pollingRecorderSource.js +7 -0
  26. package/lib/generated/webSocketMockSource.js +7 -0
  27. package/lib/protocol/validator.js +103 -17
  28. package/lib/server/ariaSnapshot.js +33 -0
  29. package/lib/server/bidi/bidiBrowser.js +23 -8
  30. package/lib/server/bidi/bidiChromium.js +124 -0
  31. package/lib/server/bidi/bidiConnection.js +1 -3
  32. package/lib/server/bidi/bidiExecutionContext.js +0 -6
  33. package/lib/server/bidi/bidiFirefox.js +15 -21
  34. package/lib/server/bidi/bidiInput.js +16 -32
  35. package/lib/server/bidi/bidiNetworkManager.js +39 -5
  36. package/lib/server/bidi/bidiOverCdp.js +103 -0
  37. package/lib/server/bidi/bidiPage.js +98 -25
  38. package/lib/server/bidi/bidiPdf.js +140 -0
  39. package/lib/server/bidi/third_party/firefoxPrefs.js +221 -0
  40. package/lib/server/browser.js +13 -2
  41. package/lib/server/browserContext.js +6 -23
  42. package/lib/server/browserType.js +43 -12
  43. package/lib/server/chromium/chromium.js +9 -17
  44. package/lib/server/chromium/chromiumSwitches.js +3 -1
  45. package/lib/server/chromium/crBrowser.js +4 -3
  46. package/lib/server/chromium/crConnection.js +153 -0
  47. package/lib/server/chromium/crExecutionContext.js +0 -20
  48. package/lib/server/chromium/crPage.js +13 -7
  49. package/lib/server/chromium/videoRecorder.js +1 -1
  50. package/lib/server/codegen/csharp.js +12 -17
  51. package/lib/server/codegen/java.js +5 -8
  52. package/lib/server/codegen/javascript.js +29 -7
  53. package/lib/server/codegen/language.js +14 -2
  54. package/lib/server/codegen/python.js +13 -17
  55. package/lib/server/cookieStore.js +73 -0
  56. package/lib/server/debugController.js +10 -7
  57. package/lib/server/deviceDescriptorsSource.json +127 -127
  58. package/lib/server/dialog.js +1 -0
  59. package/lib/server/dispatchers/androidDispatcher.js +13 -2
  60. package/lib/server/dispatchers/browserContextDispatcher.js +19 -2
  61. package/lib/server/dispatchers/debugControllerDispatcher.js +1 -1
  62. package/lib/server/dispatchers/dispatcher.js +1 -1
  63. package/lib/server/dispatchers/frameDispatcher.js +8 -1
  64. package/lib/server/dispatchers/jsHandleDispatcher.js +0 -5
  65. package/lib/server/dispatchers/pageDispatcher.js +9 -0
  66. package/lib/server/dispatchers/playwrightDispatcher.js +2 -1
  67. package/lib/server/dispatchers/tracingDispatcher.js +10 -0
  68. package/lib/server/dispatchers/webSocketRouteDispatcher.js +189 -0
  69. package/lib/server/dom.js +79 -36
  70. package/lib/server/download.js +9 -2
  71. package/lib/server/fetch.js +105 -96
  72. package/lib/server/firefox/ffBrowser.js +6 -4
  73. package/lib/server/firefox/ffExecutionContext.js +0 -15
  74. package/lib/server/firefox/ffNetworkManager.js +1 -1
  75. package/lib/server/firefox/ffPage.js +6 -3
  76. package/lib/server/firefox/firefox.js +2 -13
  77. package/lib/server/frameSelectors.js +1 -1
  78. package/lib/server/frames.js +68 -67
  79. package/lib/server/har/harTracer.js +11 -0
  80. package/lib/server/index.js +0 -6
  81. package/lib/server/input.js +0 -1
  82. package/lib/server/javascript.js +0 -13
  83. package/lib/server/page.js +53 -9
  84. package/lib/server/playwright.js +5 -2
  85. package/lib/server/progress.js +0 -3
  86. package/lib/server/recorder/contextRecorder.js +33 -50
  87. package/lib/server/recorder/recorderApp.js +22 -25
  88. package/lib/server/recorder/recorderCollection.js +68 -79
  89. package/lib/server/recorder/recorderInTraceViewer.js +144 -0
  90. package/lib/server/recorder/recorderRunner.js +75 -97
  91. package/lib/server/recorder/recorderUtils.js +48 -6
  92. package/lib/server/recorder.js +87 -47
  93. package/lib/server/registry/index.js +154 -26
  94. package/lib/server/registry/nativeDeps.js +6 -3
  95. package/lib/server/socksClientCertificatesInterceptor.js +15 -3
  96. package/lib/server/trace/recorder/snapshotter.js +2 -12
  97. package/lib/server/trace/recorder/snapshotterInjected.js +21 -3
  98. package/lib/server/trace/recorder/tracing.js +127 -17
  99. package/lib/server/trace/test/inMemorySnapshotter.js +4 -4
  100. package/lib/server/trace/viewer/traceViewer.js +4 -6
  101. package/lib/server/webkit/webkit.js +1 -1
  102. package/lib/server/webkit/wkBrowser.js +8 -7
  103. package/lib/server/webkit/wkExecutionContext.js +0 -16
  104. package/lib/server/webkit/wkPage.js +11 -4
  105. package/lib/utils/comparators.js +12 -30
  106. package/lib/utils/crypto.js +1 -4
  107. package/lib/utils/happy-eyeballs.js +13 -0
  108. package/lib/utils/hostPlatform.js +8 -2
  109. package/lib/utils/httpServer.js +1 -0
  110. package/lib/utils/isomorphic/ariaSnapshot.js +267 -0
  111. package/lib/utils/isomorphic/locatorGenerators.js +30 -21
  112. package/lib/utils/isomorphic/locatorParser.js +2 -2
  113. package/lib/utils/isomorphic/recorderUtils.js +227 -0
  114. package/lib/utils/isomorphic/stringUtils.js +30 -0
  115. package/lib/utils/isomorphic/urlMatch.js +5 -1
  116. package/lib/utils/network.js +1 -1
  117. package/lib/utils/sequence.js +64 -0
  118. package/lib/utils/stackTrace.js +16 -3
  119. package/lib/utils/zones.js +32 -23
  120. package/lib/utilsBundle.js +4 -5
  121. package/lib/utilsBundleImpl/index.js +190 -33
  122. package/lib/vite/htmlReport/index.html +19 -16
  123. package/lib/vite/recorder/assets/codeMirrorModule-AFvV6hAs.js +24 -0
  124. package/lib/vite/recorder/assets/index-_cTWgVuJ.js +184 -0
  125. package/lib/vite/recorder/assets/{index-B-MT5gKo.css → index-iA1aAGZg.css} +1 -1
  126. package/lib/vite/recorder/index.html +2 -2
  127. package/lib/vite/traceViewer/assets/codeMirrorModule-KatbITLF.js +24 -0
  128. package/lib/vite/traceViewer/assets/inspectorTab-DdpLd2bb.js +68 -0
  129. package/lib/vite/traceViewer/assets/workbench-CdYbzWFD.js +9 -0
  130. package/lib/vite/traceViewer/embedded.6m3UZh7r.js +2 -0
  131. package/lib/vite/traceViewer/embedded.html +5 -3
  132. package/lib/vite/traceViewer/index.WUV-8boJ.js +2 -0
  133. package/lib/vite/traceViewer/index.html +24 -5
  134. package/lib/vite/traceViewer/inspectorTab.DEOUW62d.css +1 -0
  135. package/lib/vite/traceViewer/recorder.B_SY1GJM.css +0 -0
  136. package/lib/vite/traceViewer/recorder.OT2tVHgn.js +2 -0
  137. package/lib/vite/traceViewer/recorder.html +17 -0
  138. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  139. package/lib/vite/traceViewer/uiMode.BZBTyvGn.js +5 -0
  140. package/lib/vite/traceViewer/uiMode.html +6 -4
  141. package/lib/vite/traceViewer/{uiMode.D3cNFP6u.css → uiMode.voC1ZiOQ.css} +1 -1
  142. package/lib/vite/traceViewer/workbench.C-zR9ysA.css +1 -0
  143. package/package.json +1 -1
  144. package/types/protocol.d.ts +135 -16
  145. package/types/types.d.ts +2149 -965
  146. package/lib/generated/recorderSource.js +0 -7
  147. package/lib/third_party/diff_match_patch.js +0 -2222
  148. package/lib/vite/recorder/assets/codeMirrorModule-aW6Vz3gf.js +0 -24
  149. package/lib/vite/recorder/assets/index-DCpXOVIh.js +0 -47
  150. package/lib/vite/traceViewer/assets/codeMirrorModule-eFKCUIu2.js +0 -24
  151. package/lib/vite/traceViewer/assets/workbench-D0cirtfA.js +0 -72
  152. package/lib/vite/traceViewer/embedded.BkuvsLJp.js +0 -2
  153. package/lib/vite/traceViewer/index.C968kAiC.js +0 -2
  154. package/lib/vite/traceViewer/uiMode.BkFnr4V0.js +0 -10
  155. package/lib/vite/traceViewer/workbench.DjbIuxix.css +0 -1
  156. /package/lib/server/recorder/{recorderActions.js → recorderFrontend.js} +0 -0
@@ -12,6 +12,8 @@ var _browserContext = require("./browserContext");
12
12
  var _debugger = require("./debugger");
13
13
  var _contextRecorder = require("./recorder/contextRecorder");
14
14
  var _recorderUtils = require("./recorder/recorderUtils");
15
+ var _recorderUtils2 = require("../utils/isomorphic/recorderUtils");
16
+ var _selectorParser = require("../utils/isomorphic/selectorParser");
15
17
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
16
18
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17
19
  /**
@@ -32,29 +34,32 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
32
34
 
33
35
  const recorderSymbol = Symbol('recorderSymbol');
34
36
  class Recorder {
35
- static showInspector(context, recorderAppFactory) {
36
- const params = {};
37
+ static async showInspector(context, params, recorderAppFactory) {
37
38
  if ((0, _utils.isUnderTest)()) params.language = process.env.TEST_INSPECTOR_LANGUAGE;
38
- Recorder.show(context, recorderAppFactory, params).catch(() => {});
39
+ return await Recorder.show('actions', context, recorderAppFactory, params);
39
40
  }
40
- static show(context, recorderAppFactory, params = {}) {
41
+ static showInspectorNoReply(context, recorderAppFactory) {
42
+ Recorder.showInspector(context, {}, recorderAppFactory).catch(() => {});
43
+ }
44
+ static show(codegenMode, context, recorderAppFactory, params) {
41
45
  let recorderPromise = context[recorderSymbol];
42
46
  if (!recorderPromise) {
43
- recorderPromise = Recorder._create(context, recorderAppFactory, params);
47
+ recorderPromise = Recorder._create(codegenMode, context, recorderAppFactory, params);
44
48
  context[recorderSymbol] = recorderPromise;
45
49
  }
46
50
  return recorderPromise;
47
51
  }
48
- static async _create(context, recorderAppFactory, params = {}) {
49
- const recorder = new Recorder(context, params);
52
+ static async _create(codegenMode, context, recorderAppFactory, params = {}) {
53
+ const recorder = new Recorder(codegenMode, context, params);
50
54
  const recorderApp = await recorderAppFactory(recorder);
51
55
  await recorder._install(recorderApp);
52
56
  return recorder;
53
57
  }
54
- constructor(context, params) {
58
+ constructor(codegenMode, context, params) {
59
+ this.handleSIGINT = void 0;
55
60
  this._context = void 0;
56
61
  this._mode = void 0;
57
- this._highlightedSelector = '';
62
+ this._highlightedElement = {};
58
63
  this._overlayState = {
59
64
  offsetX: 0
60
65
  };
@@ -67,7 +72,8 @@ class Recorder {
67
72
  this._omitCallTracking = false;
68
73
  this._currentLanguage = void 0;
69
74
  this._mode = params.mode || 'none';
70
- this._contextRecorder = new _contextRecorder.ContextRecorder(context, params, {});
75
+ this.handleSIGINT = params.handleSIGINT;
76
+ this._contextRecorder = new _contextRecorder.ContextRecorder(codegenMode, context, params, {});
71
77
  this._context = context;
72
78
  this._omitCallTracking = !!params.omitCallTracking;
73
79
  this._debugger = context.debugger();
@@ -89,8 +95,9 @@ class Recorder {
89
95
  this.setMode(data.params.mode);
90
96
  return;
91
97
  }
92
- if (data.event === 'selectorUpdated') {
93
- this.setHighlightedSelector(this._currentLanguage, data.params.selector);
98
+ if (data.event === 'highlightRequested') {
99
+ if (data.params.selector) this.setHighlightedSelector(this._currentLanguage, data.params.selector);
100
+ if (data.params.ariaTemplate) this.setHighlightedAriaTemplate(data.params.ariaTemplate);
94
101
  return;
95
102
  }
96
103
  if (data.event === 'step') {
@@ -123,17 +130,17 @@ class Recorder {
123
130
  (_this$_recorderApp = this._recorderApp) === null || _this$_recorderApp === void 0 || _this$_recorderApp.close().catch(() => {});
124
131
  });
125
132
  this._contextRecorder.on(_contextRecorder.ContextRecorder.Events.Change, data => {
126
- var _this$_recorderApp2;
127
133
  this._recorderSources = data.sources;
134
+ recorderApp.setActions(data.actions, data.sources);
135
+ recorderApp.setRunningFile(undefined);
128
136
  this._pushAllSources();
129
- (_this$_recorderApp2 = this._recorderApp) === null || _this$_recorderApp2 === void 0 || _this$_recorderApp2.setFileIfNeeded(data.primaryFileName);
130
137
  });
131
- await this._context.exposeBinding('__pw_recorderState', false, source => {
132
- let actionSelector = '';
138
+ await this._context.exposeBinding('__pw_recorderState', false, async source => {
139
+ let actionSelector;
133
140
  let actionPoint;
134
141
  const hasActiveScreenshotCommand = [...this._currentCallsMetadata.keys()].some(isScreenshotCommand);
135
142
  if (!hasActiveScreenshotCommand) {
136
- actionSelector = this._highlightedSelector;
143
+ actionSelector = await this._scopeHighlightedSelectorToFrame(source.frame);
137
144
  for (const [metadata, sdkObject] of this._currentCallsMetadata) {
138
145
  if (source.page === sdkObject.attribution.page) {
139
146
  actionPoint = metadata.point || actionPoint;
@@ -145,18 +152,22 @@ class Recorder {
145
152
  mode: this._mode,
146
153
  actionPoint,
147
154
  actionSelector,
155
+ ariaTemplate: this._highlightedElement.ariaTemplate,
148
156
  language: this._currentLanguage,
149
157
  testIdAttributeName: this._contextRecorder.testIdAttributeName(),
150
158
  overlay: this._overlayState
151
159
  };
152
160
  return uiState;
153
161
  });
154
- await this._context.exposeBinding('__pw_recorderSetSelector', false, async ({
162
+ await this._context.exposeBinding('__pw_recorderElementPicked', false, async ({
155
163
  frame
156
- }, selector) => {
157
- var _this$_recorderApp3;
164
+ }, elementInfo) => {
165
+ var _this$_recorderApp2;
158
166
  const selectorChain = await (0, _contextRecorder.generateFrameSelector)(frame);
159
- await ((_this$_recorderApp3 = this._recorderApp) === null || _this$_recorderApp3 === void 0 ? void 0 : _this$_recorderApp3.setSelector((0, _recorderUtils.buildFullSelector)(selectorChain, selector), true));
167
+ await ((_this$_recorderApp2 = this._recorderApp) === null || _this$_recorderApp2 === void 0 ? void 0 : _this$_recorderApp2.elementPicked({
168
+ selector: (0, _recorderUtils2.buildFullSelector)(selectorChain, elementInfo.selector),
169
+ ariaSnapshot: elementInfo.ariaSnapshot
170
+ }, true));
160
171
  });
161
172
  await this._context.exposeBinding('__pw_recorderSetMode', false, async ({
162
173
  frame
@@ -180,7 +191,7 @@ class Recorder {
180
191
  this._context.recorderAppForTest = this._recorderApp;
181
192
  }
182
193
  _pausedStateChanged() {
183
- var _this$_recorderApp4;
194
+ var _this$_recorderApp3;
184
195
  // If we are called upon page.pause, we don't have metadatas, populate them.
185
196
  for (const {
186
197
  metadata,
@@ -188,18 +199,18 @@ class Recorder {
188
199
  } of this._debugger.pausedDetails()) {
189
200
  if (!this._currentCallsMetadata.has(metadata)) this.onBeforeCall(sdkObject, metadata);
190
201
  }
191
- (_this$_recorderApp4 = this._recorderApp) === null || _this$_recorderApp4 === void 0 || _this$_recorderApp4.setPaused(this._debugger.isPaused());
202
+ (_this$_recorderApp3 = this._recorderApp) === null || _this$_recorderApp3 === void 0 || _this$_recorderApp3.setPaused(this._debugger.isPaused());
192
203
  this._updateUserSources();
193
204
  this.updateCallLog([...this._currentCallsMetadata.keys()]);
194
205
  }
195
206
  setMode(mode) {
196
- var _this$_recorderApp5;
207
+ var _this$_recorderApp4;
197
208
  if (this._mode === mode) return;
198
- this._highlightedSelector = '';
209
+ this._highlightedElement = {};
199
210
  this._mode = mode;
200
- (_this$_recorderApp5 = this._recorderApp) === null || _this$_recorderApp5 === void 0 || _this$_recorderApp5.setMode(this._mode);
201
- this._contextRecorder.setEnabled(this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue');
202
- this._debugger.setMuted(this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue');
211
+ (_this$_recorderApp4 = this._recorderApp) === null || _this$_recorderApp4 === void 0 || _this$_recorderApp4.setMode(this._mode);
212
+ this._contextRecorder.setEnabled(this._isRecording());
213
+ this._debugger.setMuted(this._isRecording());
203
214
  if (this._mode !== 'none' && this._mode !== 'standby' && this._context.pages().length === 1) this._context.pages()[0].bringToFront().catch(() => {});
204
215
  this._refreshOverlay();
205
216
  }
@@ -210,40 +221,66 @@ class Recorder {
210
221
  return this._mode;
211
222
  }
212
223
  setHighlightedSelector(language, selector) {
213
- this._highlightedSelector = (0, _locatorParser.locatorOrSelectorAsSelector)(language, selector, this._context.selectors().testIdAttributeName());
224
+ this._highlightedElement = {
225
+ selector: (0, _locatorParser.locatorOrSelectorAsSelector)(language, selector, this._context.selectors().testIdAttributeName())
226
+ };
227
+ this._refreshOverlay();
228
+ }
229
+ setHighlightedAriaTemplate(ariaTemplate) {
230
+ this._highlightedElement = {
231
+ ariaTemplate
232
+ };
214
233
  this._refreshOverlay();
215
234
  }
216
235
  hideHighlightedSelector() {
217
- this._highlightedSelector = '';
236
+ this._highlightedElement = {};
218
237
  this._refreshOverlay();
219
238
  }
239
+ async _scopeHighlightedSelectorToFrame(frame) {
240
+ if (!this._highlightedElement.selector) return;
241
+ try {
242
+ const mainFrame = frame._page.mainFrame();
243
+ const resolved = await mainFrame.selectors.resolveFrameForSelector(this._highlightedElement.selector);
244
+ // selector couldn't be found, don't highlight anything
245
+ if (!resolved) return '';
246
+
247
+ // selector points to no specific frame, highlight in all frames
248
+ if ((resolved === null || resolved === void 0 ? void 0 : resolved.frame) === mainFrame) return (0, _selectorParser.stringifySelector)(resolved.info.parsed);
249
+
250
+ // selector points to this frame, highlight it
251
+ if ((resolved === null || resolved === void 0 ? void 0 : resolved.frame) === frame) return (0, _selectorParser.stringifySelector)(resolved.info.parsed);
252
+
253
+ // selector points to a different frame, highlight nothing
254
+ return '';
255
+ } catch {
256
+ return '';
257
+ }
258
+ }
220
259
  setOutput(codegenId, outputFile) {
221
260
  this._contextRecorder.setOutput(codegenId, outputFile);
222
261
  }
223
262
  _refreshOverlay() {
224
- for (const page of this._context.pages()) page.mainFrame().evaluateExpression('window.__pw_refreshOverlay()').catch(() => {});
263
+ for (const page of this._context.pages()) {
264
+ for (const frame of page.frames()) frame.evaluateExpression('window.__pw_refreshOverlay()').catch(() => {});
265
+ }
225
266
  }
226
267
  async onBeforeCall(sdkObject, metadata) {
227
- if (this._omitCallTracking || this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue') return;
268
+ if (this._omitCallTracking || this._isRecording()) return;
228
269
  this._currentCallsMetadata.set(metadata, sdkObject);
229
270
  this._updateUserSources();
230
271
  this.updateCallLog([metadata]);
231
- if (isScreenshotCommand(metadata)) {
232
- this.hideHighlightedSelector();
233
- } else if (metadata.params && metadata.params.selector) {
234
- var _this$_recorderApp6;
235
- this._highlightedSelector = metadata.params.selector;
236
- (_this$_recorderApp6 = this._recorderApp) === null || _this$_recorderApp6 === void 0 || _this$_recorderApp6.setSelector(this._highlightedSelector).catch(() => {});
237
- }
272
+ if (isScreenshotCommand(metadata)) this.hideHighlightedSelector();else if (metadata.params && metadata.params.selector) this._highlightedElement = {
273
+ selector: metadata.params.selector
274
+ };
238
275
  }
239
276
  async onAfterCall(sdkObject, metadata) {
240
- if (this._omitCallTracking || this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue') return;
277
+ if (this._omitCallTracking || this._isRecording()) return;
241
278
  if (!metadata.error) this._currentCallsMetadata.delete(metadata);
242
279
  this._updateUserSources();
243
280
  this.updateCallLog([metadata]);
244
281
  }
245
282
  _updateUserSources() {
246
- var _this$_recorderApp7;
283
+ var _this$_recorderApp5;
247
284
  // Remove old decorations.
248
285
  for (const source of this._userSources.values()) {
249
286
  source.highlight = [];
@@ -281,19 +318,19 @@ class Recorder {
281
318
  }
282
319
  }
283
320
  this._pushAllSources();
284
- if (fileToSelect) (_this$_recorderApp7 = this._recorderApp) === null || _this$_recorderApp7 === void 0 || _this$_recorderApp7.setFileIfNeeded(fileToSelect);
321
+ if (fileToSelect) (_this$_recorderApp5 = this._recorderApp) === null || _this$_recorderApp5 === void 0 || _this$_recorderApp5.setRunningFile(fileToSelect);
285
322
  }
286
323
  _pushAllSources() {
287
- var _this$_recorderApp8;
288
- (_this$_recorderApp8 = this._recorderApp) === null || _this$_recorderApp8 === void 0 || _this$_recorderApp8.setSources([...this._recorderSources, ...this._userSources.values()]);
324
+ var _this$_recorderApp6;
325
+ (_this$_recorderApp6 = this._recorderApp) === null || _this$_recorderApp6 === void 0 || _this$_recorderApp6.setSources([...this._recorderSources, ...this._userSources.values()]);
289
326
  }
290
327
  async onBeforeInputAction(sdkObject, metadata) {}
291
328
  async onCallLog(sdkObject, metadata, logName, message) {
292
329
  this.updateCallLog([metadata]);
293
330
  }
294
331
  updateCallLog(metadatas) {
295
- var _this$_recorderApp9;
296
- if (this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue') return;
332
+ var _this$_recorderApp7;
333
+ if (this._isRecording()) return;
297
334
  const logs = [];
298
335
  for (const metadata of metadatas) {
299
336
  if (!metadata.method || metadata.internal) continue;
@@ -302,7 +339,10 @@ class Recorder {
302
339
  if (this._debugger.isPaused(metadata)) status = 'paused';
303
340
  logs.push((0, _recorderUtils.metadataToCallLog)(metadata, status));
304
341
  }
305
- (_this$_recorderApp9 = this._recorderApp) === null || _this$_recorderApp9 === void 0 || _this$_recorderApp9.updateCallLogs(logs);
342
+ (_this$_recorderApp7 = this._recorderApp) === null || _this$_recorderApp7 === void 0 || _this$_recorderApp7.updateCallLogs(logs);
343
+ }
344
+ _isRecording() {
345
+ return ['recording', 'assertingText', 'assertingVisibility', 'assertingValue', 'assertingSnapshot'].includes(this._mode);
306
346
  }
307
347
  _readSource(fileName) {
308
348
  try {
@@ -8,7 +8,6 @@ exports.browserDirectoryToMarkerFilePath = browserDirectoryToMarkerFilePath;
8
8
  exports.buildPlaywrightCLICommand = buildPlaywrightCLICommand;
9
9
  exports.findChromiumChannel = findChromiumChannel;
10
10
  exports.installBrowsersForNpmInstall = installBrowsersForNpmInstall;
11
- exports.installDefaultBrowsersForNpmInstall = installDefaultBrowsersForNpmInstall;
12
11
  exports.registryDirectory = exports.registry = void 0;
13
12
  Object.defineProperty(exports, "writeDockerVersion", {
14
13
  enumerable: true,
@@ -65,6 +64,11 @@ const EXECUTABLE_PATHS = {
65
64
  'mac': ['chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'],
66
65
  'win': ['chrome-win', 'chrome.exe']
67
66
  },
67
+ 'chromium-headless-shell': {
68
+ 'linux': ['chrome-linux', 'headless_shell'],
69
+ 'mac': ['chrome-mac', 'headless_shell'],
70
+ 'win': ['chrome-win', 'headless_shell.exe']
71
+ },
68
72
  'firefox': {
69
73
  'linux': ['firefox', 'firefox'],
70
74
  'mac': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'],
@@ -107,8 +111,39 @@ const DOWNLOAD_PATHS = {
107
111
  'mac13-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
108
112
  'mac14': 'builds/chromium/%s/chromium-mac.zip',
109
113
  'mac14-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
114
+ 'mac15': 'builds/chromium/%s/chromium-mac.zip',
115
+ 'mac15-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
110
116
  'win64': 'builds/chromium/%s/chromium-win64.zip'
111
117
  },
118
+ 'chromium-headless-shell': {
119
+ '<unknown>': undefined,
120
+ 'ubuntu18.04-x64': undefined,
121
+ 'ubuntu20.04-x64': 'builds/chromium/%s/chromium-headless-shell-linux.zip',
122
+ 'ubuntu22.04-x64': 'builds/chromium/%s/chromium-headless-shell-linux.zip',
123
+ 'ubuntu24.04-x64': 'builds/chromium/%s/chromium-headless-shell-linux.zip',
124
+ 'ubuntu18.04-arm64': undefined,
125
+ 'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-headless-shell-linux-arm64.zip',
126
+ 'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-headless-shell-linux-arm64.zip',
127
+ 'ubuntu24.04-arm64': 'builds/chromium/%s/chromium-headless-shell-linux-arm64.zip',
128
+ 'debian11-x64': 'builds/chromium/%s/chromium-headless-shell-linux.zip',
129
+ 'debian11-arm64': 'builds/chromium/%s/chromium-headless-shell-linux-arm64.zip',
130
+ 'debian12-x64': 'builds/chromium/%s/chromium-headless-shell-linux.zip',
131
+ 'debian12-arm64': 'builds/chromium/%s/chromium-headless-shell-linux-arm64.zip',
132
+ 'mac10.13': undefined,
133
+ 'mac10.14': undefined,
134
+ 'mac10.15': undefined,
135
+ 'mac11': 'builds/chromium/%s/chromium-headless-shell-mac.zip',
136
+ 'mac11-arm64': 'builds/chromium/%s/chromium-headless-shell-mac-arm64.zip',
137
+ 'mac12': 'builds/chromium/%s/chromium-headless-shell-mac.zip',
138
+ 'mac12-arm64': 'builds/chromium/%s/chromium-headless-shell-mac-arm64.zip',
139
+ 'mac13': 'builds/chromium/%s/chromium-headless-shell-mac.zip',
140
+ 'mac13-arm64': 'builds/chromium/%s/chromium-headless-shell-mac-arm64.zip',
141
+ 'mac14': 'builds/chromium/%s/chromium-headless-shell-mac.zip',
142
+ 'mac14-arm64': 'builds/chromium/%s/chromium-headless-shell-mac-arm64.zip',
143
+ 'mac15': 'builds/chromium/%s/chromium-headless-shell-mac.zip',
144
+ 'mac15-arm64': 'builds/chromium/%s/chromium-headless-shell-mac-arm64.zip',
145
+ 'win64': 'builds/chromium/%s/chromium-headless-shell-win64.zip'
146
+ },
112
147
  'chromium-tip-of-tree': {
113
148
  '<unknown>': undefined,
114
149
  'ubuntu18.04-x64': undefined,
@@ -134,6 +169,8 @@ const DOWNLOAD_PATHS = {
134
169
  'mac13-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
135
170
  'mac14': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
136
171
  'mac14-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
172
+ 'mac15': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
173
+ 'mac15-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
137
174
  'win64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-win64.zip'
138
175
  },
139
176
  'firefox': {
@@ -161,6 +198,8 @@ const DOWNLOAD_PATHS = {
161
198
  'mac13-arm64': 'builds/firefox/%s/firefox-mac-arm64.zip',
162
199
  'mac14': 'builds/firefox/%s/firefox-mac.zip',
163
200
  'mac14-arm64': 'builds/firefox/%s/firefox-mac-arm64.zip',
201
+ 'mac15': 'builds/firefox/%s/firefox-mac.zip',
202
+ 'mac15-arm64': 'builds/firefox/%s/firefox-mac-arm64.zip',
164
203
  'win64': 'builds/firefox/%s/firefox-win64.zip'
165
204
  },
166
205
  'firefox-beta': {
@@ -188,6 +227,8 @@ const DOWNLOAD_PATHS = {
188
227
  'mac13-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-arm64.zip',
189
228
  'mac14': 'builds/firefox-beta/%s/firefox-beta-mac.zip',
190
229
  'mac14-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-arm64.zip',
230
+ 'mac15': 'builds/firefox-beta/%s/firefox-beta-mac.zip',
231
+ 'mac15-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-arm64.zip',
191
232
  'win64': 'builds/firefox-beta/%s/firefox-beta-win64.zip'
192
233
  },
193
234
  'webkit': {
@@ -215,6 +256,8 @@ const DOWNLOAD_PATHS = {
215
256
  'mac13-arm64': 'builds/webkit/%s/webkit-mac-13-arm64.zip',
216
257
  'mac14': 'builds/webkit/%s/webkit-mac-14.zip',
217
258
  'mac14-arm64': 'builds/webkit/%s/webkit-mac-14-arm64.zip',
259
+ 'mac15': 'builds/webkit/%s/webkit-mac-15.zip',
260
+ 'mac15-arm64': 'builds/webkit/%s/webkit-mac-15-arm64.zip',
218
261
  'win64': 'builds/webkit/%s/webkit-win64.zip'
219
262
  },
220
263
  'ffmpeg': {
@@ -242,6 +285,8 @@ const DOWNLOAD_PATHS = {
242
285
  'mac13-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
243
286
  'mac14': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
244
287
  'mac14-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
288
+ 'mac15': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
289
+ 'mac15-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
245
290
  'win64': 'builds/ffmpeg/%s/ffmpeg-win64.zip'
246
291
  },
247
292
  'android': {
@@ -269,6 +314,8 @@ const DOWNLOAD_PATHS = {
269
314
  'mac13-arm64': 'builds/android/%s/android.zip',
270
315
  'mac14': 'builds/android/%s/android.zip',
271
316
  'mac14-arm64': 'builds/android/%s/android.zip',
317
+ 'mac15': 'builds/android/%s/android.zip',
318
+ 'mac15-arm64': 'builds/android/%s/android.zip',
272
319
  'win64': 'builds/android/%s/android.zip'
273
320
  },
274
321
  // TODO(bidi): implement downloads.
@@ -299,7 +346,7 @@ const registryDirectory = exports.registryDirectory = (() => {
299
346
  function isBrowserDirectory(browserDirectory) {
300
347
  const baseName = _path.default.basename(browserDirectory);
301
348
  for (const browserName of allDownloadable) {
302
- if (baseName.startsWith(browserName + '-')) return true;
349
+ if (baseName.startsWith(browserName.replace(/-/g, '_') + '-')) return true;
303
350
  }
304
351
  return false;
305
352
  }
@@ -312,6 +359,7 @@ function readDescriptors(browsersJSON) {
312
359
  const descriptor = {
313
360
  name,
314
361
  revision,
362
+ hasRevisionOverride: !!revisionOverride,
315
363
  // We only put browser version for the supported operating systems.
316
364
  browserVersion: revisionOverride ? undefined : obj.browserVersion,
317
365
  installByDefault: !!obj.installByDefault,
@@ -325,7 +373,7 @@ function readDescriptors(browsersJSON) {
325
373
  return descriptor;
326
374
  });
327
375
  }
328
- const allDownloadable = ['chromium', 'firefox', 'webkit', 'ffmpeg', 'firefox-beta', 'chromium-tip-of-tree'];
376
+ const allDownloadable = ['android', 'chromium', 'firefox', 'webkit', 'ffmpeg', 'firefox-beta', 'chromium-tip-of-tree', 'chromium-headless-shell'];
329
377
  class Registry {
330
378
  constructor(browsersJSON) {
331
379
  this._executables = void 0;
@@ -358,13 +406,30 @@ class Registry {
358
406
  executablePath: () => chromiumExecutable,
359
407
  executablePathOrDie: sdkLanguage => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage),
360
408
  installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand',
361
- _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),
409
+ _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, chromium.dir, ['chrome-linux'], [], ['chrome-win']),
362
410
  downloadURLs: this._downloadURLs(chromium),
363
411
  browserVersion: chromium.browserVersion,
364
412
  _install: () => this._downloadExecutable(chromium, chromiumExecutable),
365
413
  _dependencyGroup: 'chromium',
366
414
  _isHermeticInstallation: true
367
415
  });
416
+ const chromiumHeadlessShell = descriptors.find(d => d.name === 'chromium-headless-shell');
417
+ const chromiumHeadlessShellExecutable = findExecutablePath(chromiumHeadlessShell.dir, 'chromium-headless-shell');
418
+ this._executables.push({
419
+ type: 'channel',
420
+ name: 'chromium-headless-shell',
421
+ browserName: 'chromium',
422
+ directory: chromiumHeadlessShell.dir,
423
+ executablePath: () => chromiumHeadlessShellExecutable,
424
+ executablePathOrDie: sdkLanguage => executablePathOrDie('chromium', chromiumHeadlessShellExecutable, chromiumHeadlessShell.installByDefault, sdkLanguage),
425
+ installType: chromiumHeadlessShell.installByDefault ? 'download-by-default' : 'download-on-demand',
426
+ _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, chromiumHeadlessShell.dir, ['chrome-linux'], [], ['chrome-win']),
427
+ downloadURLs: this._downloadURLs(chromiumHeadlessShell),
428
+ browserVersion: chromium.browserVersion,
429
+ _install: () => this._downloadExecutable(chromiumHeadlessShell, chromiumHeadlessShellExecutable),
430
+ _dependencyGroup: 'chromium',
431
+ _isHermeticInstallation: true
432
+ });
368
433
  const chromiumTipOfTree = descriptors.find(d => d.name === 'chromium-tip-of-tree');
369
434
  const chromiumTipOfTreeExecutable = findExecutablePath(chromiumTipOfTree.dir, 'chromium');
370
435
  this._executables.push({
@@ -375,7 +440,7 @@ class Registry {
375
440
  executablePath: () => chromiumTipOfTreeExecutable,
376
441
  executablePathOrDie: sdkLanguage => executablePathOrDie('chromium-tip-of-tree', chromiumTipOfTreeExecutable, chromiumTipOfTree.installByDefault, sdkLanguage),
377
442
  installType: chromiumTipOfTree.installByDefault ? 'download-by-default' : 'download-on-demand',
378
- _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumTipOfTree.dir, ['chrome-linux'], [], ['chrome-win']),
443
+ _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, chromiumTipOfTree.dir, ['chrome-linux'], [], ['chrome-win']),
379
444
  downloadURLs: this._downloadURLs(chromiumTipOfTree),
380
445
  browserVersion: chromiumTipOfTree.browserVersion,
381
446
  _install: () => this._downloadExecutable(chromiumTipOfTree, chromiumTipOfTreeExecutable),
@@ -442,11 +507,46 @@ class Registry {
442
507
  'darwin': '/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary',
443
508
  'win32': `\\Microsoft\\Edge SxS\\Application\\msedge.exe`
444
509
  }));
445
- this._executables.push(this._createBidiChannel('bidi-firefox-stable', {
446
- 'linux': '/usr/bin/firefox',
447
- 'darwin': '/Applications/Firefox.app/Contents/MacOS/firefox',
448
- 'win32': '\\Mozilla Firefox\\firefox.exe'
510
+ this._executables.push(this._createBidiFirefoxChannel('bidi-firefox-stable', {
511
+ 'linux': '/firefox/firefox',
512
+ 'darwin': '/Firefox.app/Contents/MacOS/firefox',
513
+ 'win32': '\\core\\firefox.exe'
514
+ }));
515
+ this._executables.push(this._createBidiFirefoxChannel('bidi-firefox-beta', {
516
+ 'linux': '/firefox/firefox',
517
+ 'darwin': '/Firefox.app/Contents/MacOS/firefox',
518
+ 'win32': '\\core\\firefox.exe'
519
+ }));
520
+ this._executables.push(this._createBidiFirefoxChannel('bidi-firefox-nightly', {
521
+ 'linux': '/firefox/firefox',
522
+ 'darwin': '/Firefox Nightly.app/Contents/MacOS/firefox',
523
+ 'win32': '\\firefox\\firefox.exe'
449
524
  }));
525
+ this._executables.push(this._createBidiChannel('bidi-chrome-stable', {
526
+ 'linux': '/opt/google/chrome/chrome',
527
+ 'darwin': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
528
+ 'win32': `\\Google\\Chrome\\Application\\chrome.exe`
529
+ }));
530
+ this._executables.push(this._createBidiChannel('bidi-chrome-canary', {
531
+ 'linux': '',
532
+ 'darwin': '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
533
+ 'win32': `\\Google\\Chrome SxS\\Application\\chrome.exe`
534
+ }));
535
+ this._executables.push({
536
+ type: 'browser',
537
+ name: 'bidi-chromium',
538
+ browserName: 'bidi',
539
+ directory: chromium.dir,
540
+ executablePath: () => chromiumExecutable,
541
+ executablePathOrDie: sdkLanguage => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage),
542
+ installType: 'download-on-demand',
543
+ _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, chromium.dir, ['chrome-linux'], [], ['chrome-win']),
544
+ downloadURLs: this._downloadURLs(chromium),
545
+ browserVersion: chromium.browserVersion,
546
+ _install: () => this._downloadExecutable(chromium, chromiumExecutable),
547
+ _dependencyGroup: 'chromium',
548
+ _isHermeticInstallation: true
549
+ });
450
550
  const firefox = descriptors.find(d => d.name === 'firefox');
451
551
  const firefoxExecutable = findExecutablePath(firefox.dir, 'firefox');
452
552
  this._executables.push({
@@ -457,7 +557,7 @@ class Registry {
457
557
  executablePath: () => firefoxExecutable,
458
558
  executablePathOrDie: sdkLanguage => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage),
459
559
  installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand',
460
- _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']),
560
+ _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, firefox.dir, ['firefox'], [], ['firefox']),
461
561
  downloadURLs: this._downloadURLs(firefox),
462
562
  browserVersion: firefox.browserVersion,
463
563
  _install: () => this._downloadExecutable(firefox, firefoxExecutable),
@@ -474,7 +574,7 @@ class Registry {
474
574
  executablePath: () => firefoxBetaExecutable,
475
575
  executablePathOrDie: sdkLanguage => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage),
476
576
  installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand',
477
- _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),
577
+ _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, firefoxBeta.dir, ['firefox'], [], ['firefox']),
478
578
  downloadURLs: this._downloadURLs(firefoxBeta),
479
579
  browserVersion: firefoxBeta.browserVersion,
480
580
  _install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable),
@@ -492,7 +592,7 @@ class Registry {
492
592
  executablePath: () => webkitExecutable,
493
593
  executablePathOrDie: sdkLanguage => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage),
494
594
  installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand',
495
- _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),
595
+ _validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),
496
596
  downloadURLs: this._downloadURLs(webkit),
497
597
  browserVersion: webkit.browserVersion,
498
598
  _install: () => this._downloadExecutable(webkit, webkitExecutable),
@@ -575,6 +675,38 @@ class Registry {
575
675
  _install: install
576
676
  };
577
677
  }
678
+ _createBidiFirefoxChannel(name, lookAt, install) {
679
+ const executablePath = (sdkLanguage, shouldThrow) => {
680
+ const suffix = lookAt[process.platform];
681
+ if (!suffix) {
682
+ if (shouldThrow) throw new Error(`Firefox distribution '${name}' is not supported on ${process.platform}`);
683
+ return undefined;
684
+ }
685
+ const folder = _path.default.resolve('firefox');
686
+ let channelName = 'stable';
687
+ if (name.includes('beta')) channelName = 'beta';else if (name.includes('nightly')) channelName = 'nightly';
688
+ const installedVersions = fs.readdirSync(folder);
689
+ const found = installedVersions.filter(e => e.includes(channelName));
690
+ if (found.length === 1) return _path.default.join(folder, found[0], suffix);
691
+ if (found.length > 1) {
692
+ if (shouldThrow) throw new Error(`Multiple Firefox installations found for channel '${name}': ${found.join(', ')}`);else return undefined;
693
+ }
694
+ if (shouldThrow) throw new Error(`Cannot find Firefox installation for channel '${name}' under ${folder}`);
695
+ return undefined;
696
+ };
697
+ return {
698
+ type: 'channel',
699
+ name,
700
+ browserName: 'bidi',
701
+ directory: undefined,
702
+ executablePath: sdkLanguage => executablePath(sdkLanguage, false),
703
+ executablePathOrDie: sdkLanguage => executablePath(sdkLanguage, true),
704
+ installType: 'none',
705
+ _validateHostRequirements: () => Promise.resolve(),
706
+ _isHermeticInstallation: true,
707
+ _install: install
708
+ };
709
+ }
578
710
  _createBidiChannel(name, lookAt, install) {
579
711
  const executablePath = (sdkLanguage, shouldThrow) => {
580
712
  const suffix = lookAt[process.platform];
@@ -614,20 +746,15 @@ class Registry {
614
746
  defaultExecutables() {
615
747
  return this._executables.filter(e => e.installType === 'download-by-default');
616
748
  }
617
- _addRequirementsAndDedupe(executables) {
618
- const set = new Set();
619
- for (const executable of executables) {
620
- set.add(executable);
621
- if (executable.browserName === 'chromium') set.add(this.findExecutable('ffmpeg'));
622
- }
623
- return Array.from(set);
749
+ _dedupe(executables) {
750
+ return Array.from(new Set(executables));
624
751
  }
625
- async _validateHostRequirements(sdkLanguage, browserName, browserDirectory, linuxLddDirectories, dlOpenLibraries, windowsExeAndDllDirectories) {
752
+ async _validateHostRequirements(sdkLanguage, browserDirectory, linuxLddDirectories, dlOpenLibraries, windowsExeAndDllDirectories) {
626
753
  if (os.platform() === 'linux') return await (0, _dependencies.validateDependenciesLinux)(sdkLanguage, linuxLddDirectories.map(d => _path.default.join(browserDirectory, d)), dlOpenLibraries);
627
754
  if (os.platform() === 'win32' && os.arch() === 'x64') return await (0, _dependencies.validateDependenciesWindows)(windowsExeAndDllDirectories.map(d => _path.default.join(browserDirectory, d)));
628
755
  }
629
756
  async installDeps(executablesToInstallDeps, dryRun) {
630
- const executables = this._addRequirementsAndDedupe(executablesToInstallDeps);
757
+ const executables = this._dedupe(executablesToInstallDeps);
631
758
  const targets = new Set();
632
759
  for (const executable of executables) {
633
760
  if (executable._dependencyGroup) targets.add(executable._dependencyGroup);
@@ -637,7 +764,7 @@ class Registry {
637
764
  if (os.platform() === 'linux') return await (0, _dependencies.installDependenciesLinux)(targets, dryRun);
638
765
  }
639
766
  async install(executablesToInstall, forceReinstall) {
640
- const executables = this._addRequirementsAndDedupe(executablesToInstall);
767
+ const executables = this._dedupe(executablesToInstall);
641
768
  await fs.promises.mkdir(registryDirectory, {
642
769
  recursive: true
643
770
  });
@@ -745,6 +872,11 @@ class Registry {
745
872
  const downloadURLs = this._downloadURLs(descriptor);
746
873
  if (!downloadURLs.length) throw new Error(`ERROR: Playwright does not support ${descriptor.name} on ${_hostPlatform.hostPlatform}`);
747
874
  if (!_hostPlatform.isOfficiallySupportedPlatform) (0, _browserFetcher.logPolitely)(`BEWARE: your OS is not officially supported by Playwright; downloading fallback build for ${_hostPlatform.hostPlatform}.`);
875
+ if (descriptor.hasRevisionOverride) {
876
+ const message = `You are using a frozen ${descriptor.name} browser which does not receive updates anymore on ${_hostPlatform.hostPlatform}. Please update to the latest version of your operating system to test up-to-date browsers.`;
877
+ if (process.env.GITHUB_ACTIONS) console.log(`::warning title=Playwright::${message}`); // eslint-disable-line no-console
878
+ else (0, _browserFetcher.logPolitely)(message);
879
+ }
748
880
  const displayName = descriptor.name.split('-').map(word => {
749
881
  return word === 'ffmpeg' ? 'FFMPEG' : word.charAt(0).toUpperCase() + word.slice(1);
750
882
  }).join(' ');
@@ -878,10 +1010,6 @@ function buildPlaywrightCLICommand(sdkLanguage, parameters) {
878
1010
  }
879
1011
  }
880
1012
  }
881
- async function installDefaultBrowsersForNpmInstall() {
882
- const defaultBrowserNames = registry.defaultExecutables().map(e => e.name);
883
- return installBrowsersForNpmInstall(defaultBrowserNames);
884
- }
885
1013
  async function installBrowsersForNpmInstall(browsers) {
886
1014
  // PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD should have a value of 0 or 1
887
1015
  if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD')) {