more cleanup

This commit is contained in:
Dmitry Gozman 2024-12-13 15:19:01 +00:00
parent b0dc3efc2d
commit fc8112f904
11 changed files with 42 additions and 58 deletions

View file

@ -80,9 +80,9 @@ export class BidiPage implements PageDelegate {
// Initialize main frame.
// TODO: Wait for first execution context to be created and maybe about:blank navigated.
this._initialize()
.finally(() => this._page.initOpener(this._opener?._page))
.then(() => this._page.reportAsNew(), error => this._page.reportAsNew(error));
this._initialize().then(
() => this._page.reportAsNew(this._opener?._page),
error => this._page.reportAsNew(this._opener?._page, error));
}
private async _initialize() {
@ -101,10 +101,6 @@ export class BidiPage implements PageDelegate {
return Promise.all(this._page.allInitScripts().map(initScript => this.addInitScript(initScript)));
}
potentiallyUninitializedPage(): Page {
return this._page;
}
didClose() {
this._session.dispose();
eventsHelper.removeEventListeners(this._sessionListeners);

View file

@ -257,7 +257,7 @@ export abstract class BrowserContext extends SdkObject {
}
pages(): Page[] {
return this.possiblyUninitializedPages().filter(page => page.initialized());
return this.possiblyUninitializedPages().filter(page => page.initializedOrUndefined());
}
// BrowserContext methods.

View file

@ -259,10 +259,10 @@ export class CRBrowser extends Browser {
}
page.willBeginDownload();
let originPage = page._page.initialized();
let originPage = page._page.initializedOrUndefined();
// If it's a new window download, report it on the opener page.
if (!originPage && page._opener)
originPage = page._opener._page.initialized();
originPage = page._opener._page.initializedOrUndefined();
if (!originPage)
return;
this._downloadCreated(originPage, payload.guid, payload.url, payload.suggestedFilename);
@ -544,7 +544,7 @@ export class CRBrowserContext extends BrowserContext {
// When persistent context is closed, we do not necessary get Target.detachedFromTarget
// for all the background pages.
for (const [targetId, backgroundPage] of this._browser._backgroundPages.entries()) {
if (backgroundPage._browserContext === this && backgroundPage._page.initialized()) {
if (backgroundPage._browserContext === this && backgroundPage._page.initializedOrUndefined()) {
backgroundPage.didClose();
this._browser._backgroundPages.delete(targetId);
}
@ -569,7 +569,7 @@ export class CRBrowserContext extends BrowserContext {
backgroundPages(): Page[] {
const result: Page[] = [];
for (const backgroundPage of this._browser._backgroundPages.values()) {
if (backgroundPage._browserContext === this && backgroundPage._page.initialized())
if (backgroundPage._browserContext === this && backgroundPage._page.initializedOrUndefined())
result.push(backgroundPage._page);
}
return result;

View file

@ -108,9 +108,9 @@ export class CRPage implements PageDelegate {
}
const createdEvent = this._isBackgroundPage ? CRBrowserContext.CREvents.BackgroundPage : BrowserContext.Events.Page;
this._mainFrameSession._initialize(bits.hasUIWindow)
.finally(() => this._page.initOpener(this._opener?._page))
.then(() => this._page.reportAsNew(undefined, createdEvent), error => this._page.reportAsNew(error, createdEvent));
this._mainFrameSession._initialize(bits.hasUIWindow).then(
() => this._page.reportAsNew(this._opener?._page, undefined, createdEvent),
error => this._page.reportAsNew(this._opener?._page, error, createdEvent));
}
private async _forAllFrameSessions(cb: (frame: FrameSession) => Promise<any>) {
@ -873,7 +873,7 @@ class FrameSession {
}
_willBeginDownload() {
if (!this._crPage._page.initialized()) {
if (!this._crPage._page.initializedOrUndefined()) {
// Resume the page creation with an error. The page will automatically close right
// after the download begins.
this._firstNonInitialNavigationCommittedReject(new Error('Starting new page download'));

View file

@ -133,7 +133,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
const requestDispatcher = RequestDispatcher.from(this, request);
this._dispatchEvent('request', {
request: requestDispatcher,
page: PageDispatcher.fromNullable(this, request.frame()?._page.initialized())
page: PageDispatcher.fromNullable(this, request.frame()?._page.initializedOrUndefined())
});
});
this.addObjectListener(BrowserContext.Events.Response, (response: Response) => {
@ -142,7 +142,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
return;
this._dispatchEvent('response', {
response: ResponseDispatcher.from(this, response),
page: PageDispatcher.fromNullable(this, response.frame()?._page.initialized())
page: PageDispatcher.fromNullable(this, response.frame()?._page.initializedOrUndefined())
});
});
this.addObjectListener(BrowserContext.Events.RequestFailed, (request: Request) => {
@ -153,7 +153,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
request: RequestDispatcher.from(this, request),
failureText: request._failureText || undefined,
responseEndTiming: request._responseEndTiming,
page: PageDispatcher.fromNullable(this, request.frame()?._page.initialized())
page: PageDispatcher.fromNullable(this, request.frame()?._page.initializedOrUndefined())
});
});
this.addObjectListener(BrowserContext.Events.RequestFinished, ({ request, response }: { request: Request, response: Response | null }) => {
@ -164,13 +164,13 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
request: RequestDispatcher.from(this, request),
response: ResponseDispatcher.fromNullable(this, response),
responseEndTiming: request._responseEndTiming,
page: PageDispatcher.fromNullable(this, request.frame()?._page.initialized()),
page: PageDispatcher.fromNullable(this, request.frame()?._page.initializedOrUndefined()),
});
});
}
private _shouldDispatchNetworkEvent(request: Request, event: channels.BrowserContextUpdateSubscriptionParams['event'] & channels.PageUpdateSubscriptionParams['event']): boolean {
return this._shouldDispatchEvent(request.frame()?._page?.initialized(), event);
return this._shouldDispatchEvent(request.frame()?._page?.initializedOrUndefined(), event);
}
private _shouldDispatchEvent(page: Page | undefined, event: channels.BrowserContextUpdateSubscriptionParams['event'] & channels.PageUpdateSubscriptionParams['event']): boolean {

View file

@ -24,7 +24,7 @@ export class DialogDispatcher extends Dispatcher<Dialog, channels.DialogChannel,
_type_Dialog = true;
constructor(scope: BrowserContextDispatcher, dialog: Dialog) {
const page = PageDispatcher.fromNullable(scope, dialog.page().initialized());
const page = PageDispatcher.fromNullable(scope, dialog.page().initializedOrUndefined());
// Prefer scoping to the page, unless we don't have one.
super(page || scope, dialog, 'Dialog', {
page,

View file

@ -136,14 +136,14 @@ export class FFBrowser extends Browser {
// Abort the navigation that turned into download.
ffPage._page._frameManager.frameAbortedNavigation(payload.frameId, 'Download is starting');
let originPage = ffPage._page.initialized();
let originPage = ffPage._page.initializedOrUndefined();
// If it's a new window download, report it on the opener page.
if (!originPage) {
// Resume the page creation with an error. The page will automatically close right
// after the download begins.
ffPage._markAsError(new Error('Starting new page download'));
if (ffPage._opener)
originPage = ffPage._opener._page.initialized();
originPage = ffPage._opener._page.initializedOrUndefined();
}
if (!originPage)
return;

View file

@ -48,7 +48,7 @@ export class FFPage implements PageDelegate {
readonly _page: Page;
readonly _networkManager: FFNetworkManager;
readonly _browserContext: FFBrowserContext;
private _initializationFailed = false;
private _reportedAsNew = false;
readonly _opener: FFPage | null;
private readonly _contextIdToContext: Map<string, dom.FrameExecutionContext>;
private _eventListeners: RegisteredListener[];
@ -99,31 +99,23 @@ export class FFPage implements PageDelegate {
eventsHelper.addEventListener(this._session, 'Page.screencastFrame', this._onScreencastFrame.bind(this)),
];
this._session.once('Page.ready', async () => {
await this._page.initOpener(this._opener?._page);
if (this._initializationFailed)
this._session.once('Page.ready', () => {
if (this._reportedAsNew)
return;
this._page.reportAsNew();
this._reportedAsNew = true;
this._page.reportAsNew(this._opener?._page);
});
// Ideally, we somehow ensure that utility world is created before Page.ready arrives, but currently it is racy.
// Therefore, we can end up with an initialized page without utility world, although very unlikely.
this.addInitScript(new InitScript('', true), UTILITY_WORLD_NAME).catch(e => this._markAsError(e));
}
potentiallyUninitializedPage(): Page {
return this._page;
}
async _markAsError(error: Error) {
// Same error may be reported twice: channel disconnected and session.send fails.
if (this._initializationFailed)
if (this._reportedAsNew)
return;
this._initializationFailed = true;
if (!this._page.initialized()) {
await this._page.initOpener(this._opener?._page);
this._page.reportAsNew(error);
}
this._reportedAsNew = true;
this._page.reportAsNew(this._opener?._page, error);
}
_onWebSocketCreated(event: Protocol.Page.webSocketCreatedPayload) {

View file

@ -192,15 +192,16 @@ export class Page extends SdkObject {
this.coverage = delegate.coverage ? delegate.coverage() : null;
}
async initOpener(opener: Page | undefined) {
if (!opener)
return;
const openerPageOrError = await opener.waitForInitializedOrError();
if (openerPageOrError instanceof Page && !openerPageOrError.isClosed())
this._opener = openerPageOrError;
async reportAsNew(opener: Page | undefined, error: Error | undefined = undefined, contextEvent: string = BrowserContext.Events.Page) {
if (opener) {
const openerPageOrError = await opener.waitForInitializedOrError();
if (openerPageOrError instanceof Page && !openerPageOrError.isClosed())
this._opener = openerPageOrError;
}
this._markInitialized(error, contextEvent);
}
reportAsNew(error: Error | undefined = undefined, contextEvent: string = BrowserContext.Events.Page) {
private _markInitialized(error: Error | undefined = undefined, contextEvent: string = BrowserContext.Events.Page) {
if (error) {
// Initialization error could have happened because of
// context/browser closure. Just ignore the page.
@ -228,7 +229,7 @@ export class Page extends SdkObject {
this._initializedPromise.resolve(this._initialized);
}
initialized(): Page | undefined {
initializedOrUndefined(): Page | undefined {
return this._initialized ? this : undefined;
}

View file

@ -121,14 +121,14 @@ export class WKBrowser extends Browser {
// abort navigation that is still running. We should be able to fix this by
// instrumenting policy decision start/proceed/cancel.
page._page._frameManager.frameAbortedNavigation(payload.frameId, 'Download is starting');
let originPage = page._page.initialized();
let originPage = page._page.initializedOrUndefined();
// If it's a new window download, report it on the opener page.
if (!originPage) {
// Resume the page creation with an error. The page will automatically close right
// after the download begins.
page._firstNonInitialNavigationCommittedReject(new Error('Starting new page download'));
if (page._opener)
originPage = page._opener._page.initialized();
originPage = page._opener._page.initializedOrUndefined();
}
if (!originPage)
return;

View file

@ -108,10 +108,6 @@ export class WKPage implements PageDelegate {
}
}
potentiallyUninitializedPage(): Page {
return this._page;
}
private async _initializePageProxySession() {
if (this._page._browserContext.isSettingStorageState())
return;
@ -280,7 +276,7 @@ export class WKPage implements PageDelegate {
}
handleProvisionalLoadFailed(event: Protocol.Playwright.provisionalLoadFailedPayload) {
if (!this._page.initialized()) {
if (!this._page.initializedOrUndefined()) {
this._firstNonInitialNavigationCommittedReject(new Error('Initial load failed'));
return;
}
@ -309,7 +305,7 @@ export class WKPage implements PageDelegate {
assert(targetInfo.type === 'page', 'Only page targets are expected in WebKit, received: ' + targetInfo.type);
if (!targetInfo.isProvisional) {
assert(!this._page.initialized());
assert(!this._page.initializedOrUndefined());
let pageOrError: Page | Error;
try {
this._setSession(session);
@ -336,8 +332,7 @@ export class WKPage implements PageDelegate {
// Avoid rejection on disconnect.
this._firstNonInitialNavigationCommittedPromise.catch(() => {});
}
await this._page.initOpener(this._opener?._page);
this._page.reportAsNew(pageOrError instanceof Page ? undefined : pageOrError);
this._page.reportAsNew(this._opener?._page, pageOrError instanceof Page ? undefined : pageOrError);
} else {
assert(targetInfo.isProvisional);
assert(!this._provisionalPage);