chore: start listening for navigation events before navigation starts (#32237)

There is a chance in case of cross-process navigation that the
navigation event comes before `navigateFrame` finishes.
This commit is contained in:
Yury Semikhatsky 2024-08-21 08:34:55 -07:00 committed by GitHub
parent 6512bccffd
commit 918dbe5e3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 21 additions and 8 deletions

View File

@ -659,18 +659,24 @@ export class Frame extends SdkObject {
}
url = helper.completeUserURL(url);
const sameDocument = helper.waitForEvent(progress, this, Frame.Events.InternalNavigation, (e: NavigationEvent) => !e.newDocument);
const navigateResult = await this._page._delegate.navigateFrame(this, url, referer);
const navigationEvents: NavigationEvent[] = [];
const collectNavigations = (arg: NavigationEvent) => navigationEvents.push(arg);
this.on(Frame.Events.InternalNavigation, collectNavigations);
const navigateResult = await this._page._delegate.navigateFrame(this, url, referer).finally(
() => this.off(Frame.Events.InternalNavigation, collectNavigations));
let event: NavigationEvent;
if (navigateResult.newDocumentId) {
sameDocument.dispose();
event = await helper.waitForEvent(progress, this, Frame.Events.InternalNavigation, (event: NavigationEvent) => {
const predicate = (event: NavigationEvent) => {
// We are interested either in this specific document, or any other document that
// did commit and replaced the expected document.
return event.newDocument && (event.newDocument.documentId === navigateResult.newDocumentId || !event.error);
}).promise;
};
const events = navigationEvents.filter(predicate);
if (events.length)
event = events[0];
else
event = await helper.waitForEvent(progress, this, Frame.Events.InternalNavigation, predicate).promise;
if (event.newDocument!.documentId !== navigateResult.newDocumentId) {
// This is just a sanity check. In practice, new navigation should
// cancel the previous one and report "request cancelled"-like error.
@ -679,7 +685,13 @@ export class Frame extends SdkObject {
if (event.error)
throw event.error;
} else {
event = await sameDocument.promise;
// Wait for same document navigation.
const predicate = (e: NavigationEvent) => !e.newDocument;
const events = navigationEvents.filter(predicate);
if (events.length)
event = events[0];
else
event = await helper.waitForEvent(progress, this, Frame.Events.InternalNavigation, predicate).promise;
}
if (!this._firedLifecycleEvents.has(waitUntil))

View File

@ -181,8 +181,9 @@ it('should work with Cross-Origin-Opener-Policy after redirect', async ({ page,
it('should properly cancel Cross-Origin-Opener-Policy navigation', {
annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/32107' },
}, async ({ page, server, browserName, isLinux }) => {
}, async ({ page, server, browserName, isLinux, headless }) => {
it.fixme(browserName === 'webkit' && isLinux, 'Started failing after https://commits.webkit.org/281488@main');
it.fixme(browserName === 'chromium' && headless, 'COOP navigation cancels the one that starts later');
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
res.end();