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

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 (38) hide show
  1. package/lib/client/playwright.js +2 -2
  2. package/lib/inProcessFactory.js +2 -2
  3. package/lib/protocol/validator.js +2 -2
  4. package/lib/remote/playwrightConnection.js +27 -168
  5. package/lib/remote/playwrightServer.js +173 -27
  6. package/lib/server/android/android.js +31 -25
  7. package/lib/server/bidi/bidiChromium.js +1 -1
  8. package/lib/server/bidi/bidiFirefox.js +4 -1
  9. package/lib/server/browser.js +13 -12
  10. package/lib/server/browserContext.js +49 -46
  11. package/lib/server/browserType.js +26 -19
  12. package/lib/server/chromium/chromium.js +9 -7
  13. package/lib/server/chromium/videoRecorder.js +2 -1
  14. package/lib/server/debugController.js +1 -1
  15. package/lib/server/dispatchers/androidDispatcher.js +4 -4
  16. package/lib/server/dispatchers/browserContextDispatcher.js +1 -1
  17. package/lib/server/dispatchers/browserDispatcher.js +2 -2
  18. package/lib/server/dispatchers/electronDispatcher.js +2 -2
  19. package/lib/server/dispatchers/frameDispatcher.js +1 -1
  20. package/lib/server/dispatchers/localUtilsDispatcher.js +1 -2
  21. package/lib/server/dispatchers/playwrightDispatcher.js +5 -21
  22. package/lib/server/dom.js +3 -4
  23. package/lib/server/electron/electron.js +15 -16
  24. package/lib/server/fetch.js +12 -26
  25. package/lib/server/firefox/ffPage.js +0 -1
  26. package/lib/server/frames.js +93 -92
  27. package/lib/server/helper.js +1 -1
  28. package/lib/server/page.js +48 -42
  29. package/lib/server/playwright.js +2 -2
  30. package/lib/server/recorder/recorderApp.js +1 -1
  31. package/lib/server/registry/index.js +7 -20
  32. package/lib/server/screenshotter.js +17 -31
  33. package/lib/server/socksClientCertificatesInterceptor.js +7 -3
  34. package/lib/server/trace/viewer/traceViewer.js +1 -1
  35. package/lib/server/transport.js +3 -7
  36. package/lib/server/utils/processLauncher.js +1 -1
  37. package/lib/vite/htmlReport/index.html +9 -9
  38. package/package.json +1 -1
