playwright-core 1.55.0-alpha-2025-07-29 → 1.55.0-alpha-2025-07-30
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.
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- package/lib/protocol/validator.js +0 -16
- package/lib/server/android/android.js +54 -43
- package/lib/server/bidi/bidiPage.js +4 -0
- package/lib/server/browser.js +22 -18
- package/lib/server/browserContext.js +73 -46
- package/lib/server/browserType.js +67 -48
- package/lib/server/chromium/chromium.js +34 -28
- package/lib/server/chromium/crCoverage.js +3 -4
- package/lib/server/chromium/videoRecorder.js +10 -19
- package/lib/server/codegen/jsonl.js +2 -1
- package/lib/server/debugController.js +2 -18
- package/lib/server/dispatchers/debugControllerDispatcher.js +0 -9
- package/lib/server/dispatchers/localUtilsDispatcher.js +0 -5
- package/lib/server/frames.js +6 -6
- package/lib/server/localUtils.js +12 -7
- package/lib/server/playwright.js +0 -4
- package/lib/server/progress.js +17 -11
- package/lib/server/recorder/recorderUtils.js +5 -0
- package/lib/server/recorder.js +61 -1
- package/lib/server/socksClientCertificatesInterceptor.js +21 -6
- package/lib/server/utils/processLauncher.js +4 -1
- package/lib/utils/isomorphic/ariaSnapshot.js +58 -4
- package/lib/utils/isomorphic/protocolMetainfo.js +1 -5
- package/lib/utils/isomorphic/urlMatch.js +0 -2
- package/lib/vite/htmlReport/index.html +16 -16
- package/lib/vite/recorder/assets/{codeMirrorModule-cgtwtYOb.js → codeMirrorModule-BAFWw0fz.js} +1 -1
- package/lib/vite/recorder/assets/{index-KWWSfrzB.js → index-DyMqECqY.js} +28 -28
- package/lib/vite/recorder/index.html +1 -1
- package/lib/vite/traceViewer/assets/{codeMirrorModule-k_7BpzGX.js → codeMirrorModule-BOjqK4ng.js} +1 -1
- package/lib/vite/traceViewer/assets/{defaultSettingsView-CKM53V_K.js → defaultSettingsView-B-LNxb2i.js} +103 -103
- package/lib/vite/traceViewer/{index.CCXGYfh2.js → index.CWlPEVCA.js} +1 -1
- package/lib/vite/traceViewer/index.html +2 -2
- package/lib/vite/traceViewer/{uiMode.CNa3x5Xj.js → uiMode.NUAVc1od.js} +1 -1
- package/lib/vite/traceViewer/uiMode.html +2 -2
- package/package.json +1 -1
|
@@ -258,10 +258,14 @@ if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { co
|
|
|
258
258
|
const binding = new import_page2.PageBinding(name, playwrightBinding, needsHandle);
|
|
259
259
|
binding.forClient = forClient;
|
|
260
260
|
this._pageBindings.set(name, binding);
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
261
|
+
try {
|
|
262
|
+
await progress.race(this.doAddInitScript(binding.initScript));
|
|
263
|
+
await progress.race(this.safeNonStallingEvaluateInAllFrames(binding.initScript.source, "main"));
|
|
264
|
+
return binding;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
this._pageBindings.delete(name);
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
265
269
|
}
|
|
266
270
|
async removeExposedBindings(bindings) {
|
|
267
271
|
bindings = bindings.filter((binding) => this._pageBindings.get(binding.name) === binding);
|
|
@@ -291,20 +295,26 @@ if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { co
|
|
|
291
295
|
async setExtraHTTPHeaders(progress, headers) {
|
|
292
296
|
const oldHeaders = this._options.extraHTTPHeaders;
|
|
293
297
|
this._options.extraHTTPHeaders = headers;
|
|
294
|
-
|
|
298
|
+
try {
|
|
299
|
+
await progress.race(this.doUpdateExtraHTTPHeaders());
|
|
300
|
+
} catch (error) {
|
|
295
301
|
this._options.extraHTTPHeaders = oldHeaders;
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
302
|
+
this.doUpdateExtraHTTPHeaders().catch(() => {
|
|
303
|
+
});
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
299
306
|
}
|
|
300
307
|
async setOffline(progress, offline) {
|
|
301
308
|
const oldOffline = this._options.offline;
|
|
302
309
|
this._options.offline = offline;
|
|
303
|
-
|
|
310
|
+
try {
|
|
311
|
+
await progress.race(this.doUpdateOffline());
|
|
312
|
+
} catch (error) {
|
|
304
313
|
this._options.offline = oldOffline;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
314
|
+
this.doUpdateOffline().catch(() => {
|
|
315
|
+
});
|
|
316
|
+
throw error;
|
|
317
|
+
}
|
|
308
318
|
}
|
|
309
319
|
async _loadDefaultContextAsIs(progress) {
|
|
310
320
|
if (!this.possiblyUninitializedPages().length) {
|
|
@@ -353,13 +363,18 @@ if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { co
|
|
|
353
363
|
async addInitScript(progress, source) {
|
|
354
364
|
const initScript = new import_page.InitScript(source);
|
|
355
365
|
this.initScripts.push(initScript);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
366
|
+
try {
|
|
367
|
+
const promise = this.doAddInitScript(initScript);
|
|
368
|
+
if (progress)
|
|
369
|
+
await progress.race(promise);
|
|
370
|
+
else
|
|
371
|
+
await promise;
|
|
372
|
+
return initScript;
|
|
373
|
+
} catch (error) {
|
|
374
|
+
this.removeInitScripts([initScript]).catch(() => {
|
|
375
|
+
});
|
|
376
|
+
throw error;
|
|
377
|
+
}
|
|
363
378
|
}
|
|
364
379
|
async removeInitScripts(initScripts) {
|
|
365
380
|
const set = new Set(initScripts);
|
|
@@ -419,14 +434,20 @@ if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { co
|
|
|
419
434
|
await this._closePromise;
|
|
420
435
|
}
|
|
421
436
|
async newPage(progress, isServerSide) {
|
|
422
|
-
const page = await progress.
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
if (pageOrError.
|
|
426
|
-
|
|
427
|
-
|
|
437
|
+
const page = await progress.race(this.doCreateNewPage(isServerSide));
|
|
438
|
+
try {
|
|
439
|
+
const pageOrError = await progress.race(page.waitForInitializedOrError());
|
|
440
|
+
if (pageOrError instanceof import_page2.Page) {
|
|
441
|
+
if (pageOrError.isClosed())
|
|
442
|
+
throw new Error("Page has been closed.");
|
|
443
|
+
return pageOrError;
|
|
444
|
+
}
|
|
445
|
+
throw pageOrError;
|
|
446
|
+
} catch (error) {
|
|
447
|
+
await page.close({ reason: "Failed to create page" }).catch(() => {
|
|
448
|
+
});
|
|
449
|
+
throw error;
|
|
428
450
|
}
|
|
429
|
-
throw pageOrError;
|
|
430
451
|
}
|
|
431
452
|
addVisitedOrigin(origin) {
|
|
432
453
|
this._origins.add(origin);
|
|
@@ -457,18 +478,21 @@ if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { co
|
|
|
457
478
|
}
|
|
458
479
|
if (originsToSave.size) {
|
|
459
480
|
const page = await this.newPage(progress, true);
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
481
|
+
try {
|
|
482
|
+
await page.addRequestInterceptor(progress, (route) => {
|
|
483
|
+
route.fulfill({ body: "<html></html>" }).catch(() => {
|
|
484
|
+
});
|
|
485
|
+
}, "prepend");
|
|
486
|
+
for (const origin of originsToSave) {
|
|
487
|
+
const frame = page.mainFrame();
|
|
488
|
+
await frame.gotoImpl(progress, origin, {});
|
|
489
|
+
const storage = await progress.race(frame.evaluateExpression(collectScript, { world: "utility" }));
|
|
490
|
+
if (storage.localStorage.length || storage.indexedDB?.length)
|
|
491
|
+
result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB });
|
|
492
|
+
}
|
|
493
|
+
} finally {
|
|
494
|
+
await page.close();
|
|
470
495
|
}
|
|
471
|
-
await page.close();
|
|
472
496
|
}
|
|
473
497
|
return result;
|
|
474
498
|
}
|
|
@@ -483,26 +507,29 @@ if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { co
|
|
|
483
507
|
route.fulfill({ body: "<html></html>" }).catch(() => {
|
|
484
508
|
});
|
|
485
509
|
};
|
|
486
|
-
progress.cleanupWhenAborted(() => page.removeRequestInterceptor(interceptor));
|
|
487
510
|
await page.addRequestInterceptor(progress, interceptor, "prepend");
|
|
488
|
-
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
511
|
+
try {
|
|
512
|
+
for (const origin of /* @__PURE__ */ new Set([...oldOrigins, ...newOrigins.keys()])) {
|
|
513
|
+
const frame = page.mainFrame();
|
|
514
|
+
await frame.gotoImpl(progress, origin, {});
|
|
515
|
+
await progress.race(frame.resetStorageForCurrentOriginBestEffort(newOrigins.get(origin)));
|
|
516
|
+
}
|
|
517
|
+
this._origins = /* @__PURE__ */ new Set([...newOrigins.keys()]);
|
|
518
|
+
} finally {
|
|
519
|
+
await page.removeRequestInterceptor(interceptor);
|
|
492
520
|
}
|
|
493
|
-
await page.removeRequestInterceptor(interceptor);
|
|
494
|
-
this._origins = /* @__PURE__ */ new Set([...newOrigins.keys()]);
|
|
495
521
|
}
|
|
496
522
|
isSettingStorageState() {
|
|
497
523
|
return this._settingStorageState;
|
|
498
524
|
}
|
|
499
525
|
async setStorageState(progress, state) {
|
|
526
|
+
let page;
|
|
500
527
|
this._settingStorageState = true;
|
|
501
528
|
try {
|
|
502
529
|
if (state.cookies)
|
|
503
530
|
await progress.race(this.addCookies(state.cookies));
|
|
504
531
|
if (state.origins && state.origins.length) {
|
|
505
|
-
|
|
532
|
+
page = await this.newPage(progress, true);
|
|
506
533
|
await page.addRequestInterceptor(progress, (route) => {
|
|
507
534
|
route.fulfill({ body: "<html></html>" }).catch(() => {
|
|
508
535
|
});
|
|
@@ -518,13 +545,13 @@ if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { co
|
|
|
518
545
|
})()`;
|
|
519
546
|
await progress.race(frame.evaluateExpression(restoreScript, { world: "utility" }));
|
|
520
547
|
}
|
|
521
|
-
await page.close();
|
|
522
548
|
}
|
|
523
549
|
} catch (error) {
|
|
524
550
|
(0, import_stackTrace.rewriteErrorMessage)(error, `Error setting storage state:
|
|
525
551
|
` + error.message);
|
|
526
552
|
throw error;
|
|
527
553
|
} finally {
|
|
554
|
+
await page?.close();
|
|
528
555
|
this._settingStorageState = false;
|
|
529
556
|
}
|
|
530
557
|
}
|
|
@@ -77,16 +77,22 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
77
77
|
const launchOptions = this._validateLaunchOptions(options);
|
|
78
78
|
let clientCertificatesProxy;
|
|
79
79
|
if (options.clientCertificates?.length) {
|
|
80
|
-
clientCertificatesProxy = await
|
|
80
|
+
clientCertificatesProxy = await import_socksClientCertificatesInterceptor.ClientCertificatesProxy.create(progress, options);
|
|
81
81
|
launchOptions.proxyOverride = clientCertificatesProxy.proxySettings();
|
|
82
82
|
options = { ...options };
|
|
83
83
|
options.internalIgnoreHTTPSErrors = true;
|
|
84
84
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
try {
|
|
86
|
+
const browser = await this._innerLaunchWithRetries(progress, launchOptions, options, import_helper.helper.debugProtocolLogger(), userDataDir).catch((e) => {
|
|
87
|
+
throw this._rewriteStartupLog(e);
|
|
88
|
+
});
|
|
89
|
+
browser._defaultContext._clientCertificatesProxy = clientCertificatesProxy;
|
|
90
|
+
return browser._defaultContext;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
await clientCertificatesProxy?.close().catch(() => {
|
|
93
|
+
});
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
90
96
|
}
|
|
91
97
|
async _innerLaunchWithRetries(progress, options, persistent, protocolLogger, userDataDir) {
|
|
92
98
|
try {
|
|
@@ -104,34 +110,40 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
104
110
|
options.proxy = options.proxy ? (0, import_browserContext.normalizeProxySettings)(options.proxy) : void 0;
|
|
105
111
|
const browserLogsCollector = new import_debugLogger.RecentLogsCollector();
|
|
106
112
|
const { browserProcess, userDataDir, artifactsDir, transport } = await this._launchProcess(progress, options, !!persistent, browserLogsCollector, maybeUserDataDir);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
113
|
+
try {
|
|
114
|
+
if (options.__testHookBeforeCreateBrowser)
|
|
115
|
+
await progress.race(options.__testHookBeforeCreateBrowser());
|
|
116
|
+
const browserOptions = {
|
|
117
|
+
name: this._name,
|
|
118
|
+
isChromium: this._name === "chromium",
|
|
119
|
+
channel: options.channel,
|
|
120
|
+
slowMo: options.slowMo,
|
|
121
|
+
persistent,
|
|
122
|
+
headful: !options.headless,
|
|
123
|
+
artifactsDir,
|
|
124
|
+
downloadsPath: options.downloadsPath || artifactsDir,
|
|
125
|
+
tracesDir: options.tracesDir || artifactsDir,
|
|
126
|
+
browserProcess,
|
|
127
|
+
customExecutablePath: options.executablePath,
|
|
128
|
+
proxy: options.proxy,
|
|
129
|
+
protocolLogger,
|
|
130
|
+
browserLogsCollector,
|
|
131
|
+
wsEndpoint: transport instanceof import_transport.WebSocketTransport ? transport.wsEndpoint : void 0,
|
|
132
|
+
originalLaunchOptions: options
|
|
133
|
+
};
|
|
134
|
+
if (persistent)
|
|
135
|
+
(0, import_browserContext.validateBrowserContextOptions)(persistent, browserOptions);
|
|
136
|
+
copyTestHooks(options, browserOptions);
|
|
137
|
+
const browser = await progress.race(this.connectToTransport(transport, browserOptions, browserLogsCollector));
|
|
138
|
+
browser._userDataDirForTest = userDataDir;
|
|
139
|
+
if (persistent && !options.ignoreAllDefaultArgs)
|
|
140
|
+
await browser._defaultContext._loadDefaultContext(progress);
|
|
141
|
+
return browser;
|
|
142
|
+
} catch (error) {
|
|
143
|
+
await browserProcess.close().catch(() => {
|
|
144
|
+
});
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
135
147
|
}
|
|
136
148
|
async _prepareToLaunch(options, isPersistent, userDataDir) {
|
|
137
149
|
const {
|
|
@@ -182,7 +194,6 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
182
194
|
} = options;
|
|
183
195
|
const env = options.env ? (0, import_processLauncher.envArrayToObject)(options.env) : process.env;
|
|
184
196
|
const prepared = await progress.race(this._prepareToLaunch(options, isPersistent, userDataDir));
|
|
185
|
-
progress.cleanupWhenAborted(() => (0, import_fileUtils.removeFolders)(prepared.tempDirectories));
|
|
186
197
|
let transport = void 0;
|
|
187
198
|
let browserProcess = void 0;
|
|
188
199
|
const exitPromise = new import_manualPromise.ManualPromise();
|
|
@@ -202,7 +213,11 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
202
213
|
attemptToGracefullyClose: async () => {
|
|
203
214
|
if (options.__testHookGracefullyClose)
|
|
204
215
|
await options.__testHookGracefullyClose();
|
|
205
|
-
|
|
216
|
+
if (transport) {
|
|
217
|
+
this.attemptToGracefullyCloseBrowser(transport);
|
|
218
|
+
} else {
|
|
219
|
+
throw new Error("Force-killing the browser because no transport is available to gracefully close it.");
|
|
220
|
+
}
|
|
206
221
|
},
|
|
207
222
|
onExit: (exitCode, signal) => {
|
|
208
223
|
exitPromise.resolve();
|
|
@@ -230,19 +245,23 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
230
245
|
close: () => closeOrKill(options.__testHookBrowserCloseTimeout || import_time.DEFAULT_PLAYWRIGHT_TIMEOUT),
|
|
231
246
|
kill
|
|
232
247
|
};
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
248
|
+
try {
|
|
249
|
+
const { wsEndpoint } = await progress.race([
|
|
250
|
+
this.waitForReadyState(options, browserLogsCollector),
|
|
251
|
+
exitPromise.then(() => ({ wsEndpoint: void 0 }))
|
|
252
|
+
]);
|
|
253
|
+
if (options.cdpPort !== void 0 || !this.supportsPipeTransport()) {
|
|
254
|
+
transport = await import_transport.WebSocketTransport.connect(progress, wsEndpoint);
|
|
255
|
+
} else {
|
|
256
|
+
const stdio = launchedProcess.stdio;
|
|
257
|
+
transport = new import_pipeTransport.PipeTransport(stdio[3], stdio[4]);
|
|
258
|
+
}
|
|
259
|
+
return { browserProcess, artifactsDir: prepared.artifactsDir, userDataDir: prepared.userDataDir, transport };
|
|
260
|
+
} catch (error) {
|
|
261
|
+
await closeOrKill(import_time.DEFAULT_PLAYWRIGHT_TIMEOUT).catch(() => {
|
|
262
|
+
});
|
|
263
|
+
throw error;
|
|
243
264
|
}
|
|
244
|
-
progress.cleanupWhenAborted(() => transport.close());
|
|
245
|
-
return { browserProcess, artifactsDir: prepared.artifactsDir, userDataDir: prepared.userDataDir, transport };
|
|
246
265
|
}
|
|
247
266
|
async _createArtifactDirs(options) {
|
|
248
267
|
if (options.downloadsPath)
|
|
@@ -72,39 +72,45 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
72
72
|
else if (headersMap && !Object.keys(headersMap).some((key) => key.toLowerCase() === "user-agent"))
|
|
73
73
|
headersMap["User-Agent"] = (0, import_userAgent.getUserAgent)();
|
|
74
74
|
const artifactsDir = await progress.race(import_fs.default.promises.mkdtemp(ARTIFACTS_FOLDER));
|
|
75
|
-
const wsEndpoint = await urlToWSEndpoint(progress, endpointURL, headersMap);
|
|
76
|
-
const chromeTransport = await import_transport.WebSocketTransport.connect(progress, wsEndpoint, { headers: headersMap });
|
|
77
|
-
progress.cleanupWhenAborted(() => chromeTransport.close());
|
|
78
|
-
const cleanedUp = new import_manualPromise.ManualPromise();
|
|
79
75
|
const doCleanup = async () => {
|
|
80
76
|
await (0, import_fileUtils.removeFolders)([artifactsDir]);
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
const cb = onClose;
|
|
78
|
+
onClose = void 0;
|
|
79
|
+
await cb?.();
|
|
83
80
|
};
|
|
81
|
+
let chromeTransport;
|
|
84
82
|
const doClose = async () => {
|
|
85
|
-
await chromeTransport
|
|
86
|
-
await
|
|
83
|
+
await chromeTransport?.closeAndWait();
|
|
84
|
+
await doCleanup();
|
|
87
85
|
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
86
|
+
try {
|
|
87
|
+
const wsEndpoint = await urlToWSEndpoint(progress, endpointURL, headersMap);
|
|
88
|
+
chromeTransport = await import_transport.WebSocketTransport.connect(progress, wsEndpoint, { headers: headersMap });
|
|
89
|
+
const browserProcess = { close: doClose, kill: doClose };
|
|
90
|
+
const persistent = { noDefaultViewport: true };
|
|
91
|
+
const browserOptions = {
|
|
92
|
+
slowMo: options.slowMo,
|
|
93
|
+
name: "chromium",
|
|
94
|
+
isChromium: true,
|
|
95
|
+
persistent,
|
|
96
|
+
browserProcess,
|
|
97
|
+
protocolLogger: import_helper.helper.debugProtocolLogger(),
|
|
98
|
+
browserLogsCollector: new import_debugLogger.RecentLogsCollector(),
|
|
99
|
+
artifactsDir,
|
|
100
|
+
downloadsPath: options.downloadsPath || artifactsDir,
|
|
101
|
+
tracesDir: options.tracesDir || artifactsDir,
|
|
102
|
+
originalLaunchOptions: {}
|
|
103
|
+
};
|
|
104
|
+
(0, import_browserContext.validateBrowserContextOptions)(persistent, browserOptions);
|
|
105
|
+
const browser = await progress.race(import_crBrowser.CRBrowser.connect(this.attribution.playwright, chromeTransport, browserOptions));
|
|
106
|
+
browser._isCollocatedWithServer = false;
|
|
107
|
+
browser.on(import_browser.Browser.Events.Disconnected, doCleanup);
|
|
108
|
+
return browser;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
await doClose().catch(() => {
|
|
111
|
+
});
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
108
114
|
}
|
|
109
115
|
_createDevTools() {
|
|
110
116
|
const directory = import_registry.registry.findExecutable("chromium").directory;
|
|
@@ -23,21 +23,20 @@ __export(crCoverage_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(crCoverage_exports);
|
|
24
24
|
var import_utils = require("../../utils");
|
|
25
25
|
var import_eventsHelper = require("../utils/eventsHelper");
|
|
26
|
+
var import_progress = require("../progress");
|
|
26
27
|
class CRCoverage {
|
|
27
28
|
constructor(client) {
|
|
28
29
|
this._jsCoverage = new JSCoverage(client);
|
|
29
30
|
this._cssCoverage = new CSSCoverage(client);
|
|
30
31
|
}
|
|
31
32
|
async startJSCoverage(progress, options) {
|
|
32
|
-
progress.
|
|
33
|
-
await progress.race(this._jsCoverage.start(options));
|
|
33
|
+
await (0, import_progress.raceUncancellableOperationWithCleanup)(progress, () => this._jsCoverage.start(options), () => this._jsCoverage.stop());
|
|
34
34
|
}
|
|
35
35
|
async stopJSCoverage() {
|
|
36
36
|
return await this._jsCoverage.stop();
|
|
37
37
|
}
|
|
38
38
|
async startCSSCoverage(progress, options) {
|
|
39
|
-
progress.
|
|
40
|
-
await progress.race(this._cssCoverage.start(options));
|
|
39
|
+
await (0, import_progress.raceUncancellableOperationWithCleanup)(progress, () => this._cssCoverage.start(options), () => this._cssCoverage.stop());
|
|
41
40
|
}
|
|
42
41
|
async stopCSSCoverage() {
|
|
43
42
|
return await this._cssCoverage.stop();
|
|
@@ -22,13 +22,11 @@ __export(videoRecorder_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(videoRecorder_exports);
|
|
24
24
|
var import_utils = require("../../utils");
|
|
25
|
-
var import_instrumentation = require("../instrumentation");
|
|
26
25
|
var import_page = require("../page");
|
|
27
26
|
var import_processLauncher = require("../utils/processLauncher");
|
|
28
|
-
var import_progress = require("../progress");
|
|
29
27
|
const fps = 25;
|
|
30
28
|
class VideoRecorder {
|
|
31
|
-
constructor(page, ffmpegPath
|
|
29
|
+
constructor(page, ffmpegPath) {
|
|
32
30
|
this._process = null;
|
|
33
31
|
this._gracefullyClose = null;
|
|
34
32
|
this._lastWritePromise = Promise.resolve();
|
|
@@ -37,47 +35,40 @@ class VideoRecorder {
|
|
|
37
35
|
this._lastWriteTimestamp = 0;
|
|
38
36
|
this._frameQueue = [];
|
|
39
37
|
this._isStopped = false;
|
|
40
|
-
this._progress = progress;
|
|
41
38
|
this._ffmpegPath = ffmpegPath;
|
|
42
39
|
page.on(import_page.Page.Events.ScreencastFrame, (frame) => this.writeFrame(frame.buffer, frame.frameSwapWallTime / 1e3));
|
|
43
40
|
}
|
|
44
41
|
static async launch(page, ffmpegPath, options) {
|
|
45
42
|
if (!options.outputFile.endsWith(".webm"))
|
|
46
43
|
throw new Error("File must have .webm extension");
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
return
|
|
50
|
-
const recorder = new VideoRecorder(page, ffmpegPath, progress);
|
|
51
|
-
progress.cleanupWhenAborted(() => recorder.stop());
|
|
52
|
-
await recorder._launch(options);
|
|
53
|
-
return recorder;
|
|
54
|
-
});
|
|
44
|
+
const recorder = new VideoRecorder(page, ffmpegPath);
|
|
45
|
+
await recorder._launch(options);
|
|
46
|
+
return recorder;
|
|
55
47
|
}
|
|
56
48
|
async _launch(options) {
|
|
57
49
|
const w = options.width;
|
|
58
50
|
const h = options.height;
|
|
59
51
|
const args = `-loglevel error -f image2pipe -avioflags direct -fpsprobesize 0 -probesize 32 -analyzeduration 0 -c:v mjpeg -i pipe:0 -y -an -r ${fps} -c:v vp8 -qmin 0 -qmax 50 -crf 8 -deadline realtime -speed 8 -b:v 1M -threads 1 -vf pad=${w}:${h}:0:0:gray,crop=${w}:${h}:0:0`.split(" ");
|
|
60
52
|
args.push(options.outputFile);
|
|
61
|
-
const progress = this._progress;
|
|
62
53
|
const { launchedProcess, gracefullyClose } = await (0, import_processLauncher.launchProcess)({
|
|
63
54
|
command: this._ffmpegPath,
|
|
64
55
|
args,
|
|
65
56
|
stdio: "stdin",
|
|
66
|
-
log: (message) =>
|
|
57
|
+
log: (message) => import_utils.debugLogger.log("browser", message),
|
|
67
58
|
tempDirectories: [],
|
|
68
59
|
attemptToGracefullyClose: async () => {
|
|
69
|
-
|
|
60
|
+
import_utils.debugLogger.log("browser", "Closing stdin...");
|
|
70
61
|
launchedProcess.stdin.end();
|
|
71
62
|
},
|
|
72
63
|
onExit: (exitCode, signal) => {
|
|
73
|
-
|
|
64
|
+
import_utils.debugLogger.log("browser", `ffmpeg onkill exitCode=${exitCode} signal=${signal}`);
|
|
74
65
|
}
|
|
75
66
|
});
|
|
76
67
|
launchedProcess.stdin.on("finish", () => {
|
|
77
|
-
|
|
68
|
+
import_utils.debugLogger.log("browser", "ffmpeg finished input.");
|
|
78
69
|
});
|
|
79
70
|
launchedProcess.stdin.on("error", () => {
|
|
80
|
-
|
|
71
|
+
import_utils.debugLogger.log("browser", "ffmpeg error.");
|
|
81
72
|
});
|
|
82
73
|
this._process = launchedProcess;
|
|
83
74
|
this._gracefullyClose = gracefullyClose;
|
|
@@ -104,7 +95,7 @@ class VideoRecorder {
|
|
|
104
95
|
async _sendFrame(frame) {
|
|
105
96
|
return new Promise((f) => this._process.stdin.write(frame, f)).then((error) => {
|
|
106
97
|
if (error)
|
|
107
|
-
|
|
98
|
+
import_utils.debugLogger.log("browser", `ffmpeg failed to write: ${String(error)}`);
|
|
108
99
|
});
|
|
109
100
|
}
|
|
110
101
|
async stop() {
|
|
@@ -65,17 +65,6 @@ class DebugController extends import_instrumentation.SdkObject {
|
|
|
65
65
|
this._trackHierarchyListener = void 0;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
async resetForReuse(progress) {
|
|
69
|
-
const contexts = /* @__PURE__ */ new Set();
|
|
70
|
-
for (const page of this._playwright.allPages())
|
|
71
|
-
contexts.add(page.browserContext);
|
|
72
|
-
for (const context of contexts)
|
|
73
|
-
await context.resetForReuse(progress, null);
|
|
74
|
-
}
|
|
75
|
-
async navigate(progress, url) {
|
|
76
|
-
for (const p of this._playwright.allPages())
|
|
77
|
-
await p.mainFrame().goto(progress, url);
|
|
78
|
-
}
|
|
79
68
|
async setRecorderMode(progress, params) {
|
|
80
69
|
await progress.race(this._closeBrowsersWithoutPages());
|
|
81
70
|
if (params.mode === "none") {
|
|
@@ -120,10 +109,8 @@ class DebugController extends import_instrumentation.SdkObject {
|
|
|
120
109
|
async hideHighlight(progress) {
|
|
121
110
|
for (const recorder of await progress.race(this._allRecorders()))
|
|
122
111
|
recorder.hideHighlightedSelector();
|
|
123
|
-
await this._playwright.hideHighlight()
|
|
124
|
-
|
|
125
|
-
allBrowsers() {
|
|
126
|
-
return [...this._playwright.allBrowsers()];
|
|
112
|
+
await Promise.all(this._playwright.allPages().map((p) => p.hideHighlight().catch(() => {
|
|
113
|
+
})));
|
|
127
114
|
}
|
|
128
115
|
async resume(progress) {
|
|
129
116
|
for (const recorder of await progress.race(this._allRecorders()))
|
|
@@ -132,9 +119,6 @@ class DebugController extends import_instrumentation.SdkObject {
|
|
|
132
119
|
kill() {
|
|
133
120
|
(0, import_processLauncher.gracefullyProcessExitDoNotHang)(0);
|
|
134
121
|
}
|
|
135
|
-
async closeAllBrowsers() {
|
|
136
|
-
await Promise.all(this.allBrowsers().map((browser) => browser.close({ reason: "Close all browsers requested" })));
|
|
137
|
-
}
|
|
138
122
|
_emitSnapshot(initial) {
|
|
139
123
|
const pageCount = this._playwright.allPages().length;
|
|
140
124
|
if (initial && !pageCount)
|
|
@@ -52,12 +52,6 @@ class DebugControllerDispatcher extends import_dispatcher.Dispatcher {
|
|
|
52
52
|
async setReportStateChanged(params, progress) {
|
|
53
53
|
this._object.setReportStateChanged(params.enabled);
|
|
54
54
|
}
|
|
55
|
-
async resetForReuse(params, progress) {
|
|
56
|
-
await this._object.resetForReuse(progress);
|
|
57
|
-
}
|
|
58
|
-
async navigate(params, progress) {
|
|
59
|
-
await this._object.navigate(progress, params.url);
|
|
60
|
-
}
|
|
61
55
|
async setRecorderMode(params, progress) {
|
|
62
56
|
await this._object.setRecorderMode(progress, params);
|
|
63
57
|
}
|
|
@@ -73,9 +67,6 @@ class DebugControllerDispatcher extends import_dispatcher.Dispatcher {
|
|
|
73
67
|
async kill(params, progress) {
|
|
74
68
|
this._object.kill();
|
|
75
69
|
}
|
|
76
|
-
async closeAllBrowsers(params, progress) {
|
|
77
|
-
await this._object.closeAllBrowsers();
|
|
78
|
-
}
|
|
79
70
|
_onDispose() {
|
|
80
71
|
import_utils.eventsHelper.removeEventListeners(this._listeners);
|
|
81
72
|
this._object.dispose();
|
|
@@ -40,7 +40,6 @@ var import_jsonPipeDispatcher = require("../dispatchers/jsonPipeDispatcher");
|
|
|
40
40
|
var import_socksInterceptor = require("../socksInterceptor");
|
|
41
41
|
var import_transport = require("../transport");
|
|
42
42
|
var import_network = require("../utils/network");
|
|
43
|
-
var import_urlMatch = require("../../utils/isomorphic/urlMatch");
|
|
44
43
|
class LocalUtilsDispatcher extends import_dispatcher.Dispatcher {
|
|
45
44
|
constructor(scope, playwright) {
|
|
46
45
|
const localUtils2 = new import_instrumentation.SdkObject(playwright, "localUtils", "localUtils");
|
|
@@ -112,10 +111,6 @@ class LocalUtilsDispatcher extends import_dispatcher.Dispatcher {
|
|
|
112
111
|
pipe.on("close", () => transport.close());
|
|
113
112
|
return { pipe, headers: transport.headers };
|
|
114
113
|
}
|
|
115
|
-
async globToRegex(params, progress) {
|
|
116
|
-
const regex = (0, import_urlMatch.resolveGlobToRegexPattern)(params.baseURL, params.glob, params.webSocketUrl);
|
|
117
|
-
return { regex };
|
|
118
|
-
}
|
|
119
114
|
}
|
|
120
115
|
async function urlToWSEndpoint(progress, endpointURL) {
|
|
121
116
|
if (endpointURL.startsWith("ws"))
|