fix(crash): improve documentation for crash, reject waitForEvent (#2694)
This commit is contained in:
parent
bc3050776e
commit
807dc1f324
26
docs/api.md
26
docs/api.md
|
|
@ -783,7 +783,31 @@ page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
|
||||||
|
|
||||||
#### event: 'crash'
|
#### event: 'crash'
|
||||||
|
|
||||||
Emitted when the page crashes. Browser pages might crash if they try to allocate too much memory.
|
Emitted when the page crashes. Browser pages might crash if they try to allocate too much memory. When the page crashes, ongoing and subsequent operations will throw.
|
||||||
|
|
||||||
|
The most common way to deal with crashes is to catch an exception:
|
||||||
|
```js
|
||||||
|
try {
|
||||||
|
// Crash might happen during a click.
|
||||||
|
await page.click('button');
|
||||||
|
// Or while waiting for an event.
|
||||||
|
await page.waitForEvent('popup');
|
||||||
|
} catch (e) {
|
||||||
|
// When the page crashes, exception message contains 'crash'.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
However, when manually listening to events, it might be useful to avoid stalling when the page crashes. In this case, handling `crash` event helps:
|
||||||
|
|
||||||
|
```js
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
page.on('requestfinished', async request => {
|
||||||
|
if (await someProcessing(request))
|
||||||
|
resolve(request);
|
||||||
|
});
|
||||||
|
page.on('crash', error => reject(error));
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
#### event: 'dialog'
|
#### event: 'dialog'
|
||||||
- <[Dialog]>
|
- <[Dialog]>
|
||||||
|
|
|
||||||
|
|
@ -983,6 +983,7 @@ class SignalBarrier {
|
||||||
const frameTask = new FrameTask(frame, this._progress);
|
const frameTask = new FrameTask(frame, this._progress);
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
frame._page._disconnectedPromise,
|
frame._page._disconnectedPromise,
|
||||||
|
frame._page._crashedPromise,
|
||||||
frame._detachedPromise,
|
frame._detachedPromise,
|
||||||
frameTask.waitForNewDocument(),
|
frameTask.waitForNewDocument(),
|
||||||
frameTask.waitForSameDocumentNavigation(),
|
frameTask.waitForSameDocumentNavigation(),
|
||||||
|
|
@ -1114,6 +1115,7 @@ class FrameTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
function abortProgressOnFrameDetach(controller: ProgressController, frame: Frame) {
|
function abortProgressOnFrameDetach(controller: ProgressController, frame: Frame) {
|
||||||
frame._page._disconnectedPromise.then(() => controller.abort(new Error('Navigation failed because browser has disconnected!')));
|
frame._page._disconnectedPromise.then(() => controller.abort(new Error('Navigation failed because page was closed!')));
|
||||||
|
frame._page._crashedPromise.then(() => controller.abort(new Error('Navigation failed because page crashed!')));
|
||||||
frame._detachedPromise.then(() => controller.abort(new Error('Navigating frame was detached!')));
|
frame._detachedPromise.then(() => controller.abort(new Error('Navigating frame was detached!')));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,8 @@ export class Page extends EventEmitter {
|
||||||
private _disconnected = false;
|
private _disconnected = false;
|
||||||
private _disconnectedCallback: (e: Error) => void;
|
private _disconnectedCallback: (e: Error) => void;
|
||||||
readonly _disconnectedPromise: Promise<Error>;
|
readonly _disconnectedPromise: Promise<Error>;
|
||||||
|
private _crashedCallback: (e: Error) => void;
|
||||||
|
readonly _crashedPromise: Promise<Error>;
|
||||||
readonly _browserContext: BrowserContextBase;
|
readonly _browserContext: BrowserContextBase;
|
||||||
readonly keyboard: input.Keyboard;
|
readonly keyboard: input.Keyboard;
|
||||||
readonly mouse: input.Mouse;
|
readonly mouse: input.Mouse;
|
||||||
|
|
@ -121,6 +123,8 @@ export class Page extends EventEmitter {
|
||||||
this._closedPromise = new Promise(f => this._closedCallback = f);
|
this._closedPromise = new Promise(f => this._closedCallback = f);
|
||||||
this._disconnectedCallback = () => {};
|
this._disconnectedCallback = () => {};
|
||||||
this._disconnectedPromise = new Promise(f => this._disconnectedCallback = f);
|
this._disconnectedPromise = new Promise(f => this._disconnectedCallback = f);
|
||||||
|
this._crashedCallback = () => {};
|
||||||
|
this._crashedPromise = new Promise(f => this._crashedCallback = f);
|
||||||
this._browserContext = browserContext;
|
this._browserContext = browserContext;
|
||||||
this._state = {
|
this._state = {
|
||||||
viewportSize: browserContext._options.viewport ? { ...browserContext._options.viewport } : null,
|
viewportSize: browserContext._options.viewport ? { ...browserContext._options.viewport } : null,
|
||||||
|
|
@ -153,12 +157,13 @@ export class Page extends EventEmitter {
|
||||||
|
|
||||||
_didCrash() {
|
_didCrash() {
|
||||||
this.emit(Events.Page.Crash);
|
this.emit(Events.Page.Crash);
|
||||||
|
this._crashedCallback(new Error('Page crashed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
_didDisconnect() {
|
_didDisconnect() {
|
||||||
assert(!this._disconnected, 'Page disconnected twice');
|
assert(!this._disconnected, 'Page disconnected twice');
|
||||||
this._disconnected = true;
|
this._disconnected = true;
|
||||||
this._disconnectedCallback(new Error('Target closed'));
|
this._disconnectedCallback(new Error('Page closed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onFileChooserOpened(handle: dom.ElementHandle) {
|
async _onFileChooserOpened(handle: dom.ElementHandle) {
|
||||||
|
|
@ -335,6 +340,8 @@ export class Page extends EventEmitter {
|
||||||
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
|
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
|
||||||
const progressController = new ProgressController(this._logger, this._timeoutSettings.timeout(options), 'page.waitForEvent');
|
const progressController = new ProgressController(this._logger, this._timeoutSettings.timeout(options), 'page.waitForEvent');
|
||||||
this._disconnectedPromise.then(error => progressController.abort(error));
|
this._disconnectedPromise.then(error => progressController.abort(error));
|
||||||
|
if (event !== Events.Page.Crash)
|
||||||
|
this._crashedPromise.then(error => progressController.abort(error));
|
||||||
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate));
|
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ describe('Browser.disconnect', function() {
|
||||||
await server.waitForRequest('/one-style.css');
|
await server.waitForRequest('/one-style.css');
|
||||||
await remote.close();
|
await remote.close();
|
||||||
const error = await navigationPromise;
|
const error = await navigationPromise;
|
||||||
expect(error.message).toContain('Navigation failed because browser has disconnected!');
|
expect(error.message).toContain('Navigation failed because page was closed!');
|
||||||
await browserServer._checkLeaks();
|
await browserServer._checkLeaks();
|
||||||
await browserServer.close();
|
await browserServer.close();
|
||||||
});
|
});
|
||||||
|
|
@ -211,7 +211,7 @@ describe('Browser.close', function() {
|
||||||
]);
|
]);
|
||||||
for (let i = 0; i < 2; i++) {
|
for (let i = 0; i < 2; i++) {
|
||||||
const message = results[i].message;
|
const message = results[i].message;
|
||||||
expect(message).toContain('Target closed');
|
expect(message).toContain('Page closed');
|
||||||
expect(message).not.toContain('Timeout');
|
expect(message).not.toContain('Timeout');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ describe('Page.close', function() {
|
||||||
]);
|
]);
|
||||||
for (let i = 0; i < 2; i++) {
|
for (let i = 0; i < 2; i++) {
|
||||||
const message = results[i].message;
|
const message = results[i].message;
|
||||||
expect(message).toContain('Target closed');
|
expect(message).toContain('Page closed');
|
||||||
expect(message).not.toContain('Timeout');
|
expect(message).not.toContain('Timeout');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -130,6 +130,28 @@ describe.fail(FFOX && WIN)('Page.Events.Crash', function() {
|
||||||
expect(err).toBeTruthy();
|
expect(err).toBeTruthy();
|
||||||
expect(err.message).toContain('crash');
|
expect(err.message).toContain('crash');
|
||||||
});
|
});
|
||||||
|
it('should cancel waitForEvent when page crashes', async({page}) => {
|
||||||
|
await page.setContent(`<div>This page should crash</div>`);
|
||||||
|
const promise = page.waitForEvent('response').catch(e => e);
|
||||||
|
crash(page);
|
||||||
|
const error = await promise;
|
||||||
|
expect(error.message).toContain('Page crashed');
|
||||||
|
});
|
||||||
|
it('should cancel navigation when page crashes', async({page, server}) => {
|
||||||
|
await page.setContent(`<div>This page should crash</div>`);
|
||||||
|
server.setRoute('/one-style.css', () => {});
|
||||||
|
const promise = page.goto(server.PREFIX + '/one-style.html').catch(e => e);
|
||||||
|
await page.waitForNavigation({ waitUntil: 'domcontentloaded' });
|
||||||
|
crash(page);
|
||||||
|
const error = await promise;
|
||||||
|
expect(error.message).toContain('Navigation failed because page crashed');
|
||||||
|
});
|
||||||
|
it('should be able to close context when page crashes', async({page}) => {
|
||||||
|
await page.setContent(`<div>This page should crash</div>`);
|
||||||
|
crash(page);
|
||||||
|
await page.waitForEvent('crash');
|
||||||
|
await page.context().close();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page.opener', function() {
|
describe('Page.opener', function() {
|
||||||
|
|
@ -353,7 +375,7 @@ describe('Page.waitForEvent', function() {
|
||||||
const waitForPromise = page.waitForEvent('download').catch(e => error = e);
|
const waitForPromise = page.waitForEvent('download').catch(e => error = e);
|
||||||
await page.close();
|
await page.close();
|
||||||
await waitForPromise;
|
await waitForPromise;
|
||||||
expect(error.message).toContain('Target closed');
|
expect(error.message).toContain('Page closed');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue