patchright-core 1.49.2 → 1.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ThirdPartyNotices.txt +380 -12
- package/bin/reinstall_msedge_beta_linux.sh +6 -0
- package/bin/reinstall_msedge_dev_linux.sh +6 -0
- package/bin/reinstall_msedge_stable_linux.sh +6 -0
- package/browsers.json +17 -16
- package/lib/androidServerImpl.js +1 -1
- package/lib/cli/program.js +6 -30
- package/lib/client/channelOwner.js +35 -55
- package/lib/client/clientInstrumentation.js +2 -0
- package/lib/client/connection.js +3 -3
- package/lib/client/network.js +3 -1
- package/lib/client/waiter.js +1 -1
- package/lib/generated/consoleApiSource.js +1 -1
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- package/lib/inProcessFactory.js +2 -0
- package/lib/protocol/debug.js +1 -1
- package/lib/protocol/validator.js +2 -2
- package/lib/remote/playwrightConnection.js +4 -3
- package/lib/remote/playwrightServer.js +2 -1
- package/lib/server/bidi/bidiBrowser.js +9 -6
- package/lib/server/bidi/bidiExecutionContext.js +20 -1
- package/lib/server/bidi/bidiInput.js +7 -5
- package/lib/server/bidi/bidiNetworkManager.js +8 -9
- package/lib/server/bidi/bidiPage.js +9 -20
- package/lib/server/bidi/third_party/bidiKeyboard.js +9 -7
- package/lib/server/browserContext.js +24 -16
- package/lib/server/chromium/crBrowser.js +10 -10
- package/lib/server/chromium/crExecutionContext.js +1 -5
- package/lib/server/chromium/crInput.js +15 -4
- package/lib/server/chromium/crPage.js +17 -31
- package/lib/server/codegen/csharp.js +12 -2
- package/lib/server/codegen/java.js +14 -3
- package/lib/server/codegen/javascript.js +10 -2
- package/lib/server/codegen/jsonl.js +1 -1
- package/lib/server/codegen/python.js +5 -4
- package/lib/server/debugController.js +15 -40
- package/lib/server/debugger.js +1 -1
- package/lib/server/deviceDescriptorsSource.json +50 -50
- package/lib/server/dispatchers/browserContextDispatcher.js +2 -13
- package/lib/server/dispatchers/debugControllerDispatcher.js +4 -2
- package/lib/server/dispatchers/frameDispatcher.js +3 -2
- package/lib/server/dispatchers/pageDispatcher.js +1 -1
- package/lib/server/dispatchers/webSocketRouteDispatcher.js +10 -11
- package/lib/server/dom.js +7 -2
- package/lib/server/fetch.js +14 -20
- package/lib/server/firefox/ffBrowser.js +9 -7
- package/lib/server/firefox/ffInput.js +15 -4
- package/lib/server/firefox/ffPage.js +13 -28
- package/lib/server/frames.js +25 -30
- package/lib/server/har/harTracer.js +1 -1
- package/lib/server/input.js +2 -3
- package/lib/server/network.js +2 -2
- package/lib/server/page.js +23 -16
- package/lib/server/recorder/chat.js +177 -0
- package/lib/server/recorder/contextRecorder.js +6 -15
- package/lib/server/recorder/recorderApp.js +1 -1
- package/lib/server/recorder/recorderCollection.js +5 -17
- package/lib/server/recorder/recorderRunner.js +7 -3
- package/lib/server/recorder/recorderUtils.js +5 -29
- package/lib/server/recorder.js +12 -9
- package/lib/server/registry/browserFetcher.js +1 -1
- package/lib/server/registry/dependencies.js +5 -5
- package/lib/server/registry/index.js +118 -5
- package/lib/server/registry/nativeDeps.js +7 -4
- package/lib/server/socksClientCertificatesInterceptor.js +1 -1
- package/lib/server/trace/recorder/snapshotterInjected.js +12 -5
- package/lib/server/trace/viewer/traceViewer.js +6 -1
- package/lib/server/transport.js +1 -0
- package/lib/server/webkit/webkit.js +1 -1
- package/lib/server/webkit/wkBrowser.js +6 -6
- package/lib/server/webkit/wkExecutionContext.js +1 -0
- package/lib/server/webkit/wkInput.js +15 -5
- package/lib/server/webkit/wkPage.js +7 -25
- package/lib/utils/comparators.js +16 -10
- package/lib/utils/debugLogger.js +3 -1
- package/lib/utils/hostPlatform.js +14 -8
- package/lib/utils/httpServer.js +0 -4
- package/lib/utils/isomorphic/ariaSnapshot.js +176 -52
- package/lib/utils/isomorphic/cssParser.js +4 -4
- package/lib/utils/isomorphic/locatorGenerators.js +2 -2
- package/lib/utils/isomorphic/locatorParser.js +18 -12
- package/lib/utils/isomorphic/urlMatch.js +2 -4
- package/lib/utils/network.js +1 -1
- package/lib/utils/processLauncher.js +1 -1
- package/lib/utils/wsServer.js +1 -0
- package/lib/utils/zones.js +18 -20
- package/lib/utilsBundleImpl/index.js +104 -104
- package/lib/vite/htmlReport/index.html +14 -14
- package/lib/vite/{traceViewer/assets/codeMirrorModule-VZNWuWvU.js → recorder/assets/codeMirrorModule-CNAqJrkA.js} +1 -1
- package/lib/vite/recorder/assets/{index-CqeZmzx8.js → index-DGS0JLxS.js} +78 -78
- package/lib/vite/recorder/assets/{index-iA1aAGZg.css → index-eHBmevrY.css} +1 -1
- package/lib/vite/recorder/index.html +2 -2
- package/lib/vite/{recorder/assets/codeMirrorModule-DUzBrnvO.js → traceViewer/assets/codeMirrorModule-D55P_UuL.js} +10 -10
- package/lib/vite/traceViewer/assets/defaultSettingsView-B-uNoFsX.js +243 -0
- package/lib/vite/traceViewer/defaultSettingsView.2xeEXCXv.css +1 -0
- package/lib/vite/traceViewer/index.BfvuujqP.js +2 -0
- package/lib/vite/traceViewer/index.html +4 -7
- package/lib/vite/traceViewer/sw.bundle.js +3 -3
- package/lib/vite/traceViewer/{uiMode.voC1ZiOQ.css → uiMode.BatfzHMG.css} +1 -1
- package/lib/vite/traceViewer/uiMode.CStJu6jo.js +5 -0
- package/lib/vite/traceViewer/uiMode.html +4 -7
- package/package.json +1 -1
- package/types/protocol.d.ts +269 -20
- package/types/types.d.ts +69 -30
- package/bin/PrintDeps.exe +0 -0
- package/bin/README.md +0 -2
- package/lib/server/ariaSnapshot.js +0 -33
- package/lib/server/recorder/recorderInTraceViewer.js +0 -144
- package/lib/utils/isomorphic/recorderUtils.js +0 -227
- package/lib/vite/traceViewer/assets/inspectorTab-BV-Uf3j9.js +0 -68
- package/lib/vite/traceViewer/assets/testServerConnection-DeE2kSzz.js +0 -1
- package/lib/vite/traceViewer/assets/workbench-B4WPcYi9.js +0 -9
- package/lib/vite/traceViewer/embedded.BLPSqdbm.js +0 -2
- package/lib/vite/traceViewer/embedded.html +0 -18
- package/lib/vite/traceViewer/embedded.w7WN2u1R.css +0 -1
- package/lib/vite/traceViewer/index.BGZfFXXF.js +0 -2
- package/lib/vite/traceViewer/inspectorTab.DEOUW62d.css +0 -1
- package/lib/vite/traceViewer/recorder.B_SY1GJM.css +0 -0
- package/lib/vite/traceViewer/recorder.eWs2vuTG.js +0 -2
- package/lib/vite/traceViewer/recorder.html +0 -17
- package/lib/vite/traceViewer/uiMode.CW2d9h0S.js +0 -5
- package/lib/vite/traceViewer/workbench.C-zR9ysA.css +0 -1
- /package/lib/vite/recorder/assets/{codeMirrorModule-ez37Vkbh.css → codeMirrorModule-C3UTv-Ge.css} +0 -0
- /package/lib/vite/traceViewer/assets/{xtermModule-BeNbaIVa.js → xtermModule-c-SNdYZy.js} +0 -0
- /package/lib/vite/traceViewer/{codeMirrorModule.ez37Vkbh.css → codeMirrorModule.C3UTv-Ge.css} +0 -0
- /package/lib/vite/traceViewer/{index.CrbWWHbf.css → index.CFOW-Ezb.css} +0 -0
- /package/lib/vite/traceViewer/{xtermModule.DSXBckUd.css → xtermModule.Beg8tuEN.css} +0 -0
|
@@ -41,7 +41,6 @@ class BidiPage {
|
|
|
41
41
|
this.rawKeyboard = void 0;
|
|
42
42
|
this.rawTouchscreen = void 0;
|
|
43
43
|
this._page = void 0;
|
|
44
|
-
this._pagePromise = void 0;
|
|
45
44
|
this._session = void 0;
|
|
46
45
|
this._opener = void 0;
|
|
47
46
|
this._realmToContext = void 0;
|
|
@@ -49,7 +48,6 @@ class BidiPage {
|
|
|
49
48
|
this._browserContext = void 0;
|
|
50
49
|
this._networkManager = void 0;
|
|
51
50
|
this._pdf = void 0;
|
|
52
|
-
this._initializedPage = null;
|
|
53
51
|
this._initScriptIds = [];
|
|
54
52
|
this._session = bidiSession;
|
|
55
53
|
this._opener = opener;
|
|
@@ -65,15 +63,13 @@ class BidiPage {
|
|
|
65
63
|
this._sessionListeners = [_eventsHelper.eventsHelper.addEventListener(bidiSession, 'script.realmCreated', this._onRealmCreated.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'script.message', this._onScriptMessage.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.contextDestroyed', this._onBrowsingContextDestroyed.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationStarted', this._onNavigationStarted.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationAborted', this._onNavigationAborted.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationFailed', this._onNavigationFailed.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.fragmentNavigated', this._onFragmentNavigated.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.domContentLoaded', this._onDomContentLoaded.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.load', this._onLoad.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.userPromptOpened', this._onUserPromptOpened.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'log.entryAdded', this._onLogEntryAdded.bind(this))];
|
|
66
64
|
|
|
67
65
|
// Initialize main frame.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this._page.reportAsNew(e);
|
|
76
|
-
return e;
|
|
66
|
+
// TODO: Wait for first execution context to be created and maybe about:blank navigated.
|
|
67
|
+
this._initialize().then(() => {
|
|
68
|
+
var _this$_opener;
|
|
69
|
+
return this._page.reportAsNew((_this$_opener = this._opener) === null || _this$_opener === void 0 ? void 0 : _this$_opener._page);
|
|
70
|
+
}, error => {
|
|
71
|
+
var _this$_opener2;
|
|
72
|
+
return this._page.reportAsNew((_this$_opener2 = this._opener) === null || _this$_opener2 === void 0 ? void 0 : _this$_opener2._page, error);
|
|
77
73
|
});
|
|
78
74
|
}
|
|
79
75
|
async _initialize() {
|
|
@@ -84,18 +80,11 @@ class BidiPage {
|
|
|
84
80
|
async _addAllInitScripts() {
|
|
85
81
|
return Promise.all(this._page.allInitScripts().map(initScript => this.addInitScript(initScript)));
|
|
86
82
|
}
|
|
87
|
-
potentiallyUninitializedPage() {
|
|
88
|
-
return this._page;
|
|
89
|
-
}
|
|
90
83
|
didClose() {
|
|
91
84
|
this._session.dispose();
|
|
92
85
|
_eventsHelper.eventsHelper.removeEventListeners(this._sessionListeners);
|
|
93
86
|
this._page._didClose();
|
|
94
87
|
}
|
|
95
|
-
async pageOrError() {
|
|
96
|
-
// TODO: Wait for first execution context to be created and maybe about:blank navigated.
|
|
97
|
-
return this._pagePromise;
|
|
98
|
-
}
|
|
99
88
|
_onFrameAttached(frameId, parentFrameId) {
|
|
100
89
|
return this._page._frameManager.frameAttached(frameId, parentFrameId);
|
|
101
90
|
}
|
|
@@ -311,7 +300,7 @@ class BidiPage {
|
|
|
311
300
|
}
|
|
312
301
|
async _onScriptMessage(event) {
|
|
313
302
|
if (event.channel !== kPlaywrightBindingChannel) return;
|
|
314
|
-
const pageOrError = await this.
|
|
303
|
+
const pageOrError = await this._page.waitForInitializedOrError();
|
|
315
304
|
if (pageOrError instanceof Error) return;
|
|
316
305
|
const context = this._realmToContext.get(event.source.realm);
|
|
317
306
|
if (!context) return;
|
|
@@ -351,7 +340,7 @@ class BidiPage {
|
|
|
351
340
|
context: this._session.sessionId,
|
|
352
341
|
format: {
|
|
353
342
|
type: `image/${format === 'png' ? 'png' : 'jpeg'}`,
|
|
354
|
-
quality: quality
|
|
343
|
+
quality: quality ? quality / 100 : 0.8
|
|
355
344
|
},
|
|
356
345
|
origin: documentRect ? 'document' : 'viewport',
|
|
357
346
|
clip: {
|
|
@@ -13,18 +13,18 @@ exports.getBidiKeyValue = void 0;
|
|
|
13
13
|
|
|
14
14
|
/* eslint-disable curly */
|
|
15
15
|
|
|
16
|
-
const getBidiKeyValue =
|
|
17
|
-
switch (
|
|
16
|
+
const getBidiKeyValue = keyName => {
|
|
17
|
+
switch (keyName) {
|
|
18
18
|
case '\r':
|
|
19
19
|
case '\n':
|
|
20
|
-
|
|
20
|
+
keyName = 'Enter';
|
|
21
21
|
break;
|
|
22
22
|
}
|
|
23
23
|
// Measures the number of code points rather than UTF-16 code units.
|
|
24
|
-
if ([...
|
|
25
|
-
return
|
|
24
|
+
if ([...keyName].length === 1) {
|
|
25
|
+
return keyName;
|
|
26
26
|
}
|
|
27
|
-
switch (
|
|
27
|
+
switch (keyName) {
|
|
28
28
|
case 'Cancel':
|
|
29
29
|
return '\uE001';
|
|
30
30
|
case 'Help':
|
|
@@ -137,6 +137,8 @@ const getBidiKeyValue = key => {
|
|
|
137
137
|
return '\uE052';
|
|
138
138
|
case 'MetaRight':
|
|
139
139
|
return '\uE053';
|
|
140
|
+
case 'Space':
|
|
141
|
+
return ' ';
|
|
140
142
|
case 'Digit0':
|
|
141
143
|
return '0';
|
|
142
144
|
case 'Digit1':
|
|
@@ -232,7 +234,7 @@ const getBidiKeyValue = key => {
|
|
|
232
234
|
case 'Quote':
|
|
233
235
|
return '"';
|
|
234
236
|
default:
|
|
235
|
-
throw new Error(`Unknown key: "${
|
|
237
|
+
throw new Error(`Unknown key: "${keyName}"`);
|
|
236
238
|
}
|
|
237
239
|
};
|
|
238
240
|
exports.getBidiKeyValue = getBidiKeyValue;
|
|
@@ -102,7 +102,7 @@ class BrowserContext extends _instrumentation.SdkObject {
|
|
|
102
102
|
this._debugger = new _debugger.Debugger(this);
|
|
103
103
|
|
|
104
104
|
// When PWDEBUG=1, show inspector for each context.
|
|
105
|
-
if ((0, _utils.debugMode)() === 'inspector') await _recorder.Recorder.show(
|
|
105
|
+
if ((0, _utils.debugMode)() === 'inspector') await _recorder.Recorder.show(this, _recorderApp.RecorderApp.factory(this), {
|
|
106
106
|
pauseOnNextStatement: true
|
|
107
107
|
});
|
|
108
108
|
|
|
@@ -201,6 +201,9 @@ class BrowserContext extends _instrumentation.SdkObject {
|
|
|
201
201
|
this._closePromiseFulfill(new Error('Context closed'));
|
|
202
202
|
this.emit(BrowserContext.Events.Close);
|
|
203
203
|
}
|
|
204
|
+
pages() {
|
|
205
|
+
return this.possiblyUninitializedPages().filter(page => page.initializedOrUndefined());
|
|
206
|
+
}
|
|
204
207
|
|
|
205
208
|
// BrowserContext methods.
|
|
206
209
|
|
|
@@ -227,6 +230,9 @@ class BrowserContext extends _instrumentation.SdkObject {
|
|
|
227
230
|
setHTTPCredentials(httpCredentials) {
|
|
228
231
|
return this.doSetHTTPCredentials(httpCredentials);
|
|
229
232
|
}
|
|
233
|
+
hasBinding(name) {
|
|
234
|
+
return this._pageBindings.has(name);
|
|
235
|
+
}
|
|
230
236
|
async exposeBinding(name, needsHandle, playwrightBinding) {
|
|
231
237
|
if (this._pageBindings.has(name)) throw new Error(`Function "${name}" has been already registered`);
|
|
232
238
|
for (const page of this.pages()) {
|
|
@@ -265,27 +271,29 @@ class BrowserContext extends _instrumentation.SdkObject {
|
|
|
265
271
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
|
266
272
|
}
|
|
267
273
|
async _loadDefaultContextAsIs(progress) {
|
|
268
|
-
if (!this.
|
|
274
|
+
if (!this.possiblyUninitializedPages().length) {
|
|
269
275
|
const waitForEvent = _helper.helper.waitForEvent(progress, this, BrowserContext.Events.Page);
|
|
270
276
|
progress.cleanupWhenAborted(() => waitForEvent.dispose);
|
|
271
|
-
|
|
272
|
-
|
|
277
|
+
// Race against BrowserContext.close
|
|
278
|
+
await Promise.race([waitForEvent.promise, this._closePromise]);
|
|
273
279
|
}
|
|
274
|
-
const
|
|
275
|
-
if (
|
|
276
|
-
await
|
|
277
|
-
|
|
280
|
+
const page = this.possiblyUninitializedPages()[0];
|
|
281
|
+
if (!page) return;
|
|
282
|
+
const pageOrError = await page.waitForInitializedOrError();
|
|
283
|
+
if (pageOrError instanceof Error) throw pageOrError;
|
|
284
|
+
await page.mainFrame()._waitForLoadState(progress, 'load');
|
|
285
|
+
return page;
|
|
278
286
|
}
|
|
279
287
|
async _loadDefaultContext(progress) {
|
|
280
|
-
const
|
|
288
|
+
const defaultPage = await this._loadDefaultContextAsIs(progress);
|
|
289
|
+
if (!defaultPage) return;
|
|
281
290
|
const browserName = this._browser.options.name;
|
|
282
291
|
if (this._options.isMobile && browserName === 'chromium' || this._options.locale && browserName === 'webkit') {
|
|
283
292
|
// Workaround for:
|
|
284
293
|
// - chromium fails to change isMobile for existing page;
|
|
285
294
|
// - webkit fails to change locale for existing page.
|
|
286
|
-
const oldPage = pages[0];
|
|
287
295
|
await this.newPage(progress.metadata);
|
|
288
|
-
await
|
|
296
|
+
await defaultPage.close(progress.metadata);
|
|
289
297
|
}
|
|
290
298
|
}
|
|
291
299
|
_authenticateProxyViaHeader() {
|
|
@@ -318,8 +326,8 @@ class BrowserContext extends _instrumentation.SdkObject {
|
|
|
318
326
|
password: password || ''
|
|
319
327
|
};
|
|
320
328
|
}
|
|
321
|
-
async addInitScript(source) {
|
|
322
|
-
const initScript = new _page6.InitScript(source);
|
|
329
|
+
async addInitScript(source, name) {
|
|
330
|
+
const initScript = new _page6.InitScript(source, false /* internal */, name);
|
|
323
331
|
this.initScripts.push(initScript);
|
|
324
332
|
await this.doAddInitScript(initScript);
|
|
325
333
|
}
|
|
@@ -379,9 +387,9 @@ class BrowserContext extends _instrumentation.SdkObject {
|
|
|
379
387
|
await this._closePromise;
|
|
380
388
|
}
|
|
381
389
|
async newPage(metadata) {
|
|
382
|
-
const
|
|
383
|
-
if (metadata.isServerSide)
|
|
384
|
-
const pageOrError = await
|
|
390
|
+
const page = await this.doCreateNewPage();
|
|
391
|
+
if (metadata.isServerSide) page.markAsServerSideOnly();
|
|
392
|
+
const pageOrError = await page.waitForInitializedOrError();
|
|
385
393
|
if (pageOrError instanceof _page6.Page) {
|
|
386
394
|
if (pageOrError.isClosed()) throw new Error('Page has been closed.');
|
|
387
395
|
return pageOrError;
|
|
@@ -134,7 +134,7 @@ class CRBrowser extends _browser.Browser {
|
|
|
134
134
|
return this.options.name === 'clank';
|
|
135
135
|
}
|
|
136
136
|
async _waitForAllPagesToBeInitialized() {
|
|
137
|
-
await Promise.all([...this._crPages.values()].map(
|
|
137
|
+
await Promise.all([...this._crPages.values()].map(crPage => crPage._page.waitForInitializedOrError()));
|
|
138
138
|
}
|
|
139
139
|
_onAttachedToTarget({
|
|
140
140
|
targetInfo,
|
|
@@ -239,9 +239,9 @@ class CRBrowser extends _browser.Browser {
|
|
|
239
239
|
return;
|
|
240
240
|
}
|
|
241
241
|
page.willBeginDownload();
|
|
242
|
-
let originPage = page.
|
|
242
|
+
let originPage = page._page.initializedOrUndefined();
|
|
243
243
|
// If it's a new window download, report it on the opener page.
|
|
244
|
-
if (!originPage && page._opener) originPage = page._opener.
|
|
244
|
+
if (!originPage && page._opener) originPage = page._opener._page.initializedOrUndefined();
|
|
245
245
|
if (!originPage) return;
|
|
246
246
|
this._downloadCreated(originPage, payload.guid, payload.url, payload.suggestedFilename);
|
|
247
247
|
}
|
|
@@ -312,10 +312,10 @@ class CRBrowserContext extends _browserContext.BrowserContext {
|
|
|
312
312
|
_crPages() {
|
|
313
313
|
return [...this._browser._crPages.values()].filter(crPage => crPage._browserContext === this);
|
|
314
314
|
}
|
|
315
|
-
|
|
316
|
-
return this._crPages().map(crPage => crPage.
|
|
315
|
+
possiblyUninitializedPages() {
|
|
316
|
+
return this._crPages().map(crPage => crPage._page);
|
|
317
317
|
}
|
|
318
|
-
async
|
|
318
|
+
async doCreateNewPage() {
|
|
319
319
|
(0, _browserContext.assertBrowserContextIsNotOwned)(this);
|
|
320
320
|
const oldKeys = this._browser.isClank() ? new Set(this._browser._crPages.keys()) : undefined;
|
|
321
321
|
let {
|
|
@@ -338,7 +338,7 @@ class CRBrowserContext extends _browserContext.BrowserContext {
|
|
|
338
338
|
(0, _utils.assert)(newKeys.size === 1);
|
|
339
339
|
[targetId] = [...newKeys];
|
|
340
340
|
}
|
|
341
|
-
return this._browser._crPages.get(targetId);
|
|
341
|
+
return this._browser._crPages.get(targetId)._page;
|
|
342
342
|
}
|
|
343
343
|
async doGetCookies(urls) {
|
|
344
344
|
const {
|
|
@@ -372,7 +372,7 @@ class CRBrowserContext extends _browserContext.BrowserContext {
|
|
|
372
372
|
});
|
|
373
373
|
}
|
|
374
374
|
async doGrantPermissions(origin, permissions) {
|
|
375
|
-
const webPermissionToProtocol = new Map([['geolocation', 'geolocation'], ['midi', 'midi'], ['notifications', 'notifications'], ['camera', 'videoCapture'], ['microphone', 'audioCapture'], ['background-sync', 'backgroundSync'], ['ambient-light-sensor', 'sensors'], ['accelerometer', 'sensors'], ['gyroscope', 'sensors'], ['magnetometer', 'sensors'], ['
|
|
375
|
+
const webPermissionToProtocol = new Map([['geolocation', 'geolocation'], ['midi', 'midi'], ['notifications', 'notifications'], ['camera', 'videoCapture'], ['microphone', 'audioCapture'], ['background-sync', 'backgroundSync'], ['ambient-light-sensor', 'sensors'], ['accelerometer', 'sensors'], ['gyroscope', 'sensors'], ['magnetometer', 'sensors'], ['clipboard-read', 'clipboardReadWrite'], ['clipboard-write', 'clipboardSanitizedWrite'], ['payment-handler', 'paymentHandler'],
|
|
376
376
|
// chrome-specific permissions we have.
|
|
377
377
|
['midi-sysex', 'midiSysex'], ['storage-access', 'storageAccess']]);
|
|
378
378
|
const filtered = permissions.map(permission => {
|
|
@@ -463,7 +463,7 @@ class CRBrowserContext extends _browserContext.BrowserContext {
|
|
|
463
463
|
// When persistent context is closed, we do not necessary get Target.detachedFromTarget
|
|
464
464
|
// for all the background pages.
|
|
465
465
|
for (const [targetId, backgroundPage] of this._browser._backgroundPages.entries()) {
|
|
466
|
-
if (backgroundPage._browserContext === this && backgroundPage.
|
|
466
|
+
if (backgroundPage._browserContext === this && backgroundPage._page.initializedOrUndefined()) {
|
|
467
467
|
backgroundPage.didClose();
|
|
468
468
|
this._browser._backgroundPages.delete(targetId);
|
|
469
469
|
}
|
|
@@ -484,7 +484,7 @@ class CRBrowserContext extends _browserContext.BrowserContext {
|
|
|
484
484
|
backgroundPages() {
|
|
485
485
|
const result = [];
|
|
486
486
|
for (const backgroundPage of this._browser._backgroundPages.values()) {
|
|
487
|
-
if (backgroundPage._browserContext === this && backgroundPage.
|
|
487
|
+
if (backgroundPage._browserContext === this && backgroundPage._page.initializedOrUndefined()) result.push(backgroundPage._page);
|
|
488
488
|
}
|
|
489
489
|
return result;
|
|
490
490
|
}
|
|
@@ -100,11 +100,7 @@ class CRExecutionContext {
|
|
|
100
100
|
}
|
|
101
101
|
exports.CRExecutionContext = CRExecutionContext;
|
|
102
102
|
function rewriteError(error) {
|
|
103
|
-
if (error.message.includes('Object reference chain is too long'))
|
|
104
|
-
result: {
|
|
105
|
-
type: 'undefined'
|
|
106
|
-
}
|
|
107
|
-
};
|
|
103
|
+
if (error.message.includes('Object reference chain is too long')) throw new Error('Cannot serialize result: object reference chain is too long.');
|
|
108
104
|
if (error.message.includes('Object couldn\'t be returned by value')) return {
|
|
109
105
|
result: {
|
|
110
106
|
type: 'undefined'
|
|
@@ -48,13 +48,19 @@ class RawKeyboardImpl {
|
|
|
48
48
|
// remove the trailing : to match the Chromium command names.
|
|
49
49
|
return commands.map(c => c.substring(0, c.length - 1));
|
|
50
50
|
}
|
|
51
|
-
async keydown(modifiers,
|
|
51
|
+
async keydown(modifiers, keyName, description, autoRepeat) {
|
|
52
|
+
const {
|
|
53
|
+
code,
|
|
54
|
+
key,
|
|
55
|
+
location,
|
|
56
|
+
text
|
|
57
|
+
} = description;
|
|
52
58
|
if (code === 'Escape' && (await this._dragManger.cancelDrag())) return;
|
|
53
59
|
const commands = this._commandsForCode(code, modifiers);
|
|
54
60
|
await this._client.send('Input.dispatchKeyEvent', {
|
|
55
61
|
type: text ? 'keyDown' : 'rawKeyDown',
|
|
56
62
|
modifiers: (0, _crProtocolHelper.toModifiersMask)(modifiers),
|
|
57
|
-
windowsVirtualKeyCode: keyCodeWithoutLocation,
|
|
63
|
+
windowsVirtualKeyCode: description.keyCodeWithoutLocation,
|
|
58
64
|
code,
|
|
59
65
|
commands,
|
|
60
66
|
key,
|
|
@@ -65,12 +71,17 @@ class RawKeyboardImpl {
|
|
|
65
71
|
isKeypad: location === input.keypadLocation
|
|
66
72
|
});
|
|
67
73
|
}
|
|
68
|
-
async keyup(modifiers,
|
|
74
|
+
async keyup(modifiers, keyName, description) {
|
|
75
|
+
const {
|
|
76
|
+
code,
|
|
77
|
+
key,
|
|
78
|
+
location
|
|
79
|
+
} = description;
|
|
69
80
|
await this._client.send('Input.dispatchKeyEvent', {
|
|
70
81
|
type: 'keyUp',
|
|
71
82
|
modifiers: (0, _crProtocolHelper.toModifiersMask)(modifiers),
|
|
72
83
|
key,
|
|
73
|
-
windowsVirtualKeyCode: keyCodeWithoutLocation,
|
|
84
|
+
windowsVirtualKeyCode: description.keyCodeWithoutLocation,
|
|
74
85
|
code,
|
|
75
86
|
location
|
|
76
87
|
});
|
|
@@ -71,8 +71,6 @@ class CRPage {
|
|
|
71
71
|
this._pdf = void 0;
|
|
72
72
|
this._coverage = void 0;
|
|
73
73
|
this._browserContext = void 0;
|
|
74
|
-
this._pagePromise = void 0;
|
|
75
|
-
this._initializedPage = null;
|
|
76
74
|
this._isBackgroundPage = void 0;
|
|
77
75
|
// Holds window features for the next popup being opened via window.open,
|
|
78
76
|
// until the popup target arrives. This could be racy if two oopifs
|
|
@@ -109,29 +107,15 @@ class CRPage {
|
|
|
109
107
|
screen: viewportSize
|
|
110
108
|
};
|
|
111
109
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
throw e;
|
|
120
|
-
}).then(() => {
|
|
121
|
-
this._initializedPage = this._page;
|
|
122
|
-
this._reportAsNew();
|
|
123
|
-
return this._page;
|
|
124
|
-
}).catch(e => {
|
|
125
|
-
this._reportAsNew(e);
|
|
126
|
-
return e;
|
|
110
|
+
const createdEvent = this._isBackgroundPage ? _crBrowser.CRBrowserContext.CREvents.BackgroundPage : _browserContext.BrowserContext.Events.Page;
|
|
111
|
+
this._mainFrameSession._initialize(bits.hasUIWindow).then(() => {
|
|
112
|
+
var _this$_opener;
|
|
113
|
+
return this._page.reportAsNew((_this$_opener = this._opener) === null || _this$_opener === void 0 ? void 0 : _this$_opener._page, undefined, createdEvent);
|
|
114
|
+
}, error => {
|
|
115
|
+
var _this$_opener2;
|
|
116
|
+
return this._page.reportAsNew((_this$_opener2 = this._opener) === null || _this$_opener2 === void 0 ? void 0 : _this$_opener2._page, error, createdEvent);
|
|
127
117
|
});
|
|
128
118
|
}
|
|
129
|
-
potentiallyUninitializedPage() {
|
|
130
|
-
return this._page;
|
|
131
|
-
}
|
|
132
|
-
_reportAsNew(error) {
|
|
133
|
-
this._page.reportAsNew(error, this._isBackgroundPage ? _crBrowser.CRBrowserContext.CREvents.BackgroundPage : _browserContext.BrowserContext.Events.Page);
|
|
134
|
-
}
|
|
135
119
|
async _forAllFrameSessions(cb) {
|
|
136
120
|
const frameSessions = Array.from(this._sessions.values());
|
|
137
121
|
await Promise.all(frameSessions.map(frameSession => {
|
|
@@ -159,9 +143,6 @@ class CRPage {
|
|
|
159
143
|
willBeginDownload() {
|
|
160
144
|
this._mainFrameSession._willBeginDownload();
|
|
161
145
|
}
|
|
162
|
-
async pageOrError() {
|
|
163
|
-
return this._pagePromise;
|
|
164
|
-
}
|
|
165
146
|
didClose() {
|
|
166
147
|
for (const session of this._sessions.values()) session.dispose();
|
|
167
148
|
this._page._didClose();
|
|
@@ -398,6 +379,9 @@ class FrameSession {
|
|
|
398
379
|
this._firstNonInitialNavigationCommittedFulfill = f;
|
|
399
380
|
this._firstNonInitialNavigationCommittedReject = r;
|
|
400
381
|
});
|
|
382
|
+
// The Promise is not always awaited (e.g. FrameSession._initialize can throw)
|
|
383
|
+
// so we catch errors here to prevent unhandled promise rejection.
|
|
384
|
+
this._firstNonInitialNavigationCommittedPromise.catch(() => {});
|
|
401
385
|
}
|
|
402
386
|
_isMainFrame() {
|
|
403
387
|
return this._targetId === this._crPage._targetId;
|
|
@@ -429,7 +413,7 @@ class FrameSession {
|
|
|
429
413
|
// Note: it is important to start video recorder before sending Page.startScreencast,
|
|
430
414
|
// and it is equally important to send Page.startScreencast before sending Runtime.runIfWaitingForDebugger.
|
|
431
415
|
await this._createVideoRecorder(screencastId, screencastOptions);
|
|
432
|
-
this._crPage.
|
|
416
|
+
this._crPage._page.waitForInitializedOrError().then(p => {
|
|
433
417
|
if (p instanceof Error) this._stopVideoRecording().catch(() => {});
|
|
434
418
|
});
|
|
435
419
|
}
|
|
@@ -671,6 +655,9 @@ class FrameSession {
|
|
|
671
655
|
const frame = this._page._frameManager.frame(targetId);
|
|
672
656
|
if (!frame) return; // Subtree may be already gone due to renderer/browser race.
|
|
673
657
|
this._page._frameManager.removeChildFramesRecursively(frame);
|
|
658
|
+
for (const [contextId, context] of this._contextIdToContext) {
|
|
659
|
+
if (context.frame === frame) this._onExecutionContextDestroyed(contextId);
|
|
660
|
+
}
|
|
674
661
|
const frameSession = new FrameSession(this._crPage, session, targetId, this);
|
|
675
662
|
this._crPage._sessions.set(targetId, frameSession);
|
|
676
663
|
frameSession._initialize(false).catch(e => e);
|
|
@@ -773,7 +760,7 @@ class FrameSession {
|
|
|
773
760
|
this._page._addConsoleMessage(event.type, values, (0, _crProtocolHelper.toConsoleMessageLocation)(event.stackTrace));
|
|
774
761
|
}
|
|
775
762
|
async _onBindingCalled(event) {
|
|
776
|
-
const pageOrError = await this._crPage.
|
|
763
|
+
const pageOrError = await this._crPage._page.waitForInitializedOrError();
|
|
777
764
|
if (!(pageOrError instanceof Error)) {
|
|
778
765
|
const context = this._contextIdToContext.get(event.executionContextId);
|
|
779
766
|
if (context) await this._page._onBindingCalled(event.payload, context);else await this._page._onBindingCalled(event.payload, await this._page.mainFrame()._mainContext()); // This might be a bit sketchy but it works for now
|
|
@@ -831,8 +818,7 @@ class FrameSession {
|
|
|
831
818
|
await this._page._onFileChooserOpened(handle);
|
|
832
819
|
}
|
|
833
820
|
_willBeginDownload() {
|
|
834
|
-
|
|
835
|
-
if (!originPage) {
|
|
821
|
+
if (!this._crPage._page.initializedOrUndefined()) {
|
|
836
822
|
// Resume the page creation with an error. The page will automatically close right
|
|
837
823
|
// after the download begins.
|
|
838
824
|
this._firstNonInitialNavigationCommittedReject(new Error('Starting new page download'));
|
|
@@ -871,7 +857,7 @@ class FrameSession {
|
|
|
871
857
|
});
|
|
872
858
|
// Wait for the first frame before reporting video to the client.
|
|
873
859
|
gotFirstFrame.then(() => {
|
|
874
|
-
this._crPage._browserContext._browser._videoStarted(this._crPage._browserContext, screencastId, options.outputFile, this._crPage.
|
|
860
|
+
this._crPage._browserContext._browser._videoStarted(this._crPage._browserContext, screencastId, options.outputFile, this._crPage._page.waitForInitializedOrError());
|
|
875
861
|
});
|
|
876
862
|
}
|
|
877
863
|
async _stopVideoRecording() {
|
|
@@ -151,7 +151,12 @@ class CSharpLanguageGenerator {
|
|
|
151
151
|
using var playwright = await Playwright.CreateAsync();
|
|
152
152
|
await using var browser = await playwright.${toPascal(options.browserName)}.LaunchAsync(${formatObject(options.launchOptions, ' ', 'BrowserTypeLaunchOptions')});
|
|
153
153
|
var context = await browser.NewContextAsync(${formatContextOptions(options.contextOptions, options.deviceName)});`);
|
|
154
|
-
if (options.contextOptions.recordHar)
|
|
154
|
+
if (options.contextOptions.recordHar) {
|
|
155
|
+
const url = options.contextOptions.recordHar.urlFilter;
|
|
156
|
+
formatter.add(` await context.RouteFromHARAsync(${quote(options.contextOptions.recordHar.path)}${url ? `, ${formatObject({
|
|
157
|
+
url
|
|
158
|
+
}, ' ', 'BrowserContextRouteFromHAROptions')}` : ''});`);
|
|
159
|
+
}
|
|
155
160
|
formatter.newLine();
|
|
156
161
|
return formatter.format();
|
|
157
162
|
}
|
|
@@ -176,7 +181,12 @@ class CSharpLanguageGenerator {
|
|
|
176
181
|
formatter.add(` [${this._mode === 'nunit' ? 'Test' : 'TestMethod'}]
|
|
177
182
|
public async Task MyTest()
|
|
178
183
|
{`);
|
|
179
|
-
if (options.contextOptions.recordHar)
|
|
184
|
+
if (options.contextOptions.recordHar) {
|
|
185
|
+
const url = options.contextOptions.recordHar.urlFilter;
|
|
186
|
+
formatter.add(` await Context.RouteFromHARAsync(${quote(options.contextOptions.recordHar.path)}${url ? `, ${formatObject({
|
|
187
|
+
url
|
|
188
|
+
}, ' ', 'BrowserContextRouteFromHAROptions')}` : ''});`);
|
|
189
|
+
}
|
|
180
190
|
return formatter.format();
|
|
181
191
|
}
|
|
182
192
|
generateFooter(saveStorage) {
|
|
@@ -135,27 +135,38 @@ class JavaLanguageGenerator {
|
|
|
135
135
|
import com.microsoft.playwright.Page;
|
|
136
136
|
import com.microsoft.playwright.options.*;
|
|
137
137
|
|
|
138
|
-
import org.junit.jupiter.api.*;
|
|
138
|
+
${options.contextOptions.recordHar ? `import java.nio.file.Paths;\n` : ''}import org.junit.jupiter.api.*;
|
|
139
139
|
import static com.microsoft.playwright.assertions.PlaywrightAssertions.*;
|
|
140
140
|
|
|
141
141
|
@UsePlaywright
|
|
142
142
|
public class TestExample {
|
|
143
143
|
@Test
|
|
144
144
|
void test(Page page) {`);
|
|
145
|
+
if (options.contextOptions.recordHar) {
|
|
146
|
+
const url = options.contextOptions.recordHar.urlFilter;
|
|
147
|
+
const recordHarOptions = typeof url === 'string' ? `, new Page.RouteFromHAROptions()
|
|
148
|
+
.setUrl(${quote(url)})` : '';
|
|
149
|
+
formatter.add(` page.routeFromHAR(Paths.get(${quote(options.contextOptions.recordHar.path)})${recordHarOptions});`);
|
|
150
|
+
}
|
|
145
151
|
return formatter.format();
|
|
146
152
|
}
|
|
147
153
|
formatter.add(`
|
|
148
154
|
import com.microsoft.playwright.*;
|
|
149
155
|
import com.microsoft.playwright.options.*;
|
|
150
156
|
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
|
151
|
-
import java.util.*;
|
|
157
|
+
${options.contextOptions.recordHar ? `import java.nio.file.Paths;\n` : ''}import java.util.*;
|
|
152
158
|
|
|
153
159
|
public class Example {
|
|
154
160
|
public static void main(String[] args) {
|
|
155
161
|
try (Playwright playwright = Playwright.create()) {
|
|
156
162
|
Browser browser = playwright.${options.browserName}().launch(${formatLaunchOptions(options.launchOptions)});
|
|
157
163
|
BrowserContext context = browser.newContext(${formatContextOptions(options.contextOptions, options.deviceName)});`);
|
|
158
|
-
if (options.contextOptions.recordHar)
|
|
164
|
+
if (options.contextOptions.recordHar) {
|
|
165
|
+
const url = options.contextOptions.recordHar.urlFilter;
|
|
166
|
+
const recordHarOptions = typeof url === 'string' ? `, new BrowserContext.RouteFromHAROptions()
|
|
167
|
+
.setUrl(${quote(url)})` : '';
|
|
168
|
+
formatter.add(` context.routeFromHAR(Paths.get(${quote(options.contextOptions.recordHar.path)})${recordHarOptions});`);
|
|
169
|
+
}
|
|
159
170
|
return formatter.format();
|
|
160
171
|
}
|
|
161
172
|
generateFooter(saveStorage) {
|
|
@@ -106,7 +106,10 @@ class JavaScriptLanguageGenerator {
|
|
|
106
106
|
return `${this._isTest ? '' : '// '}await expect(${subject}.${this._asLocator(action.selector)}).${assertion};`;
|
|
107
107
|
}
|
|
108
108
|
case 'assertSnapshot':
|
|
109
|
-
|
|
109
|
+
{
|
|
110
|
+
const commentIfNeeded = this._isTest ? '' : '// ';
|
|
111
|
+
return `${commentIfNeeded}await expect(${subject}.${this._asLocator(action.selector)}).toMatchAriaSnapshot(${quoteMultiline(action.snapshot, `${commentIfNeeded} `)});`;
|
|
112
|
+
}
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
_asLocator(selector) {
|
|
@@ -127,7 +130,12 @@ class JavaScriptLanguageGenerator {
|
|
|
127
130
|
import { test, expect${options.deviceName ? ', devices' : ''} } from '@playwright/test';
|
|
128
131
|
${useText ? '\ntest.use(' + useText + ');\n' : ''}
|
|
129
132
|
test('test', async ({ page }) => {`);
|
|
130
|
-
if (options.contextOptions.recordHar)
|
|
133
|
+
if (options.contextOptions.recordHar) {
|
|
134
|
+
const url = options.contextOptions.recordHar.urlFilter;
|
|
135
|
+
formatter.add(` await page.routeFromHAR(${quote(options.contextOptions.recordHar.path)}${url ? `, ${formatOptions({
|
|
136
|
+
url
|
|
137
|
+
}, false)}` : ''});`);
|
|
138
|
+
}
|
|
131
139
|
return formatter.format();
|
|
132
140
|
}
|
|
133
141
|
generateTestFooter(saveStorage) {
|
|
@@ -32,7 +32,7 @@ class JsonlLanguageGenerator {
|
|
|
32
32
|
const locator = actionInContext.action.selector ? JSON.parse((0, _utils.asLocator)('jsonl', actionInContext.action.selector)) : undefined;
|
|
33
33
|
const entry = {
|
|
34
34
|
...actionInContext.action,
|
|
35
|
-
|
|
35
|
+
...actionInContext.frame,
|
|
36
36
|
locator
|
|
37
37
|
};
|
|
38
38
|
return JSON.stringify(entry);
|
|
@@ -123,6 +123,7 @@ class PythonLanguageGenerator {
|
|
|
123
123
|
}
|
|
124
124
|
generateHeader(options) {
|
|
125
125
|
const formatter = new PythonFormatter();
|
|
126
|
+
const recordHar = options.contextOptions.recordHar;
|
|
126
127
|
if (this._isPyTest) {
|
|
127
128
|
const contextOptions = formatContextOptions(options.contextOptions, options.deviceName, true /* asDict */);
|
|
128
129
|
const fixture = contextOptions ? `
|
|
@@ -132,12 +133,12 @@ def browser_context_args(browser_context_args, playwright) {
|
|
|
132
133
|
return {${contextOptions}}
|
|
133
134
|
}
|
|
134
135
|
` : '';
|
|
135
|
-
formatter.add(`${options.deviceName ? 'import pytest\n' : ''}import re
|
|
136
|
+
formatter.add(`${options.deviceName || contextOptions ? 'import pytest\n' : ''}import re
|
|
136
137
|
from playwright.sync_api import Page, expect
|
|
137
138
|
${fixture}
|
|
138
139
|
|
|
139
140
|
def test_example(page: Page) -> None {`);
|
|
140
|
-
if (
|
|
141
|
+
if (recordHar) formatter.add(` page.route_from_har(${quote(recordHar.path)}${typeof recordHar.urlFilter === 'string' ? `, url=${quote(recordHar.urlFilter)}` : ''})`);
|
|
141
142
|
} else if (this._isAsync) {
|
|
142
143
|
formatter.add(`
|
|
143
144
|
import asyncio
|
|
@@ -148,7 +149,7 @@ from playwright.async_api import Playwright, async_playwright, expect
|
|
|
148
149
|
async def run(playwright: Playwright) -> None {
|
|
149
150
|
browser = await playwright.${options.browserName}.launch(${formatOptions(options.launchOptions, false)})
|
|
150
151
|
context = await browser.new_context(${formatContextOptions(options.contextOptions, options.deviceName)})`);
|
|
151
|
-
if (
|
|
152
|
+
if (recordHar) formatter.add(` await context.route_from_har(${quote(recordHar.path)}${typeof recordHar.urlFilter === 'string' ? `, url=${quote(recordHar.urlFilter)}` : ''})`);
|
|
152
153
|
} else {
|
|
153
154
|
formatter.add(`
|
|
154
155
|
import re
|
|
@@ -158,7 +159,7 @@ from playwright.sync_api import Playwright, sync_playwright, expect
|
|
|
158
159
|
def run(playwright: Playwright) -> None {
|
|
159
160
|
browser = playwright.${options.browserName}.launch(${formatOptions(options.launchOptions, false)})
|
|
160
161
|
context = browser.new_context(${formatContextOptions(options.contextOptions, options.deviceName)})`);
|
|
161
|
-
if (
|
|
162
|
+
if (recordHar) formatter.add(` context.route_from_har(${quote(recordHar.path)}${typeof recordHar.urlFilter === 'string' ? `, url=${quote(recordHar.urlFilter)}` : ''})`);
|
|
162
163
|
}
|
|
163
164
|
return formatter.format();
|
|
164
165
|
}
|