mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
Carefully manage unhandled rejections for navigation (#741)
Currently, navigation watcher throws exception if timeout is exceeded. Due to the way it is used in `page.navigate`, the promise get's rejected before it is awaited, which is considered to be "unhandled promise rejection". Fixes #738
This commit is contained in:
parent
0db6165d73
commit
e5c17eecb9
@ -33,7 +33,7 @@ class NavigatorWatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {!Promise<!Map<string, !Response>>}
|
* @return {!Promise<?Error>}
|
||||||
*/
|
*/
|
||||||
async waitForNavigation() {
|
async waitForNavigation() {
|
||||||
this._requestIds = new Set();
|
this._requestIds = new Set();
|
||||||
@ -70,8 +70,7 @@ class NavigatorWatcher {
|
|||||||
|
|
||||||
const error = await Promise.race(navigationPromises);
|
const error = await Promise.race(navigationPromises);
|
||||||
this._cleanup();
|
this._cleanup();
|
||||||
if (error)
|
return error ? new Error(error) : null;
|
||||||
throw new Error(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
|
11
lib/Page.js
11
lib/Page.js
@ -372,7 +372,7 @@ class Page extends EventEmitter {
|
|||||||
const watcher = new NavigatorWatcher(this._client, this._ignoreHTTPSErrors, options);
|
const watcher = new NavigatorWatcher(this._client, this._ignoreHTTPSErrors, options);
|
||||||
const responses = new Map();
|
const responses = new Map();
|
||||||
const listener = helper.addEventListener(this._networkManager, NetworkManager.Events.Response, response => responses.set(response.url, response));
|
const listener = helper.addEventListener(this._networkManager, NetworkManager.Events.Response, response => responses.set(response.url, response));
|
||||||
const result = watcher.waitForNavigation();
|
const navigationPromise = watcher.waitForNavigation();
|
||||||
|
|
||||||
const referrer = this._networkManager.extraHTTPHeaders()['referer'];
|
const referrer = this._networkManager.extraHTTPHeaders()['referer'];
|
||||||
try {
|
try {
|
||||||
@ -382,8 +382,10 @@ class Page extends EventEmitter {
|
|||||||
watcher.cancel();
|
watcher.cancel();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
await result;
|
const error = await navigationPromise;
|
||||||
helper.removeEventListeners([listener]);
|
helper.removeEventListeners([listener]);
|
||||||
|
if (error)
|
||||||
|
throw error;
|
||||||
if (this._frameManager.isMainFrameLoadingFailed())
|
if (this._frameManager.isMainFrameLoadingFailed())
|
||||||
throw new Error('Failed to navigate: ' + url);
|
throw new Error('Failed to navigate: ' + url);
|
||||||
return responses.get(this.mainFrame().url()) || null;
|
return responses.get(this.mainFrame().url()) || null;
|
||||||
@ -410,9 +412,10 @@ class Page extends EventEmitter {
|
|||||||
|
|
||||||
const responses = new Map();
|
const responses = new Map();
|
||||||
const listener = helper.addEventListener(this._networkManager, NetworkManager.Events.Response, response => responses.set(response.url, response));
|
const listener = helper.addEventListener(this._networkManager, NetworkManager.Events.Response, response => responses.set(response.url, response));
|
||||||
await watcher.waitForNavigation();
|
const error = await watcher.waitForNavigation();
|
||||||
helper.removeEventListeners([listener]);
|
helper.removeEventListeners([listener]);
|
||||||
|
if (error)
|
||||||
|
throw error;
|
||||||
return responses.get(this.mainFrame().url()) || null;
|
return responses.get(this.mainFrame().url()) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
test/test.js
15
test/test.js
@ -598,15 +598,16 @@ describe('Page', function() {
|
|||||||
expect(error.message).toContain('Failed to navigate');
|
expect(error.message).toContain('Failed to navigate');
|
||||||
}));
|
}));
|
||||||
it('should fail when exceeding maximum navigation timeout', SX(async function() {
|
it('should fail when exceeding maximum navigation timeout', SX(async function() {
|
||||||
let error = null;
|
let hasUnhandledRejection = false;
|
||||||
|
const unhandledRejectionHandler = () => hasUnhandledRejection = true;
|
||||||
|
process.on('unhandledRejection', unhandledRejectionHandler);
|
||||||
// Hang for request to the empty.html
|
// Hang for request to the empty.html
|
||||||
server.setRoute('/empty.html', (req, res) => { });
|
server.setRoute('/empty.html', (req, res) => { });
|
||||||
try {
|
let error = null;
|
||||||
await page.goto(PREFIX + '/empty.html', {timeout: 59});
|
await page.goto(PREFIX + '/empty.html', {timeout: 1}).catch(e => error = e);
|
||||||
} catch (e) {
|
expect(hasUnhandledRejection).toBe(false);
|
||||||
error = e;
|
expect(error.message).toContain('Navigation Timeout Exceeded: 1ms');
|
||||||
}
|
process.removeListener('unhandledRejection', unhandledRejectionHandler);
|
||||||
expect(error.message).toContain('Navigation Timeout Exceeded: 59ms');
|
|
||||||
}));
|
}));
|
||||||
it('should work when navigating to valid url', SX(async function() {
|
it('should work when navigating to valid url', SX(async function() {
|
||||||
const response = await page.goto(EMPTY_PAGE);
|
const response = await page.goto(EMPTY_PAGE);
|
||||||
|
Loading…
Reference in New Issue
Block a user