playwright-core 1.54.0-alpha-2025-06-18 → 1.54.0-alpha-2025-06-20

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 (31) hide show
  1. package/browsers.json +2 -2
  2. package/lib/browserServerImpl.js +1 -6
  3. package/lib/generated/injectedScriptSource.js +1 -1
  4. package/lib/remote/playwrightConnection.js +30 -33
  5. package/lib/remote/playwrightServer.js +4 -14
  6. package/lib/server/bidi/bidiChromium.js +2 -2
  7. package/lib/server/browser.js +3 -0
  8. package/lib/server/browserType.js +2 -2
  9. package/lib/server/chromium/chromium.js +2 -2
  10. package/lib/server/chromium/crPage.js +1 -1
  11. package/lib/server/dispatchers/androidDispatcher.js +6 -1
  12. package/lib/server/dispatchers/browserTypeDispatcher.js +8 -1
  13. package/lib/server/dispatchers/electronDispatcher.js +4 -1
  14. package/lib/server/dispatchers/playwrightDispatcher.js +8 -7
  15. package/lib/server/dom.js +12 -18
  16. package/lib/server/frameSelectors.js +1 -1
  17. package/lib/server/frames.js +1 -1
  18. package/lib/server/page.js +2 -2
  19. package/lib/server/recorder/contextRecorder.js +1 -1
  20. package/lib/server/recorder/recorderApp.js +1 -1
  21. package/lib/server/trace/recorder/tracing.js +5 -2
  22. package/lib/server/trace/viewer/traceViewer.js +0 -1
  23. package/lib/server/utils/wsServer.js +0 -1
  24. package/lib/utils/isomorphic/protocolMetainfo.js +1 -1
  25. package/lib/vite/traceViewer/assets/{codeMirrorModule-BrkttCNj.js → codeMirrorModule--amfWN3K.js} +1 -1
  26. package/lib/vite/traceViewer/assets/{defaultSettingsView-n407vKdT.js → defaultSettingsView-BFAIqAv2.js} +73 -73
  27. package/lib/vite/traceViewer/{index.CdwM4SOI.js → index.amRtOpxT.js} +1 -1
  28. package/lib/vite/traceViewer/index.html +2 -2
  29. package/lib/vite/traceViewer/uiMode.html +2 -2
  30. package/lib/vite/traceViewer/{uiMode.Bt-oxu9U.js → uiMode.hufuL2u6.js} +1 -1
  31. package/package.json +1 -1
@@ -33,15 +33,14 @@ var import_profiler = require("../server/utils/profiler");
33
33
  var import_utils = require("../utils");
34
34
  var import_debugLogger = require("../server/utils/debugLogger");
