diff --git a/packages/playwright-core/src/server/bidi/bidiBrowser.ts b/packages/playwright-core/src/server/bidi/bidiBrowser.ts index 9861fc80cf..acefc08fb2 100644 --- a/packages/playwright-core/src/server/bidi/bidiBrowser.ts +++ b/packages/playwright-core/src/server/bidi/bidiBrowser.ts @@ -211,6 +211,10 @@ export class BidiBrowserContext extends BrowserContext { return this._bidiPages().map(bidiPage => bidiPage._initializedPage).filter(Boolean) as Page[]; } + pagesOrErrors() { + return this._bidiPages().map(bidiPage => bidiPage.pageOrError()); + } + async newPageDelegate(): Promise { assertBrowserContextIsNotOwned(this); const { context } = await this._browser._browserSession.send('browsingContext.create', { diff --git a/packages/playwright-core/src/server/browserContext.ts b/packages/playwright-core/src/server/browserContext.ts index 025bd0f388..309008989d 100644 --- a/packages/playwright-core/src/server/browserContext.ts +++ b/packages/playwright-core/src/server/browserContext.ts @@ -259,6 +259,7 @@ export abstract class BrowserContext extends SdkObject { // BrowserContext methods. abstract pages(): Page[]; + abstract pagesOrErrors(): Promise[]; abstract newPageDelegate(): Promise; abstract addCookies(cookies: channels.SetNetworkCookie[]): Promise; abstract setGeolocation(geolocation?: types.Geolocation): Promise; @@ -358,29 +359,30 @@ export abstract class BrowserContext extends SdkObject { this._timeoutSettings.setDefaultTimeout(timeout); } - async _loadDefaultContextAsIs(progress: Progress): Promise { - if (!this.pages().length) { + async _loadDefaultContextAsIs(progress: Progress): Promise { + if (!this.pagesOrErrors().length) { const waitForEvent = helper.waitForEvent(progress, this, BrowserContext.Events.Page); progress.cleanupWhenAborted(() => waitForEvent.dispose); - const page = (await waitForEvent.promise) as Page; - if (page._pageIsError) - throw page._pageIsError; + const page = await waitForEvent.promise as Page; + const pageOrError = await page._delegate.pageOrError(); + if (pageOrError instanceof Error) + throw pageOrError; } - const pages = this.pages(); - if (pages[0]._pageIsError) - throw pages[0]._pageIsError; - await pages[0].mainFrame()._waitForLoadState(progress, 'load'); - return pages; + const pageOrError = await this.pagesOrErrors()[0]; + if (pageOrError instanceof Error) + throw pageOrError; + await pageOrError.mainFrame()._waitForLoadState(progress, 'load'); + return pageOrError; } async _loadDefaultContext(progress: Progress) { - const pages = await this._loadDefaultContextAsIs(progress); + const defaultPage = await this._loadDefaultContextAsIs(progress); const browserName = this._browser.options.name; if ((this._options.isMobile && browserName === 'chromium') || (this._options.locale && browserName === 'webkit')) { // Workaround for: // - chromium fails to change isMobile for existing page; // - webkit fails to change locale for existing page. - const oldPage = pages[0]; + const oldPage = defaultPage; await this.newPage(progress.metadata); await oldPage.close(progress.metadata); } diff --git a/packages/playwright-core/src/server/chromium/crBrowser.ts b/packages/playwright-core/src/server/chromium/crBrowser.ts index a6d77e4ae7..1aba1ed8cb 100644 --- a/packages/playwright-core/src/server/chromium/crBrowser.ts +++ b/packages/playwright-core/src/server/chromium/crBrowser.ts @@ -368,6 +368,10 @@ export class CRBrowserContext extends BrowserContext { return this._crPages().map(crPage => crPage._initializedPage).filter(Boolean) as Page[]; } + pagesOrErrors() { + return this._crPages().map(crPage => crPage.pageOrError()); + } + async newPageDelegate(): Promise { assertBrowserContextIsNotOwned(this); diff --git a/packages/playwright-core/src/server/chromium/crPage.ts b/packages/playwright-core/src/server/chromium/crPage.ts index bfad678f1c..11c609c8c2 100644 --- a/packages/playwright-core/src/server/chromium/crPage.ts +++ b/packages/playwright-core/src/server/chromium/crPage.ts @@ -432,6 +432,8 @@ class FrameSession { this._firstNonInitialNavigationCommittedFulfill = f; this._firstNonInitialNavigationCommittedReject = r; }); + // We do not always await this promise. + this._firstNonInitialNavigationCommittedPromise.catch(() => {}); } _isMainFrame(): boolean { diff --git a/packages/playwright-core/src/server/firefox/ffBrowser.ts b/packages/playwright-core/src/server/firefox/ffBrowser.ts index b26a2850ee..afc0671f70 100644 --- a/packages/playwright-core/src/server/firefox/ffBrowser.ts +++ b/packages/playwright-core/src/server/firefox/ffBrowser.ts @@ -271,6 +271,10 @@ export class FFBrowserContext extends BrowserContext { return this._ffPages().map(ffPage => ffPage._initializedPage).filter(pageOrNull => !!pageOrNull) as Page[]; } + pagesOrErrors() { + return this._ffPages().map(ffPage => ffPage.pageOrError()); + } + async newPageDelegate(): Promise { assertBrowserContextIsNotOwned(this); const { targetId } = await this._browser.session.send('Browser.newPage', { diff --git a/packages/playwright-core/src/server/page.ts b/packages/playwright-core/src/server/page.ts index d626b1ed3c..48c0827c08 100644 --- a/packages/playwright-core/src/server/page.ts +++ b/packages/playwright-core/src/server/page.ts @@ -164,7 +164,6 @@ export class Page extends SdkObject { _clientRequestInterceptor: network.RouteHandler | undefined; _serverRequestInterceptor: network.RouteHandler | undefined; _ownedContext: BrowserContext | undefined; - _pageIsError: Error | undefined; _video: Artifact | null = null; _opener: Page | undefined; private _isServerSideOnly = false; @@ -208,7 +207,7 @@ export class Page extends SdkObject { // context/browser closure. Just ignore the page. if (this._browserContext.isClosingOrClosed()) return; - this._setIsError(error); + this._frameManager.createDummyMainFrameIfNeeded(); } this._initialized = true; this.emitOnContext(contextEvent, this); @@ -709,11 +708,6 @@ export class Page extends SdkObject { await this._ownedContext.close(options); } - private _setIsError(error: Error) { - this._pageIsError = error; - this._frameManager.createDummyMainFrameIfNeeded(); - } - isClosed(): boolean { return this._closedState === 'closed'; } diff --git a/packages/playwright-core/src/server/webkit/wkBrowser.ts b/packages/playwright-core/src/server/webkit/wkBrowser.ts index f4f9f732a5..4e5467fd17 100644 --- a/packages/playwright-core/src/server/webkit/wkBrowser.ts +++ b/packages/playwright-core/src/server/webkit/wkBrowser.ts @@ -243,6 +243,10 @@ export class WKBrowserContext extends BrowserContext { return this._wkPages().map(wkPage => wkPage._initializedPage).filter(pageOrNull => !!pageOrNull) as Page[]; } + pagesOrErrors() { + return this._wkPages().map(wkPage => wkPage.pageOrError()); + } + async newPageDelegate(): Promise { assertBrowserContextIsNotOwned(this); const { pageProxyId } = await this._browser._browserSession.send('Playwright.createPage', { browserContextId: this._browserContextId });