@@ -43,9 +43,9 @@ class Playwright extends import_channelOwner.ChannelOwner {
43
43
  this._android._playwright = this;
44
44
  this._electron = import_electron.Electron.from(initializer.electron);
45
45
  this._electron._playwright = this;
46
- this._bidiChromium = import_browserType.BrowserType.from(initializer.bidiChromium);
46
+ this._bidiChromium = import_browserType.BrowserType.from(initializer._bidiChromium);
47
47
  this._bidiChromium._playwright = this;
48
- this._bidiFirefox = import_browserType.BrowserType.from(initializer.bidiFirefox);
48
+ this._bidiFirefox = import_browserType.BrowserType.from(initializer._bidiFirefox);
49
49
  this._bidiFirefox._playwright = this;
50
50
  this.devices = this._connection.localUtils()?.devices ?? {};
51
51
  this.selectors = new import_selectors.Selectors(this._connection._platform);
@@ -43,8 +43,8 @@ function createInProcessPlaywright() {
43
43
  playwrightAPI.firefox._serverLauncher = new import_browserServerImpl.BrowserServerLauncherImpl("firefox");
44
44
  playwrightAPI.webkit._serverLauncher = new import_browserServerImpl.BrowserServerLauncherImpl("webkit");
45
45
  playwrightAPI._android._serverLauncher = new import_androidServerImpl.AndroidServerLauncherImpl();
46
- playwrightAPI._bidiChromium._serverLauncher = new import_browserServerImpl.BrowserServerLauncherImpl("bidiChromium");
47
- playwrightAPI._bidiFirefox._serverLauncher = new import_browserServerImpl.BrowserServerLauncherImpl("bidiFirefox");
46
+ playwrightAPI._bidiChromium._serverLauncher = new import_browserServerImpl.BrowserServerLauncherImpl("_bidiChromium");
47
+ playwrightAPI._bidiFirefox._serverLauncher = new import_browserServerImpl.BrowserServerLauncherImpl("_bidiFirefox");
48
48
  dispatcherConnection.onmessage = (message) => setImmediate(() => clientConnection.dispatch(message));
49
49
  clientConnection.onmessage = (message) => setImmediate(() => dispatcherConnection.dispatch(message));
50
50
  clientConnection.toImpl = (x) => x ? dispatcherConnection._dispatcherByGuid.get(x._guid)._object : dispatcherConnection._dispatcherByGuid.get("");
@@ -382,8 +382,8 @@ import_validatorPrimitives.scheme.PlaywrightInitializer = (0, import_validatorPr
382
382
  chromium: (0, import_validatorPrimitives.tChannel)(["BrowserType"]),
383
383
  firefox: (0, import_validatorPrimitives.tChannel)(["BrowserType"]),
384
384
  webkit: (0, import_validatorPrimitives.tChannel)(["BrowserType"]),
385
- bidiChromium: (0, import_validatorPrimitives.tChannel)(["BrowserType"]),
386
- bidiFirefox: (0, import_validatorPrimitives.tChannel)(["BrowserType"]),
385
+ _bidiChromium: (0, import_validatorPrimitives.tChannel)(["BrowserType"]),
386
+ _bidiFirefox: (0, import_validatorPrimitives.tChannel)(["BrowserType"]),
387
387
  android: (0, import_validatorPrimitives.tChannel)(["Android"]),
388
388
  electron: (0, import_validatorPrimitives.tChannel)(["Electron"]),
389
389
  utils: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tChannel)(["LocalUtils"])),
@@ -21,31 +21,22 @@ __export(playwrightConnection_exports, {
21
21
  PlaywrightConnection: () => PlaywrightConnection
22
22
  });
23
23
  module.exports = __toCommonJS(playwrightConnection_exports);
24
- var import_socksProxy = require("../server/utils/socksProxy");
25
24
  var import_server = require("../server");
26
25
  var import_android = require("../server/android/android");
27
26
  var import_browser = require("../server/browser");
28
27
  var import_debugControllerDispatcher = require("../server/dispatchers/debugControllerDispatcher");
29
- var import_instrumentation = require("../server/instrumentation");
30
- var import_assert = require("../utils/isomorphic/assert");
31
- var import_debug = require("../server/utils/debug");
32
28
  var import_profiler = require("../server/utils/profiler");
33
29
  var import_utils = require("../utils");
34
30
  var import_debugLogger = require("../server/utils/debugLogger");
35
31
  class PlaywrightConnection {
36
- constructor(lock, clientType, ws, options, playwright, preLaunched, id, onClose) {
32
+ constructor(semaphore, ws, controller, playwright, initialize, id) {
37
33
  this._cleanups = [];
38
34
  this._disconnected = false;
39
35
  this._ws = ws;
40
- this._playwright = playwright;
41
- this._preLaunched = preLaunched;
42
- this._options = options;
43
- options.launchOptions = filterLaunchOptions(options.launchOptions, options.allowFSPaths);
44
- if (clientType === "pre-launched-browser-or-android")
45
- (0, import_assert.assert)(preLaunched.browser || preLaunched.androidDevice);
46
- this._onClose = onClose;
36
+ this._semaphore = semaphore;
47
37
  this._id = id;
48
- this._profileName = `${(/* @__PURE__ */ new Date()).toISOString()}-${clientType}`;
38
+ this._profileName = (/* @__PURE__ */ new Date()).toISOString();
39
+ const lock = this._semaphore.acquire();
49
40
  this._dispatcherConnection = new import_server.DispatcherConnection();
50
41
  this._dispatcherConnection.onmessage = async (message) => {
51
42
  await lock;
@@ -70,125 +61,33 @@ class PlaywrightConnection {
70
61
  });
71
62
  ws.on("close", () => this._onDisconnect());
72
63
  ws.on("error", (error) => this._onDisconnect(error));
73
- if (clientType === "controller") {
74
- this._root = this._initDebugControllerMode();
64
+ if (controller) {
65
+ import_debugLogger.debugLogger.log("server", `[${this._id}] engaged reuse controller mode`);
66
+ this._root = new import_debugControllerDispatcher.DebugControllerDispatcher(this._dispatcherConnection, playwright.debugController);
75
67
  return;
76
68
  }
77
- this._root = new import_server.RootDispatcher(this._dispatcherConnection, async (scope, options2) => {
69
+ this._root = new import_server.RootDispatcher(this._dispatcherConnection, async (scope, params) => {
78
70
  await (0, import_profiler.startProfiling)();
79
- if (clientType === "reuse-browser")
80
- return await this._initReuseBrowsersMode(scope, options2);
81
- if (clientType === "pre-launched-browser-or-android")
82
- return this._preLaunched.browser ? await this._initPreLaunchedBrowserMode(scope, options2) : await this._initPreLaunchedAndroidMode(scope);
83
- if (clientType === "launch-browser")
84
- return await this._initLaunchBrowserMode(scope, options2);
85
- throw new Error("Unsupported client type: " + clientType);
86
- });
87
- }
88
- async _initLaunchBrowserMode(scope, options) {
89
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged launch mode for "${this._options.browserName}"`);
90
- const ownedSocksProxy = await this._createOwnedSocksProxy();
91
- let browserName = this._options.browserName;
92
- if ("bidi" === browserName) {
93
- if (this._options.launchOptions?.channel?.toLocaleLowerCase().includes("firefox"))
94
- browserName = "bidiFirefox";
95
- else
96
- browserName = "bidiChromium";
97
- }
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" }));
101
- browser.on(import_browser.Browser.Events.Disconnected, () => {
102
- this.close({ code: 1001, reason: "Browser closed" });
103
- });
104
- return new import_server.PlaywrightDispatcher(scope, this._playwright, { socksProxy: ownedSocksProxy, preLaunchedBrowser: browser, denyLaunch: true });
105
- }
106
- async _initPreLaunchedBrowserMode(scope, options) {
107
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged pre-launched (browser) mode`);
108
- this._preLaunched.socksProxy?.setPattern(this._options.socksProxyPattern);
109
- const browser = this._preLaunched.browser;
110
- browser.options.sdkLanguage = options.sdkLanguage;
111
- browser.on(import_browser.Browser.Events.Disconnected, () => {
112
- this.close({ code: 1001, reason: "Browser closed" });
113
- });
114
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, this._playwright, {
115
- socksProxy: this._preLaunched.socksProxy,
116
- preLaunchedBrowser: browser,
117
- sharedBrowser: this._options.sharedBrowser,
118
- denyLaunch: true
119
- });
120
- for (const b of this._playwright.allBrowsers()) {
121
- if (b !== browser)
122
- await b.close({ reason: "Connection terminated" });
123
- }
124
- this._cleanups.push(() => playwrightDispatcher.cleanup());
125
- return playwrightDispatcher;
126
- }
127
- async _initPreLaunchedAndroidMode(scope) {
128
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged pre-launched (Android) mode`);
129
- const androidDevice = this._preLaunched.androidDevice;
130
- androidDevice.on(import_android.AndroidDevice.Events.Close, () => {
131
- this.close({ code: 1001, reason: "Android device disconnected" });
132
- });
133
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, this._playwright, { preLaunchedAndroidDevice: androidDevice, denyLaunch: true });
134
- this._cleanups.push(() => playwrightDispatcher.cleanup());
135
- return playwrightDispatcher;
136
- }
137
- _initDebugControllerMode() {
138
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged reuse controller mode`);
139
- return new import_debugControllerDispatcher.DebugControllerDispatcher(this._dispatcherConnection, this._playwright.debugController);
140
- }
141
- async _initReuseBrowsersMode(scope, options) {
142
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged reuse browsers mode for ${this._options.browserName}`);
143
- const requestedOptions = launchOptionsHash(this._options.launchOptions);
144
- let browser = this._playwright.allBrowsers().find((b) => {
145
- if (b.options.name !== this._options.browserName)
146
- return false;
147
- const existingOptions = launchOptionsHash(b.options.originalLaunchOptions);
148
- return existingOptions === requestedOptions;
149
- });
150
- for (const b of this._playwright.allBrowsers()) {
151
- if (b === browser)
152
- continue;
153
- if (b.options.name === this._options.browserName && b.options.channel === this._options.launchOptions.channel)
154
- await b.close({ reason: "Connection terminated" });
155
- }
156
- if (!browser) {
157
- browser = await this._playwright[this._options.browserName || "chromium"].launch((0, import_instrumentation.serverSideCallMetadata)(), {
158
- ...this._options.launchOptions,
159
- headless: !!process.env.PW_DEBUG_CONTROLLER_HEADLESS
160
- });
161
- browser.on(import_browser.Browser.Events.Disconnected, () => {
162
- this.close({ code: 1001, reason: "Browser closed" });
163
- });
164
- }
165
- browser.options.sdkLanguage = options.sdkLanguage;
166
- this._cleanups.push(async () => {
167
- for (const browser2 of this._playwright.allBrowsers()) {
168
- for (const context of browser2.contexts()) {
169
- if (!context.pages().length)
170
- await context.close({ reason: "Connection terminated" });
171
- else
172
- await context.stopPendingOperations("Connection closed");
173
- }
174
- if (!browser2.contexts())
175
- await browser2.close({ reason: "Connection terminated" });
71
+ const options = await initialize();
72
+ if (options.preLaunchedBrowser) {
73
+ const browser = options.preLaunchedBrowser;
74
+ browser.options.sdkLanguage = params.sdkLanguage;
75
+ browser.on(import_browser.Browser.Events.Disconnected, () => {
76
+ this.close({ code: 1001, reason: "Browser closed" });
77
+ });
78
+ }
79
+ if (options.preLaunchedAndroidDevice) {
80
+ const androidDevice = options.preLaunchedAndroidDevice;
81
+ androidDevice.on(import_android.AndroidDevice.Events.Close, () => {
82
+ this.close({ code: 1001, reason: "Android device disconnected" });
83
+ });
176
84
  }
85
+ if (options.dispose)
86
+ this._cleanups.push(options.dispose);
87
+ const dispatcher = new import_server.PlaywrightDispatcher(scope, playwright, options);
88
+ this._cleanups.push(() => dispatcher.cleanup());
89
+ return dispatcher;
177
90
  });
178
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, this._playwright, { preLaunchedBrowser: browser, denyLaunch: true });
179
- return playwrightDispatcher;
180
- }
181
- async _createOwnedSocksProxy() {
182
- if (!this._options.socksProxyPattern) {
183
- this._options.launchOptions.socksProxyPort = void 0;
184
- return;
185
- }
186
- const socksProxy = new import_socksProxy.SocksProxy();
187
- socksProxy.setPattern(this._options.socksProxyPattern);
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}`);
190
- this._cleanups.push(() => socksProxy.close());
191
- return socksProxy;
192
91
  }
193
92
  async _onDisconnect(error) {
194
93
  this._disconnected = true;
@@ -199,7 +98,7 @@ class PlaywrightConnection {
199
98
  await cleanup().catch(() => {
200
99
  });
201
100
  await (0, import_profiler.stopProfiling)(this._profileName);
202
- this._onClose();
101
+ this._semaphore.release();
203
102
  import_debugLogger.debugLogger.log("server", `[${this._id}] finished cleanup`);
204
103
  }
205
104
  logServerMetadata(message, messageString, direction) {
@@ -222,46 +121,6 @@ class PlaywrightConnection {
222
121
  }
223
122
  }
224
123
  }
225
- function launchOptionsHash(options) {
226
- const copy = { ...options };
227
- for (const k of Object.keys(copy)) {
228
- const key = k;
229
- if (copy[key] === defaultLaunchOptions[key])
230
- delete copy[key];
231
- }
232
- for (const key of optionsThatAllowBrowserReuse)
233
- delete copy[key];
234
- return JSON.stringify(copy);
235
- }
236
- function filterLaunchOptions(options, allowFSPaths) {
237
- return {
238
- channel: options.channel,
239
- args: options.args,
240
- ignoreAllDefaultArgs: options.ignoreAllDefaultArgs,
241
- ignoreDefaultArgs: options.ignoreDefaultArgs,
242
- timeout: options.timeout,
243
- headless: options.headless,
244
- proxy: options.proxy,
245
- chromiumSandbox: options.chromiumSandbox,
246
- firefoxUserPrefs: options.firefoxUserPrefs,
247
- slowMo: options.slowMo,
248
- executablePath: (0, import_debug.isUnderTest)() || allowFSPaths ? options.executablePath : void 0,
249
- downloadsPath: allowFSPaths ? options.downloadsPath : void 0
250
- };
251
- }
252
- const defaultLaunchOptions = {
253
- ignoreAllDefaultArgs: false,
254
- handleSIGINT: false,
255
- handleSIGTERM: false,
256
- handleSIGHUP: false,
257
- headless: true,
258
- devtools: false
259
- };
260
- const optionsThatAllowBrowserReuse = [
261
- "headless",
262
- "timeout",
263
- "tracesDir"
264
- ];
265
124
  // Annotate the CommonJS export names for ESM import in node:
266
125
  0 && (module.exports = {
267
126
  PlaywrightConnection
@@ -28,6 +28,9 @@ var import_time = require("../utils/isomorphic/time");
28
28
  var import_wsServer = require("../server/utils/wsServer");
29
29
  var import_ascii = require("../server/utils/ascii");
30
30
  var import_userAgent = require("../server/utils/userAgent");
31
+ var import_utils = require("../utils");
32
+ var import_server = require("../server");
33
+ var import_socksProxy = require("../server/utils/socksProxy");
31
34
  class PlaywrightServer {
32
35
  constructor(options) {
33
36
  this._options = options;
@@ -75,41 +78,144 @@ ${uaError}` };
75
78
  } catch (e) {
76
79
  }
77
80
  const isExtension = this._options.mode === "extension";
78
- let clientType = "launch-browser";
79
- let semaphore = browserSemaphore;
80
- if (isExtension && url.searchParams.has("debug-controller")) {
81
- clientType = "controller";
82
- semaphore = controllerSemaphore;
83
- } else if (isExtension) {
84
- clientType = "reuse-browser";
85
- semaphore = reuseBrowserSemaphore;
86
- } else if (this._options.mode === "launchServer" || this._options.mode === "launchServerShared") {
87
- clientType = "pre-launched-browser-or-android";
88
- semaphore = browserSemaphore;
81
+ const allowFSPaths = isExtension;
82
+ launchOptions = filterLaunchOptions(launchOptions, allowFSPaths);
83
+ if (isExtension) {
84
+ if (url.searchParams.has("debug-controller")) {
85
+ return new import_playwrightConnection.PlaywrightConnection(
86
+ controllerSemaphore,
87
+ ws,
88
+ true,
89
+ this._playwright,
90
+ async () => {
91
+ throw new Error("shouldnt be used");
92
+ },
93
+ id
94
+ );
95
+ }
96
+ return new import_playwrightConnection.PlaywrightConnection(
97
+ reuseBrowserSemaphore,
98
+ ws,
99
+ false,
100
+ this._playwright,
101
+ () => this._initReuseBrowsersMode(browserName, launchOptions, id),
102
+ id
103
+ );
104
+ }
105
+ if (this._options.mode === "launchServer" || this._options.mode === "launchServerShared") {
106
+ if (this._options.preLaunchedBrowser) {
107
+ return new import_playwrightConnection.PlaywrightConnection(
108
+ browserSemaphore,
109
+ ws,
110
+ false,
111
+ this._playwright,
112
+ () => this._initPreLaunchedBrowserMode(id),
113
+ id
114
+ );
115
+ }
116
+ return new import_playwrightConnection.PlaywrightConnection(
117
+ browserSemaphore,
118
+ ws,
119
+ false,
120
+ this._playwright,
121
+ () => this._initPreLaunchedAndroidMode(id),
122
+ id
123
+ );
89
124
  }
90
125
  return new import_playwrightConnection.PlaywrightConnection(
91
- semaphore.acquire(),
92
- clientType,
126
+ browserSemaphore,
93
127
  ws,
94
- {
95
- socksProxyPattern: proxyValue,
96
- browserName,
97
- launchOptions,
98
- allowFSPaths: this._options.mode === "extension",
99
- sharedBrowser: this._options.mode === "launchServerShared"
100
- },
128
+ false,
101
129
  this._playwright,
102
- {
103
- browser: this._options.preLaunchedBrowser,
104
- androidDevice: this._options.preLaunchedAndroidDevice,
105
- socksProxy: this._options.preLaunchedSocksProxy
106
- },
107
- id,
108
- () => semaphore.release()
130
+ () => this._initLaunchBrowserMode(browserName, proxyValue, launchOptions, id),
131
+ id
109
132
  );
110
133
  }
111
134
  });
112
135
  }
136
+ async _initReuseBrowsersMode(browserName, launchOptions, id) {
137
+ import_utils.debugLogger.log("server", `[${id}] engaged reuse browsers mode for ${browserName}`);
138
+ const requestedOptions = launchOptionsHash(launchOptions);
139
+ let browser = this._playwright.allBrowsers().find((b) => {
140
+ if (b.options.name !== browserName)
141
+ return false;
142
+ const existingOptions = launchOptionsHash(b.options.originalLaunchOptions);
143
+ return existingOptions === requestedOptions;
144
+ });
145
+ for (const b of this._playwright.allBrowsers()) {
146
+ if (b === browser)
147
+ continue;
148
+ if (b.options.name === browserName && b.options.channel === launchOptions.channel)
149
+ await b.close({ reason: "Connection terminated" });
150
+ }
151
+ if (!browser) {
152
+ browser = await this._playwright[browserName || "chromium"].launch((0, import_server.serverSideCallMetadata)(), {
153
+ ...launchOptions,
154
+ headless: !!process.env.PW_DEBUG_CONTROLLER_HEADLESS
155
+ });
156
+ }
157
+ return {
158
+ preLaunchedBrowser: browser,
159
+ denyLaunch: true,
160
+ dispose: async () => {
161
+ for (const browser2 of this._playwright.allBrowsers()) {
162
+ for (const context of browser2.contexts()) {
163
+ if (!context.pages().length)
164
+ await context.close({ reason: "Connection terminated" });
165
+ else
166
+ await context.stopPendingOperations("Connection closed");
167
+ }
168
+ if (!browser2.contexts())
169
+ await browser2.close({ reason: "Connection terminated" });
170
+ }
171
+ }
172
+ };
173
+ }
174
+ async _initPreLaunchedBrowserMode(id) {
175
+ import_utils.debugLogger.log("server", `[${id}] engaged pre-launched (browser) mode`);
176
+ const browser = this._options.preLaunchedBrowser;
177
+ for (const b of this._playwright.allBrowsers()) {
178
+ if (b !== browser)
179
+ await b.close({ reason: "Connection terminated" });
180
+ }
181
+ return {
182
+ preLaunchedBrowser: browser,
183
+ socksProxy: this._options.preLaunchedSocksProxy,
184
+ sharedBrowser: this._options.mode === "launchServerShared",
185
+ denyLaunch: true
186
+ };
187
+ }
188
+ async _initPreLaunchedAndroidMode(id) {
189
+ import_utils.debugLogger.log("server", `[${id}] engaged pre-launched (Android) mode`);
190
+ const androidDevice = this._options.preLaunchedAndroidDevice;
191
+ return {
192
+ preLaunchedAndroidDevice: androidDevice,
193
+ denyLaunch: true
194
+ };
195
+ }
196
+ async _initLaunchBrowserMode(browserName, proxyValue, launchOptions, id) {
197
+ import_utils.debugLogger.log("server", `[${id}] engaged launch mode for "${browserName}"`);
198
+ let socksProxy;
199
+ if (proxyValue) {
200
+ socksProxy = new import_socksProxy.SocksProxy();
201
+ socksProxy.setPattern(proxyValue);
202
+ launchOptions.socksProxyPort = await socksProxy.listen(0);
203
+ import_utils.debugLogger.log("server", `[${id}] started socks proxy on port ${launchOptions.socksProxyPort}`);
204
+ } else {
205
+ launchOptions.socksProxyPort = void 0;
206
+ }
207
+ const browser = await this._playwright[browserName].launch((0, import_server.serverSideCallMetadata)(), launchOptions);
208
+ return {
209
+ preLaunchedBrowser: browser,
210
+ socksProxy,
211
+ sharedBrowser: true,
212
+ denyLaunch: true,
213
+ dispose: async () => {
214
+ await browser.close({ reason: "Connection terminated" });
215
+ socksProxy?.close();
216
+ }
217
+ };
218
+ }
113
219
  async listen(port = 0, hostname) {
114
220
  return this._wsServer.listen(port, hostname, this._options.path);
115
221
  }
@@ -140,6 +246,46 @@ function userAgentVersionMatchesErrorMessage(userAgent) {
140
246
  ].join("\n"), 1);
141
247
  }
142
248
  }
249
+ function launchOptionsHash(options) {
250
+ const copy = { ...options };
251
+ for (const k of Object.keys(copy)) {
252
+ const key = k;
253
+ if (copy[key] === defaultLaunchOptions[key])
254
+ delete copy[key];
255
+ }
256
+ for (const key of optionsThatAllowBrowserReuse)
257
+ delete copy[key];
258
+ return JSON.stringify(copy);
259
+ }
260
+ function filterLaunchOptions(options, allowFSPaths) {
261
+ return {
262
+ channel: options.channel,
263
+ args: options.args,
264
+ ignoreAllDefaultArgs: options.ignoreAllDefaultArgs,
265
+ ignoreDefaultArgs: options.ignoreDefaultArgs,
266
+ timeout: options.timeout,
267
+ headless: options.headless,
268
+ proxy: options.proxy,
269
+ chromiumSandbox: options.chromiumSandbox,
270
+ firefoxUserPrefs: options.firefoxUserPrefs,
271
+ slowMo: options.slowMo,
272
+ executablePath: (0, import_utils.isUnderTest)() || allowFSPaths ? options.executablePath : void 0,
273
+ downloadsPath: allowFSPaths ? options.downloadsPath : void 0
274
+ };
275
+ }
276
+ const defaultLaunchOptions = {
277
+ ignoreAllDefaultArgs: false,
278
+ handleSIGINT: false,
279
+ handleSIGTERM: false,
280
+ handleSIGHUP: false,
281
+ headless: true,
282
+ devtools: false
283
+ };
284
+ const optionsThatAllowBrowserReuse = [
285
+ "headless",
286
+ "timeout",
287
+ "tracesDir"
288
+ ];
143
289
  // Annotate the CommonJS export names for ESM import in node:
144
290
  0 && (module.exports = {
145
291
  PlaywrightServer
@@ -93,6 +93,7 @@ class AndroidDevice extends import_instrumentation.SdkObject {
93
93
  this.model = model;
94
94
  this.serial = backend.serial;
95
95
  this._options = options;
96
+ this.logName = "browser";
96
97
  }
97
98
  static {
98
99
  this.Events = {
@@ -220,17 +221,20 @@ class AndroidDevice extends import_instrumentation.SdkObject {
220
221
  this._android._deviceClosed(this);
221
222
  this.emit(AndroidDevice.Events.Close);
222
223
  }
223
- async launchBrowser(pkg = "com.android.chrome", options) {
224
- (0, import_utilsBundle.debug)("pw:android")("Force-stopping", pkg);
225
- await this._backend.runCommand(`shell:am force-stop ${pkg}`);
226
- const socketName = (0, import_debug.isUnderTest)() ? "webview_devtools_remote_playwright_test" : "playwright_" + (0, import_crypto.createGuid)() + "_devtools_remote";
227
- const commandLine = this._defaultArgs(options, socketName).join(" ");
228
- (0, import_utilsBundle.debug)("pw:android")("Starting", pkg, commandLine);
229
- await this._backend.runCommand(`shell:echo "${Buffer.from(commandLine).toString("base64")}" | base64 -d > /data/local/tmp/chrome-command-line`);
230
- await this._backend.runCommand(`shell:am start -a android.intent.action.VIEW -d about:blank ${pkg}`);
231
- const browserContext = await this._connectToBrowser(socketName, options);
232
- await this._backend.runCommand(`shell:rm /data/local/tmp/chrome-command-line`);
233
- return browserContext;
224
+ async launchBrowser(metadata, pkg = "com.android.chrome", options) {
225
+ const controller = new import_progress.ProgressController(metadata, this, "strict");
226
+ return controller.run(async (progress) => {
227
+ (0, import_utilsBundle.debug)("pw:android")("Force-stopping", pkg);
228
+ await this._backend.runCommand(`shell:am force-stop ${pkg}`);
229
+ const socketName = (0, import_debug.isUnderTest)() ? "webview_devtools_remote_playwright_test" : "playwright_" + (0, import_crypto.createGuid)() + "_devtools_remote";
230
+ const commandLine = this._defaultArgs(options, socketName).join(" ");
231
+ (0, import_utilsBundle.debug)("pw:android")("Starting", pkg, commandLine);
232
+ await progress.race(this._backend.runCommand(`shell:echo "${Buffer.from(commandLine).toString("base64")}" | base64 -d > /data/local/tmp/chrome-command-line`));
233
+ await progress.race(this._backend.runCommand(`shell:am start -a android.intent.action.VIEW -d about:blank ${pkg}`));
234
+ const browserContext = await this._connectToBrowser(progress, socketName, options);
235
+ await progress.race(this._backend.runCommand(`shell:rm /data/local/tmp/chrome-command-line`));
236
+ return browserContext;
237
+ });
234
238
  }
235
239
  _defaultArgs(options, socketName) {
236
240
  const chromeArguments = [
@@ -259,23 +263,28 @@ class AndroidDevice extends import_instrumentation.SdkObject {
259
263
  chromeArguments.push(...args);
260
264
  return chromeArguments;
261
265
  }
262
- async connectToWebView(socketName) {
263
- const webView = this._webViews.get(socketName);
264
- if (!webView)
265
- throw new Error("WebView has been closed");
266
- return await this._connectToBrowser(socketName);
266
+ async connectToWebView(metadata, socketName) {
267
+ const controller = new import_progress.ProgressController(metadata, this, "strict");
268
+ return controller.run(async (progress) => {
269
+ const webView = this._webViews.get(socketName);
270
+ if (!webView)
271
+ throw new Error("WebView has been closed");
272
+ return await this._connectToBrowser(progress, socketName);
273
+ });
267
274
  }
268
- async _connectToBrowser(socketName, options = {}) {
269
- const socket = await this._waitForLocalAbstract(socketName);
275
+ async _connectToBrowser(progress, socketName, options = {}) {
276
+ const socket = await progress.race(this._waitForLocalAbstract(socketName));
270
277
  const androidBrowser = new AndroidBrowser(this, socket);
271
- await androidBrowser._init();
278
+ progress.cleanupWhenAborted(() => androidBrowser.close());
279
+ await progress.race(androidBrowser._init());
272
280
  this._browserConnections.add(androidBrowser);
273
- const artifactsDir = await import_fs.default.promises.mkdtemp(ARTIFACTS_FOLDER);
281
+ const artifactsDir = await progress.race(import_fs.default.promises.mkdtemp(ARTIFACTS_FOLDER));
274
282
  const cleanupArtifactsDir = async () => {
275
283
  const errors = (await (0, import_fileUtils.removeFolders)([artifactsDir])).filter(Boolean);
276
284
  for (let i = 0; i < (errors || []).length; ++i)
277
285
  (0, import_utilsBundle.debug)("pw:android")(`exception while removing ${artifactsDir}: ${errors[i]}`);
278
286
  };
287
+ progress.cleanupWhenAborted(cleanupArtifactsDir);
279
288
  import_processLauncher.gracefullyCloseSet.add(cleanupArtifactsDir);
280
289
  socket.on("close", async () => {
281
290
  import_processLauncher.gracefullyCloseSet.delete(cleanupArtifactsDir);
@@ -296,12 +305,9 @@ class AndroidDevice extends import_instrumentation.SdkObject {
296
305
  originalLaunchOptions: { timeout: 0 }
297
306
  };
298
307
  (0, import_browserContext.validateBrowserContextOptions)(options, browserOptions);
299
- const browser = await import_crBrowser.CRBrowser.connect(this.attribution.playwright, androidBrowser, browserOptions);
300
- const controller = new import_progress.ProgressController((0, import_instrumentation.serverSideCallMetadata)(), this);
308
+ const browser = await progress.race(import_crBrowser.CRBrowser.connect(this.attribution.playwright, androidBrowser, browserOptions));
301
309
  const defaultContext = browser._defaultContext;
302
- await controller.run(async (progress) => {
303
- await defaultContext._loadDefaultContextAsIs(progress);
304
- });
310
+ await defaultContext._loadDefaultContextAsIs(progress);
305
311
  return defaultContext;
306
312
  }
307
313
  webViews() {
@@ -40,7 +40,7 @@ var import_chromiumSwitches = require("../chromium/chromiumSwitches");
40
40
  var import_chromium = require("../chromium/chromium");
41
41
  class BidiChromium extends import_browserType.BrowserType {
42
42
  constructor(parent) {
43
- super(parent, "bidi");
43
+ super(parent, "_bidiChromium");
44
44
  }
45
45
  async connectToTransport(transport, options, browserLogsCollector) {
46
46
  const bidiTransport = await require("./bidiOverCdp").connectBidiOverCdp(transport);
@@ -41,7 +41,10 @@ var import_firefoxPrefs = require("./third_party/firefoxPrefs");
41
41
  var import_manualPromise = require("../../utils/isomorphic/manualPromise");
42
42
  class BidiFirefox extends import_browserType.BrowserType {
43
43
  constructor(parent) {
44
- super(parent, "bidi");
44
+ super(parent, "_bidiFirefox");
45
+ }
46
+ executablePath() {
47
+ return "";
45
48
  }
46
49
  async connectToTransport(transport, options) {
47
50
  return import_bidiBrowser.BidiBrowser.connect(this.attribution.playwright, transport, options);