35
35
  class PlaywrightConnection {
36
- constructor(lock, clientType, ws, options, preLaunched, id, onClose) {
36
+ constructor(lock, clientType, ws, options, playwright, preLaunched, id, onClose) {
37
37
  this._cleanups = [];
38
38
  this._disconnected = false;
39
39
  this._ws = ws;
40
+ this._playwright = playwright;
40
41
  this._preLaunched = preLaunched;
41
42
  this._options = options;
42
43
  options.launchOptions = filterLaunchOptions(options.launchOptions, options.allowFSPaths);
43
- if (clientType === "reuse-browser" || clientType === "pre-launched-browser-or-android")
44
- (0, import_assert.assert)(preLaunched.playwright);
45
44
  if (clientType === "pre-launched-browser-or-android")
46
45
  (0, import_assert.assert)(preLaunched.browser || preLaunched.androidDevice);
47
46
  this._onClose = onClose;
@@ -78,9 +77,9 @@ class PlaywrightConnection {
78
77
  this._root = new import_server.RootDispatcher(this._dispatcherConnection, async (scope, options2) => {
79
78
  await (0, import_profiler.startProfiling)();
80
79
  if (clientType === "reuse-browser")
81
- return await this._initReuseBrowsersMode(scope);
80
+ return await this._initReuseBrowsersMode(scope, options2);
82
81
  if (clientType === "pre-launched-browser-or-android")
83
- return this._preLaunched.browser ? await this._initPreLaunchedBrowserMode(scope) : await this._initPreLaunchedAndroidMode(scope);
82
+ return this._preLaunched.browser ? await this._initPreLaunchedBrowserMode(scope, options2) : await this._initPreLaunchedAndroidMode(scope);
84
83
  if (clientType === "launch-browser")
85
84
  return await this._initLaunchBrowserMode(scope, options2);
86
85
  throw new Error("Unsupported client type: " + clientType);
@@ -88,8 +87,7 @@ class PlaywrightConnection {
88
87
  }
89
88
  async _initLaunchBrowserMode(scope, options) {
90
89
  import_debugLogger.debugLogger.log("server", `[${this._id}] engaged launch mode for "${this._options.browserName}"`);
91
- const playwright = (0, import_server.createPlaywright)({ sdkLanguage: options.sdkLanguage, isServer: true });
92
- const ownedSocksProxy = await this._createOwnedSocksProxy(playwright);
90
+ const ownedSocksProxy = await this._createOwnedSocksProxy();
93
91
  let browserName = this._options.browserName;
94
92
  if ("bidi" === browserName) {
95
93
  if (this._options.launchOptions?.channel?.toLocaleLowerCase().includes("firefox"))
@@ -97,30 +95,29 @@ class PlaywrightConnection {
97
95
  else
98
96
  browserName = "bidiChromium";
99
97
  }
100
- const browser = await playwright[browserName].launch((0, import_instrumentation.serverSideCallMetadata)(), this._options.launchOptions);
101
- this._cleanups.push(async () => {
102
- for (const browser2 of playwright.allBrowsers())
103
- await browser2.close({ reason: "Connection terminated" });
104
- });
98
+ const browser = await this._playwright[browserName].launch((0, import_instrumentation.serverSideCallMetadata)(), this._options.launchOptions);
99
+ browser.options.sdkLanguage = options.sdkLanguage;
100
+ this._cleanups.push(() => browser.close({ reason: "Connection terminated" }));
105
101
  browser.on(import_browser.Browser.Events.Disconnected, () => {
106
102
  this.close({ code: 1001, reason: "Browser closed" });
107
103
  });
108
- return new import_server.PlaywrightDispatcher(scope, playwright, { socksProxy: ownedSocksProxy, preLaunchedBrowser: browser });
104
+ return new import_server.PlaywrightDispatcher(scope, this._playwright, { socksProxy: ownedSocksProxy, preLaunchedBrowser: browser, denyLaunch: true });
109
105
  }
110
- async _initPreLaunchedBrowserMode(scope) {
106
+ async _initPreLaunchedBrowserMode(scope, options) {
111
107
  import_debugLogger.debugLogger.log("server", `[${this._id}] engaged pre-launched (browser) mode`);
112
- const playwright = this._preLaunched.playwright;
113
108
  this._preLaunched.socksProxy?.setPattern(this._options.socksProxyPattern);
114
109
  const browser = this._preLaunched.browser;
110
+ browser.options.sdkLanguage = options.sdkLanguage;
115
111
  browser.on(import_browser.Browser.Events.Disconnected, () => {
116
112
  this.close({ code: 1001, reason: "Browser closed" });
117
113
  });
118
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, playwright, {
114
+ const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, this._playwright, {
119
115
  socksProxy: this._preLaunched.socksProxy,
120
116
  preLaunchedBrowser: browser,
121
- sharedBrowser: this._options.sharedBrowser
117
+ sharedBrowser: this._options.sharedBrowser,
118
+ denyLaunch: true
122
119
  });
123
- for (const b of playwright.allBrowsers()) {
120
+ for (const b of this._playwright.allBrowsers()) {
124
121
  if (b !== browser)
125
122
  await b.close({ reason: "Connection terminated" });
126
123
  }
@@ -129,38 +126,35 @@ class PlaywrightConnection {
129
126
  }
130
127
  async _initPreLaunchedAndroidMode(scope) {
131
128
  import_debugLogger.debugLogger.log("server", `[${this._id}] engaged pre-launched (Android) mode`);
132
- const playwright = this._preLaunched.playwright;
133
129
  const androidDevice = this._preLaunched.androidDevice;
134
130
  androidDevice.on(import_android.AndroidDevice.Events.Close, () => {
135
131
  this.close({ code: 1001, reason: "Android device disconnected" });
136
132
  });
137
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, playwright, { preLaunchedAndroidDevice: androidDevice });
133
+ const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, this._playwright, { preLaunchedAndroidDevice: androidDevice, denyLaunch: true });
138
134
  this._cleanups.push(() => playwrightDispatcher.cleanup());
139
135
  return playwrightDispatcher;
140
136
  }
141
137
  _initDebugControllerMode() {
142
138
  import_debugLogger.debugLogger.log("server", `[${this._id}] engaged reuse controller mode`);
143
- const playwright = this._preLaunched.playwright;
144
- return new import_debugControllerDispatcher.DebugControllerDispatcher(this._dispatcherConnection, playwright.debugController);
139
+ return new import_debugControllerDispatcher.DebugControllerDispatcher(this._dispatcherConnection, this._playwright.debugController);
145
140
  }
146
- async _initReuseBrowsersMode(scope) {
141
+ async _initReuseBrowsersMode(scope, options) {
147
142
  import_debugLogger.debugLogger.log("server", `[${this._id}] engaged reuse browsers mode for ${this._options.browserName}`);
148
- const playwright = this._preLaunched.playwright;
149
143
  const requestedOptions = launchOptionsHash(this._options.launchOptions);
150
- let browser = playwright.allBrowsers().find((b) => {
144
+ let browser = this._playwright.allBrowsers().find((b) => {
151
145
  if (b.options.name !== this._options.browserName)
152
146
  return false;
153
147
  const existingOptions = launchOptionsHash(b.options.originalLaunchOptions);
154
148
  return existingOptions === requestedOptions;
155
149
  });
156
- for (const b of playwright.allBrowsers()) {
150
+ for (const b of this._playwright.allBrowsers()) {
157
151
  if (b === browser)
158
152
  continue;
159
153
  if (b.options.name === this._options.browserName && b.options.channel === this._options.launchOptions.channel)
160
154
  await b.close({ reason: "Connection terminated" });
161
155
  }
162
156
  if (!browser) {
163
- browser = await playwright[this._options.browserName || "chromium"].launch((0, import_instrumentation.serverSideCallMetadata)(), {
157
+ browser = await this._playwright[this._options.browserName || "chromium"].launch((0, import_instrumentation.serverSideCallMetadata)(), {
164
158
  ...this._options.launchOptions,
165
159
  headless: !!process.env.PW_DEBUG_CONTROLLER_HEADLESS
166
160
  });
@@ -168,8 +162,9 @@ class PlaywrightConnection {
168
162
  this.close({ code: 1001, reason: "Browser closed" });
169
163
  });
170
164
  }
165
+ browser.options.sdkLanguage = options.sdkLanguage;
171
166
  this._cleanups.push(async () => {
172
- for (const browser2 of playwright.allBrowsers()) {
167
+ for (const browser2 of this._playwright.allBrowsers()) {
173
168
  for (const context of browser2.contexts()) {
174
169
  if (!context.pages().length)
175
170
  await context.close({ reason: "Connection terminated" });
@@ -180,16 +175,18 @@ class PlaywrightConnection {
180
175
  await browser2.close({ reason: "Connection terminated" });
181
176
  }
182
177
  });
183
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, playwright, { preLaunchedBrowser: browser });
178
+ const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, this._playwright, { preLaunchedBrowser: browser, denyLaunch: true });
184
179
  return playwrightDispatcher;
185
180
  }
186
- async _createOwnedSocksProxy(playwright) {
187
- if (!this._options.socksProxyPattern)
181
+ async _createOwnedSocksProxy() {
182
+ if (!this._options.socksProxyPattern) {
183
+ this._options.launchOptions.socksProxyPort = void 0;
188
184
  return;
185
+ }
189
186
  const socksProxy = new import_socksProxy.SocksProxy();
190
187
  socksProxy.setPattern(this._options.socksProxyPattern);
191
- playwright.options.socksProxyPort = await socksProxy.listen(0);
192
- import_debugLogger.debugLogger.log("server", `[${this._id}] started socks proxy on port ${playwright.options.socksProxyPort}`);
188
+ this._options.launchOptions.socksProxyPort = await socksProxy.listen(0);
189
+ import_debugLogger.debugLogger.log("server", `[${this._id}] started socks proxy on port ${this._options.launchOptions.socksProxyPort}`);
193
190
  this._cleanups.push(() => socksProxy.close());
194
191
  return socksProxy;
195
192
  }
@@ -23,7 +23,6 @@ __export(playwrightServer_exports, {
23
23
  module.exports = __toCommonJS(playwrightServer_exports);
24
24
  var import_playwrightConnection = require("./playwrightConnection");
25
25
  var import_playwright = require("../server/playwright");
26
- var import_debugLogger = require("../server/utils/debugLogger");
27
26
  var import_semaphore = require("../utils/isomorphic/semaphore");
28
27
  var import_time = require("../utils/isomorphic/time");
29
28
  var import_wsServer = require("../server/utils/wsServer");
@@ -33,9 +32,10 @@ class PlaywrightServer {
33
32
  constructor(options) {
34
33
  this._options = options;
35
34
  if (options.preLaunchedBrowser)
36
- this._preLaunchedPlaywright = options.preLaunchedBrowser.attribution.playwright;
35
+ this._playwright = options.preLaunchedBrowser.attribution.playwright;
37
36
  if (options.preLaunchedAndroidDevice)
38
- this._preLaunchedPlaywright = options.preLaunchedAndroidDevice._android.attribution.playwright;
37
+ this._playwright = options.preLaunchedAndroidDevice._android.attribution.playwright;
38
+ this._playwright ??= (0, import_playwright.createPlaywright)({ sdkLanguage: "javascript", isServer: true });
39
39
  const browserSemaphore = new import_semaphore.Semaphore(this._options.maxConnections);
40
40
  const controllerSemaphore = new import_semaphore.Semaphore(1);
41
41
  const reuseBrowserSemaphore = new import_semaphore.Semaphore(1);
@@ -75,10 +75,6 @@ ${uaError}` };
75
75
  } catch (e) {
76
76
  }
77
77
  const isExtension = this._options.mode === "extension";
78
- if (isExtension) {
79
- if (!this._preLaunchedPlaywright)
80
- this._preLaunchedPlaywright = (0, import_playwright.createPlaywright)({ sdkLanguage: "javascript", isServer: true });
81
- }
82
78
  let clientType = "launch-browser";
83
79
  let semaphore = browserSemaphore;
84
80
  if (isExtension && url.searchParams.has("debug-controller")) {
@@ -102,8 +98,8 @@ ${uaError}` };
102
98
  allowFSPaths: this._options.mode === "extension",
103
99
  sharedBrowser: this._options.mode === "launchServerShared"
104
100
  },
101
+ this._playwright,
105
102
  {
106
- playwright: this._preLaunchedPlaywright,
107
103
  browser: this._options.preLaunchedBrowser,
108
104
  androidDevice: this._options.preLaunchedAndroidDevice,
109
105
  socksProxy: this._options.preLaunchedSocksProxy
@@ -111,12 +107,6 @@ ${uaError}` };
111
107
  id,
112
108
  () => semaphore.release()
113
109
  );
114
- },
115
- onClose: async () => {
116
- import_debugLogger.debugLogger.log("server", "closing browsers");
117
- if (this._preLaunchedPlaywright)
118
- await Promise.all(this._preLaunchedPlaywright.allBrowsers().map((browser) => browser.close({ reason: "Playwright Server stopped" })));
119
- import_debugLogger.debugLogger.log("server", "closed browsers");
120
110
  }
121
111
  });
122
112
  }
@@ -130,12 +130,12 @@ class BidiChromium extends import_browserType.BrowserType {
130
130
  if (proxy) {
131
131
  const proxyURL = new URL(proxy.server);
132
132
  const isSocks = proxyURL.protocol === "socks5:";
133
- if (isSocks && !this.attribution.playwright.options.socksProxyPort) {
133
+ if (isSocks && !options.socksProxyPort) {
134
134
  chromeArguments.push(`--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE ${proxyURL.hostname}"`);
135
135
  }
136
136
  chromeArguments.push(`--proxy-server=${proxy.server}`);
137
137
  const proxyBypassRules = [];
138
- if (this.attribution.playwright.options.socksProxyPort)
138
+ if (options.socksProxyPort)
139
139
  proxyBypassRules.push("<-loopback>");
140
140
  if (proxy.bypass)
141
141
  proxyBypassRules.push(...proxy.bypass.split(",").map((t) => t.trim()).map((t) => t.startsWith(".") ? "*" + t : t));
@@ -45,6 +45,9 @@ class Browser extends import_instrumentation.SdkObject {
45
45
  Disconnected: "disconnected"
46
46
  };
47
47
  }
48
+ sdkLanguage() {
49
+ return this.options.sdkLanguage || this.attribution.playwright.options.sdkLanguage;
50
+ }
48
51
  async newContext(metadata, options) {
49
52
  (0, import_browserContext.validateBrowserContextOptions)(options, this.options);
50
53
  let clientCertificatesProxy;
@@ -265,8 +265,8 @@ class BrowserType extends import_instrumentation.SdkObject {
265
265
  headless = false;
266
266
  if (downloadsPath && !import_path.default.isAbsolute(downloadsPath))
267
267
  downloadsPath = import_path.default.join(process.cwd(), downloadsPath);
268
- if (this.attribution.playwright.options.socksProxyPort)
269
- proxy = { server: `socks5://127.0.0.1:${this.attribution.playwright.options.socksProxyPort}` };
268
+ if (options.socksProxyPort)
269
+ proxy = { server: `socks5://127.0.0.1:${options.socksProxyPort}` };
270
270
  return { ...options, devtools, headless, downloadsPath, proxy };
271
271
  }
272
272
  _createUserDataDirArgMisuseError(userDataDirArg) {
@@ -295,12 +295,12 @@ class Chromium extends import_browserType.BrowserType {
295
295
  if (proxy) {
296
296
  const proxyURL = new URL(proxy.server);
297
297
  const isSocks = proxyURL.protocol === "socks5:";
298
- if (isSocks && !this.attribution.playwright.options.socksProxyPort) {
298
+ if (isSocks && !options.socksProxyPort) {
299
299
  chromeArguments.push(`--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE ${proxyURL.hostname}"`);
300
300
  }
301
301
  chromeArguments.push(`--proxy-server=${proxy.server}`);
302
302
  const proxyBypassRules = [];
303
- if (this.attribution.playwright.options.socksProxyPort)
303
+ if (options.socksProxyPort)
304
304
  proxyBypassRules.push("<-loopback>");
305
305
  if (proxy.bypass)
306
306
  proxyBypassRules.push(...proxy.bypass.split(",").map((t) => t.trim()).map((t) => t.startsWith(".") ? "*" + t : t));
@@ -736,7 +736,7 @@ class FrameSession {
736
736
  }
737
737
  async _createVideoRecorder(screencastId, options) {
738
738
  (0, import_assert.assert)(!this._screencastId);
739
- const ffmpegPath = import_registry.registry.findExecutable("ffmpeg").executablePathOrDie(this._page.attribution.playwright.options.sdkLanguage);
739
+ const ffmpegPath = import_registry.registry.findExecutable("ffmpeg").executablePathOrDie(this._page.browserContext._browser.sdkLanguage());
740
740
  this._videoRecorder = await import_videoRecorder.VideoRecorder.launch(this._crPage._page, ffmpegPath, options);
741
741
  this._screencastId = screencastId;
742
742
  }
@@ -29,9 +29,10 @@ var import_android = require("../android/android");
29
29
  var import_eventsHelper = require("../utils/eventsHelper");
30
30
  var import_instrumentation = require("../instrumentation");
31
31
  class AndroidDispatcher extends import_dispatcher.Dispatcher {
32
- constructor(scope, android) {
32
+ constructor(scope, android, denyLaunch) {
33
33
  super(scope, android, "Android", {});
34
34
  this._type_Android = true;
35
+ this._denyLaunch = denyLaunch;
35
36
  }
36
37
  async devices(params) {
37
38
  const devices = await this._object.devices(params);
@@ -136,6 +137,8 @@ class AndroidDeviceDispatcher extends import_dispatcher.Dispatcher {
136
137
  await this._object.push(params.file, params.path, params.mode);
137
138
  }
138
139
  async launchBrowser(params) {
140
+ if (this.parentScope()._denyLaunch)
141
+ throw new Error(`Launching more browsers is not allowed.`);
139
142
  const context = await this._object.launchBrowser(params.pkg, params);
140
143
  return { context: import_browserContextDispatcher.BrowserContextDispatcher.from(this, context) };
141
144
  }
@@ -143,6 +146,8 @@ class AndroidDeviceDispatcher extends import_dispatcher.Dispatcher {
143
146
  await this._object.close();
144
147
  }
145
148
  async connectToWebView(params) {
149
+ if (this.parentScope()._denyLaunch)
150
+ throw new Error(`Launching more browsers is not allowed.`);
146
151
  return { context: import_browserContextDispatcher.BrowserContextDispatcher.from(this, await this._object.connectToWebView(params.socketName)) };
147
152
  }
148
153
  }
@@ -25,24 +25,31 @@ var import_browserContextDispatcher = require("./browserContextDispatcher");
25
25
  var import_browserDispatcher = require("./browserDispatcher");
26
26
  var import_dispatcher = require("./dispatcher");
27
27
  class BrowserTypeDispatcher extends import_dispatcher.Dispatcher {
28
- constructor(scope, browserType) {
28
+ constructor(scope, browserType, denyLaunch) {
29
29
  super(scope, browserType, "BrowserType", {
30
30
  executablePath: browserType.executablePath(),
31
31
  name: browserType.name()
32
32
  });
33
33
  this._type_BrowserType = true;
34
+ this._denyLaunch = denyLaunch;
34
35
  }
35
36
  async launch(params, metadata) {
37
+ if (this._denyLaunch)
38
+ throw new Error(`Launching more browsers is not allowed.`);
36
39
  const browser = await this._object.launch(metadata, params);
37
40
  return { browser: new import_browserDispatcher.BrowserDispatcher(this, browser) };
38
41
  }
39
42
  async launchPersistentContext(params, metadata) {
43
+ if (this._denyLaunch)
44
+ throw new Error(`Launching more browsers is not allowed.`);
40
45
  const browserContext = await this._object.launchPersistentContext(metadata, params.userDataDir, params);
41
46
  const browserDispatcher = new import_browserDispatcher.BrowserDispatcher(this, browserContext._browser);
42
47
  const contextDispatcher = import_browserContextDispatcher.BrowserContextDispatcher.from(browserDispatcher, browserContext);
43
48
  return { browser: browserDispatcher, context: contextDispatcher };
44
49
  }
45
50
  async connectOverCDP(params, metadata) {
51
+ if (this._denyLaunch)
52
+ throw new Error(`Launching more browsers is not allowed.`);
46
53
  const browser = await this._object.connectOverCDP(metadata, params.endpointURL, params);
47
54
  const browserDispatcher = new import_browserDispatcher.BrowserDispatcher(this, browser);
48
55
  return {
@@ -27,11 +27,14 @@ var import_dispatcher = require("./dispatcher");
27
27
  var import_jsHandleDispatcher = require("./jsHandleDispatcher");
28
28
  var import_electron = require("../electron/electron");
29
29
  class ElectronDispatcher extends import_dispatcher.Dispatcher {
30
- constructor(scope, electron) {
30
+ constructor(scope, electron, denyLaunch) {
31
31
  super(scope, electron, "Electron", {});
32
32
  this._type_Electron = true;
33
+ this._denyLaunch = denyLaunch;
33
34
  }
34
35
  async launch(params) {
36
+ if (this._denyLaunch)
37
+ throw new Error(`Launching more browsers is not allowed.`);
35
38
  const electronApplication = await this._object.launch(params);
36
39
  return { electronApplication: new ElectronApplicationDispatcher(this, electronApplication) };
37
40
  }
@@ -35,12 +35,13 @@ var import_instrumentation = require("../instrumentation");
35
35
  var import_eventsHelper = require("../utils/eventsHelper");
36
36
  class PlaywrightDispatcher extends import_dispatcher.Dispatcher {
37
37
  constructor(scope, playwright, options = {}) {
38
- const chromium = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.chromium);
39
- const firefox = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.firefox);
40
- const webkit = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.webkit);
41
- const bidiChromium = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidiChromium);
42
- const bidiFirefox = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidiFirefox);
43
- const android = new import_androidDispatcher.AndroidDispatcher(scope, playwright.android);
38
+ const denyLaunch = options.denyLaunch ?? false;
39
+ const chromium = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.chromium, denyLaunch);
40
+ const firefox = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.firefox, denyLaunch);
41
+ const webkit = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.webkit, denyLaunch);
42
+ const bidiChromium = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidiChromium, denyLaunch);
43
+ const bidiFirefox = new import_browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidiFirefox, denyLaunch);
44
+ const android = new import_androidDispatcher.AndroidDispatcher(scope, playwright.android, denyLaunch);
44
45
  const initializer = {
45
46
  chromium,
46
47
  firefox,
@@ -48,7 +49,7 @@ class PlaywrightDispatcher extends import_dispatcher.Dispatcher {
48
49
  bidiChromium,
49
50
  bidiFirefox,
50
51
  android,
51
- electron: new import_electronDispatcher.ElectronDispatcher(scope, playwright.electron),
52
+ electron: new import_electronDispatcher.ElectronDispatcher(scope, playwright.electron, denyLaunch),
52
53
  utils: playwright.options.isServer ? void 0 : new import_localUtilsDispatcher.LocalUtilsDispatcher(scope, playwright),
53
54
  socksSupport: options.socksProxy ? new SocksSupportDispatcher(scope, playwright, options.socksProxy) : void 0
54
55
  };
package/lib/server/dom.js CHANGED
@@ -79,7 +79,7 @@ class FrameExecutionContext extends js.ExecutionContext {
79
79
  const selectorsRegistry = this.frame._page.browserContext.selectors();
80
80
  for (const [name, { source: source2 }] of selectorsRegistry._engines)
81
81
  customEngines.push({ name, source: `(${source2})` });
82
- const sdkLanguage = this.frame.attribution.playwright.options.sdkLanguage;
82
+ const sdkLanguage = this.frame._page.browserContext._browser.sdkLanguage();
83
83
  const options = {
84
84
  isUnderTest: (0, import_utils.isUnderTest)(),
85
85
  sdkLanguage,
@@ -305,7 +305,7 @@ class ElementHandle extends js.JSHandle {
305
305
  }
306
306
  if (!options.skipActionPreChecks && !options.force)
307
307
  await this._frame._page.performActionPreChecks(progress);
308
- const result = await action();
308
+ const result = await action(retry);
309
309
  ++retry;
310
310
  if (result === "error:notvisible") {
311
311
  if (options.force)
@@ -336,21 +336,15 @@ class ElementHandle extends js.JSHandle {
336
336
  }
337
337
  async _retryPointerAction(progress, actionName, waitForEnabled, action, options) {
338
338
  const skipActionPreChecks = actionName === "move and up";
339
- const scrollOptions = [
340
- void 0,
341
- { block: "end", inline: "end" },
342
- { block: "center", inline: "center" },
343
- { block: "start", inline: "start" }
344
- ];
345
- let scrollOptionIndex = 0;
346
- return await this._retryAction(progress, actionName, async () => {
347
- const forceScrollOptions = scrollOptions[scrollOptionIndex % scrollOptions.length];
348
- const result = await this._performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options);
349
- if (typeof result === "object" && "hasPositionStickyOrFixed" in result && result.hasPositionStickyOrFixed)
350
- ++scrollOptionIndex;
351
- else
352
- scrollOptionIndex = 0;
353
- return result;
339
+ return await this._retryAction(progress, actionName, async (retry) => {
340
+ const scrollOptions = [
341
+ void 0,
342
+ { block: "end", inline: "end" },
343
+ { block: "center", inline: "center" },
344
+ { block: "start", inline: "start" }
345
+ ];
346
+ const forceScrollOptions = scrollOptions[retry % scrollOptions.length];
347
+ return await this._performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options);
354
348
  }, { ...options, skipActionPreChecks });
355
349
  }
356
350
  async _performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options) {
@@ -414,7 +408,7 @@ class ElementHandle extends js.JSHandle {
414
408
  const error = handle.rawValue();
415
409
  if (error === "error:notconnected")
416
410
  return error;
417
- return JSON.parse(error);
411
+ return { hitTargetDescription: error };
418
412
  }
419
413
  hitTargetInterceptionHandle = handle;
420
414
  progress.cleanupWhenAborted(() => {
@@ -102,7 +102,7 @@ class FrameSelectors {
102
102
  for (const chunk of frameChunks) {
103
103
  (0, import_selectorParser.visitAllSelectorParts)(chunk, (part, nested) => {
104
104
  if (nested && part.name === "internal:control" && part.body === "enter-frame") {
105
- const locator = (0, import_utils.asLocator)(this.frame._page.attribution.playwright.options.sdkLanguage, selector);
105
+ const locator = (0, import_utils.asLocator)(this.frame._page.browserContext._browser.sdkLanguage(), selector);
106
106
  throw new import_selectorParser.InvalidSelectorError(`Frame locators are not allowed inside composite locators, while querying "${locator}"`);
107
107
  }
108
108
  });
@@ -1434,7 +1434,7 @@ class Frame extends import_instrumentation.SdkObject {
1434
1434
  });
1435
1435
  }
1436
1436
  _asLocator(selector) {
1437
- return (0, import_utils.asLocator)(this._page.attribution.playwright.options.sdkLanguage, selector);
1437
+ return (0, import_utils.asLocator)(this._page.browserContext._browser.sdkLanguage(), selector);
1438
1438
  }
1439
1439
  }
1440
1440
  class SignalBarrier {
@@ -348,11 +348,11 @@ class Page extends import_instrumentation.SdkObject {
348
348
  }
349
349
  if (handler.resolved) {
350
350
  ++this._locatorHandlerRunningCounter;
351
- progress.log(` found ${(0, import_utils2.asLocator)(this.attribution.playwright.options.sdkLanguage, handler.selector)}, intercepting action to run the handler`);
351
+ progress.log(` found ${(0, import_utils2.asLocator)(this.browserContext._browser.sdkLanguage(), handler.selector)}, intercepting action to run the handler`);
352
352
  const promise = handler.resolved.then(async () => {
353
353
  progress.throwIfAborted();
354
354
  if (!handler.noWaitAfter) {
355
- progress.log(` locator handler has finished, waiting for ${(0, import_utils2.asLocator)(this.attribution.playwright.options.sdkLanguage, handler.selector)} to be hidden`);
355
+ progress.log(` locator handler has finished, waiting for ${(0, import_utils2.asLocator)(this.browserContext._browser.sdkLanguage(), handler.selector)} to be hidden`);
356
356
  await this.mainFrame().waitForSelectorInternal(progress, handler.selector, false, { state: "hidden" });
357
357
  } else {
358
358
  progress.log(` locator handler has finished`);
@@ -57,7 +57,7 @@ class ContextRecorder extends import_events.EventEmitter {
57
57
  this._params = params;
58
58
  this._delegate = delegate;
59
59
  this._recorderSources = [];
60
- const language = params.language || context.attribution.playwright.options.sdkLanguage;
60
+ const language = params.language || context._browser.sdkLanguage();
61
61
  this.setOutput(language, params.outputFile);
62
62
  const languageGeneratorOptions = {
63
63
  browserName: context._browser.options.name,
@@ -109,7 +109,7 @@ class RecorderApp extends import_events.EventEmitter {
109
109
  };
110
110
  }
111
111
  static async _open(recorder, inspectedContext) {
112
- const sdkLanguage = inspectedContext.attribution.playwright.options.sdkLanguage;
112
+ const sdkLanguage = inspectedContext._browser.sdkLanguage();
113
113
  const headed = !!inspectedContext._browser.options.headful;
114
114
  const recorderPlaywright = require("../playwright").createPlaywright({ sdkLanguage: "javascript", isInternalPlaywright: true });
115
115
  const { context, page } = await (0, import_launchApp2.launchApp)(recorderPlaywright.chromium, {
@@ -78,7 +78,7 @@ class Tracing extends import_instrumentation.SdkObject {
78
78
  platform: process.platform,
79
79
  wallTime: 0,
80
80
  monotonicTime: 0,
81
- sdkLanguage: context.attribution.playwright.options.sdkLanguage,
81
+ sdkLanguage: this._sdkLanguage(),
82
82
  testIdAttributeName,
83
83
  contextId: context.guid
84
84
  };
@@ -90,6 +90,9 @@ class Tracing extends import_instrumentation.SdkObject {
90
90
  this._contextCreatedEvent.options = context._options;
91
91
  }
92
92
  }
93
+ _sdkLanguage() {
94
+ return this._context instanceof import_browserContext.BrowserContext ? this._context._browser.sdkLanguage() : this._context.attribution.playwright.options.sdkLanguage;
95
+ }
93
96
  async resetForReuse() {
94
97
  await this.stopChunk({ mode: "discard" }).catch(() => {
95
98
  });
@@ -101,7 +104,7 @@ class Tracing extends import_instrumentation.SdkObject {
101
104
  throw new Error("Cannot start tracing while stopping");
102
105
  if (this._state)
103
106
  throw new Error("Tracing has been already started");
104
- this._contextCreatedEvent.sdkLanguage = this._context.attribution.playwright.options.sdkLanguage;
107
+ this._contextCreatedEvent.sdkLanguage = this._sdkLanguage();
105
108
  const traceName = options.name || (0, import_crypto.createGuid)();
106
109
  const tracesDir = this._createTracesDirIfNeeded();
107
110
  this._state = {
@@ -148,7 +148,6 @@ async function openTraceViewerApp(url, browserName, options) {
148
148
  const traceViewerPlaywright = (0, import_playwright.createPlaywright)({ sdkLanguage: "javascript", isInternalPlaywright: true });
149
149
  const traceViewerBrowser = (0, import_utils2.isUnderTest)() ? "chromium" : browserName;
150
150
  const { context, page } = await (0, import_launchApp2.launchApp)(traceViewerPlaywright[traceViewerBrowser], {
151
- // TODO: store language in the trace.
152
151
  sdkLanguage: traceViewerPlaywright.options.sdkLanguage,
153
152
  windowSize: { width: 1280, height: 800 },
154
153
  persistentContextOptions: {
@@ -112,7 +112,6 @@ class WSServer {
112
112
  this._wsServer = void 0;
113
113
  this.server = void 0;
114
114
  import_debugLogger.debugLogger.log("server", "closed server");
115
- await this._delegate.onClose?.();
116
115
  }
117
116
  }
118
117
  // Annotate the CommonJS export names for ESM import in node:
@@ -22,7 +22,7 @@ __export(protocolMetainfo_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(protocolMetainfo_exports);
24
24
  const methodMetainfo = /* @__PURE__ */ new Map([
25
- ["APIRequestContext.fetch", { title: 'Fetch "{url}"' }],
25
+ ["APIRequestContext.fetch", { title: '{method} "{url}"' }],
26
26
  ["APIRequestContext.fetchResponseBody", { internal: true }],
27
27
  ["APIRequestContext.fetchLog", { internal: true }],
28
28
  ["APIRequestContext.storageState", { internal: true }],