fix(bidi): do not report internal pages (#35865)

This commit is contained in:
Yury Semikhatsky 2025-05-07 14:23:16 -07:00 committed by GitHub
parent 74aa1f0385
commit 83c5ee74da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 45 additions and 12 deletions

View File

@ -207,6 +207,7 @@ export class BidiBrowserContext extends BrowserContext {
declare readonly _browser: BidiBrowser; declare readonly _browser: BidiBrowser;
private _initScriptIds: bidi.Script.PreloadScript[] = []; private _initScriptIds: bidi.Script.PreloadScript[] = [];
private _originToPermissions = new Map<string, string[]>(); private _originToPermissions = new Map<string, string[]>();
private _blockingPageCreations: Set<Promise<unknown>> = new Set();
constructor(browser: BidiBrowser, browserContextId: string | undefined, options: types.BrowserContextOptions) { constructor(browser: BidiBrowser, browserContextId: string | undefined, options: types.BrowserContextOptions) {
super(browser, options, browserContextId); super(browser, options, browserContextId);
@ -265,12 +266,30 @@ export class BidiBrowserContext extends BrowserContext {
return this._bidiPages().map(bidiPage => bidiPage._page); return this._bidiPages().map(bidiPage => bidiPage._page);
} }
override async doCreateNewPage(): Promise<Page> { override async doCreateNewPage(markAsServerSideOnly?: boolean): Promise<Page> {
const promise = this._createNewPageImpl(markAsServerSideOnly);
if (markAsServerSideOnly)
this._blockingPageCreations.add(promise);
try {
return await promise;
} finally {
this._blockingPageCreations.delete(promise);
}
}
private async _createNewPageImpl(markAsServerSideOnly?: boolean): Promise<Page> {
const { context } = await this._browser._browserSession.send('browsingContext.create', { const { context } = await this._browser._browserSession.send('browsingContext.create', {
type: bidi.BrowsingContext.CreateType.Window, type: bidi.BrowsingContext.CreateType.Window,
userContext: this._browserContextId, userContext: this._browserContextId,
}); });
return this._browser._bidiPages.get(context)!._page; const page = this._browser._bidiPages.get(context)!._page;
if (markAsServerSideOnly)
page.markAsServerSideOnly();
return page;
}
async waitForBlockingPageCreations() {
await Promise.all([...this._blockingPageCreations].map(command => command.catch(() => {})));
} }
async doGetCookies(urls: string[]): Promise<channels.NetworkCookie[]> { async doGetCookies(urls: string[]): Promise<channels.NetworkCookie[]> {

View File

@ -93,6 +93,12 @@ export class BidiPage implements PageDelegate {
await Promise.all([ await Promise.all([
this.updateHttpCredentials(), this.updateHttpCredentials(),
this.updateRequestInterception(), this.updateRequestInterception(),
// If the page is created by the Playwright client's call, some initialization
// may be pending. Wait for it to complete before reporting the page as new.
//
// TODO: ideally we'd wait only for the commands that created this page, but currently
// there is no way in Bidi to track which command created this page.
this._browserContext.waitForBlockingPageCreations(),
]); ]);
} }

View File

@ -267,7 +267,7 @@ export abstract class BrowserContext extends SdkObject {
// BrowserContext methods. // BrowserContext methods.
abstract possiblyUninitializedPages(): Page[]; abstract possiblyUninitializedPages(): Page[];
abstract doCreateNewPage(): Promise<Page>; abstract doCreateNewPage(markAsServerSideOnly?: boolean): Promise<Page>;
abstract addCookies(cookies: channels.SetNetworkCookie[]): Promise<void>; abstract addCookies(cookies: channels.SetNetworkCookie[]): Promise<void>;
abstract setGeolocation(geolocation?: types.Geolocation): Promise<void>; abstract setGeolocation(geolocation?: types.Geolocation): Promise<void>;
abstract setExtraHTTPHeaders(headers: types.HeadersArray): Promise<void>; abstract setExtraHTTPHeaders(headers: types.HeadersArray): Promise<void>;
@ -495,9 +495,7 @@ export abstract class BrowserContext extends SdkObject {
} }
async newPage(metadata: CallMetadata): Promise<Page> { async newPage(metadata: CallMetadata): Promise<Page> {
const page = await this.doCreateNewPage(); const page = await this.doCreateNewPage(metadata.isServerSide);
if (metadata.isServerSide)
page.markAsServerSideOnly();
const pageOrError = await page.waitForInitializedOrError(); const pageOrError = await page.waitForInitializedOrError();
if (pageOrError instanceof Page) { if (pageOrError instanceof Page) {
if (pageOrError.isClosed()) if (pageOrError.isClosed())

View File

@ -371,9 +371,12 @@ export class CRBrowserContext extends BrowserContext {
return this._crPages().map(crPage => crPage._page); return this._crPages().map(crPage => crPage._page);
} }
override async doCreateNewPage(): Promise<Page> { override async doCreateNewPage(markAsServerSideOnly?: boolean): Promise<Page> {
const { targetId } = await this._browser._session.send('Target.createTarget', { url: 'about:blank', browserContextId: this._browserContextId }); const { targetId } = await this._browser._session.send('Target.createTarget', { url: 'about:blank', browserContextId: this._browserContextId });
return this._browser._crPages.get(targetId)!._page; const page = this._browser._crPages.get(targetId)!._page;
if (markAsServerSideOnly)
page.markAsServerSideOnly();
return page;
} }
async doGetCookies(urls: string[]): Promise<channels.NetworkCookie[]> { async doGetCookies(urls: string[]): Promise<channels.NetworkCookie[]> {

View File

@ -281,7 +281,7 @@ export class FFBrowserContext extends BrowserContext {
return this._ffPages().map(ffPage => ffPage._page); return this._ffPages().map(ffPage => ffPage._page);
} }
override async doCreateNewPage(): Promise<Page> { override async doCreateNewPage(markAsServerSideOnly?: boolean): Promise<Page> {
const { targetId } = await this._browser.session.send('Browser.newPage', { const { targetId } = await this._browser.session.send('Browser.newPage', {
browserContextId: this._browserContextId browserContextId: this._browserContextId
}).catch(e => { }).catch(e => {
@ -289,7 +289,11 @@ export class FFBrowserContext extends BrowserContext {
throw new Error(`Invalid timezone ID: ${this._options.timezoneId}`); throw new Error(`Invalid timezone ID: ${this._options.timezoneId}`);
throw e; throw e;
}); });
return this._browser._ffPages.get(targetId)!._page; const page = this._browser._ffPages.get(targetId)!._page;
if (markAsServerSideOnly)
page.markAsServerSideOnly();
return page;
} }
async doGetCookies(urls: string[]): Promise<channels.NetworkCookie[]> { async doGetCookies(urls: string[]): Promise<channels.NetworkCookie[]> {

View File

@ -244,9 +244,12 @@ export class WKBrowserContext extends BrowserContext {
return this._wkPages().map(wkPage => wkPage._page); return this._wkPages().map(wkPage => wkPage._page);
} }
override async doCreateNewPage(): Promise<Page> { override async doCreateNewPage(markAsServerSideOnly?: boolean): Promise<Page> {
const { pageProxyId } = await this._browser._browserSession.send('Playwright.createPage', { browserContextId: this._browserContextId }); const { pageProxyId } = await this._browser._browserSession.send('Playwright.createPage', { browserContextId: this._browserContextId });
return this._browser._wkPages.get(pageProxyId)!._page; const page = this._browser._wkPages.get(pageProxyId)!._page;
if (markAsServerSideOnly)
page.markAsServerSideOnly();
return page;
} }
async doGetCookies(urls: string[]): Promise<channels.NetworkCookie[]> { async doGetCookies(urls: string[]): Promise<channels.NetworkCookie[]> {