fix(reload): make sure reload() does not pick same-document navigaiton (#16504)
We lack `documentId` when doing a reload over browser protocols, so `reload()` waits for the next navigation to finish. Sometimes, the page might issue a same-document navigation while reload is in progress, which confuses the reload command. To fix the issue, just ignore same-document navigations for reload, because it is always a new document.
This commit is contained in:
parent
0ff00e5978
commit
3ae50861a3
|
|
@ -715,7 +715,7 @@ export class Frame extends SdkObject {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _waitForNavigation(progress: Progress, options: types.NavigateOptions): Promise<network.Response | null> {
|
async _waitForNavigation(progress: Progress, requiresNewDocument: boolean, options: types.NavigateOptions): Promise<network.Response | null> {
|
||||||
const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||||
progress.log(`waiting for navigation until "${waitUntil}"`);
|
progress.log(`waiting for navigation until "${waitUntil}"`);
|
||||||
|
|
||||||
|
|
@ -723,6 +723,8 @@ export class Frame extends SdkObject {
|
||||||
// Any failed navigation results in a rejection.
|
// Any failed navigation results in a rejection.
|
||||||
if (event.error)
|
if (event.error)
|
||||||
return true;
|
return true;
|
||||||
|
if (requiresNewDocument && !event.newDocument)
|
||||||
|
return false;
|
||||||
progress.log(` navigated to "${this._url}"`);
|
progress.log(` navigated to "${this._url}"`);
|
||||||
return true;
|
return true;
|
||||||
}).promise;
|
}).promise;
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,8 @@ export class Page extends SdkObject {
|
||||||
// Note: waitForNavigation may fail before we get response to reload(),
|
// Note: waitForNavigation may fail before we get response to reload(),
|
||||||
// so we should await it immediately.
|
// so we should await it immediately.
|
||||||
const [response] = await Promise.all([
|
const [response] = await Promise.all([
|
||||||
this.mainFrame()._waitForNavigation(progress, options),
|
// Reload must be a new document, and should not be confused with a stray pushState.
|
||||||
|
this.mainFrame()._waitForNavigation(progress, true /* requiresNewDocument */, options),
|
||||||
this._delegate.reload(),
|
this._delegate.reload(),
|
||||||
]);
|
]);
|
||||||
await this._doSlowMo();
|
await this._doSlowMo();
|
||||||
|
|
@ -386,7 +387,7 @@ export class Page extends SdkObject {
|
||||||
// Note: waitForNavigation may fail before we get response to goBack,
|
// Note: waitForNavigation may fail before we get response to goBack,
|
||||||
// so we should catch it immediately.
|
// so we should catch it immediately.
|
||||||
let error: Error | undefined;
|
let error: Error | undefined;
|
||||||
const waitPromise = this.mainFrame()._waitForNavigation(progress, options).catch(e => {
|
const waitPromise = this.mainFrame()._waitForNavigation(progress, false /* requiresNewDocument */, options).catch(e => {
|
||||||
error = e;
|
error = e;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
@ -407,7 +408,7 @@ export class Page extends SdkObject {
|
||||||
// Note: waitForNavigation may fail before we get response to goForward,
|
// Note: waitForNavigation may fail before we get response to goForward,
|
||||||
// so we should catch it immediately.
|
// so we should catch it immediately.
|
||||||
let error: Error | undefined;
|
let error: Error | undefined;
|
||||||
const waitPromise = this.mainFrame()._waitForNavigation(progress, options).catch(e => {
|
const waitPromise = this.mainFrame()._waitForNavigation(progress, false /* requiresNewDocument */, options).catch(e => {
|
||||||
error = e;
|
error = e;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,38 @@ it('page.reload during renderer-initiated navigation', async ({ page, server })
|
||||||
await page.waitForSelector('text=hello');
|
await page.waitForSelector('text=hello');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('page.reload should not resolve with same-document navigation', async ({ page, server }) => {
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
// 1. Make sure execution contexts are ready for fast evaluate.
|
||||||
|
await page.evaluate('1');
|
||||||
|
|
||||||
|
// 2. Stall the reload request.
|
||||||
|
let response;
|
||||||
|
server.setRoute('/empty.html', (req, res) => { response = res; });
|
||||||
|
const requestPromise = server.waitForRequest('/empty.html');
|
||||||
|
|
||||||
|
// 3. Trigger push state that could resolve the reload.
|
||||||
|
page.evaluate(() => {
|
||||||
|
window.history.pushState({}, '');
|
||||||
|
}).catch(() => {});
|
||||||
|
|
||||||
|
// 4. Trigger the reload, it should not resolve.
|
||||||
|
const reloadPromise = page.reload();
|
||||||
|
|
||||||
|
// 5. Trigger push state again, for the good measure :)
|
||||||
|
page.evaluate(() => {
|
||||||
|
window.history.pushState({}, '');
|
||||||
|
}).catch(() => {});
|
||||||
|
|
||||||
|
// 5. Serve the request, it should resolve the reload.
|
||||||
|
await requestPromise;
|
||||||
|
response.end('hello');
|
||||||
|
|
||||||
|
// 6. Check the reload response.
|
||||||
|
const gotResponse = await reloadPromise;
|
||||||
|
expect(await gotResponse.text()).toBe('hello');
|
||||||
|
});
|
||||||
|
|
||||||
it('page.goBack during renderer-initiated navigation', async ({ page, server }) => {
|
it('page.goBack during renderer-initiated navigation', async ({ page, server }) => {
|
||||||
await page.goto(server.PREFIX + '/one-style.html');
|
await page.goto(server.PREFIX + '/one-style.html');
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue