feat(context): introduce BrowserContext close event (#918)

This commit is contained in:
Pavel Feldman 2020-02-11 10:27:19 -08:00 committed by GitHub
parent 5fee93ae96
commit 72b9cf010e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 52 additions and 12 deletions

View file

@ -159,7 +159,7 @@ See [ChromiumBrowser], [FirefoxBrowser] and [WebKitBrowser] for browser-specific
#### event: 'disconnected'
Emitted when Browser gets disconnected from the browser application. This might happen because of one of the following:
- Browser application is closed or crashed.
- The [`browser.disconnect`](#browserdisconnect) method was called.
- The [`browser.close`](#browserclose) method was called.
#### browser.close()
- returns: <[Promise]>
@ -263,6 +263,7 @@ await context.close();
```
<!-- GEN:toc -->
- [event: 'close'](#event-close)
- [browserContext.clearCookies()](#browsercontextclearcookies)
- [browserContext.clearPermissions()](#browsercontextclearpermissions)
- [browserContext.close()](#browsercontextclose)
@ -274,6 +275,13 @@ await context.close();
- [browserContext.setPermissions(origin, permissions[])](#browsercontextsetpermissionsorigin-permissions)
<!-- GEN:stop -->
#### event: 'close'
Emitted when Browser context gets closed. This might happen because of one of the following:
- Browser context is closed.
- Browser application is closed or crashed.
- The [`browser.close`](#browserclose) method was called.
#### browserContext.clearCookies()
- returns: <[Promise]>
@ -426,7 +434,7 @@ page.removeListener('request', logRequest);
```
<!-- GEN:toc -->
- [event: 'close'](#event-close)
- [event: 'close'](#event-close-1)
- [event: 'console'](#event-console)
- [event: 'dialog'](#event-dialog)
- [event: 'domcontentloaded'](#event-domcontentloaded)
@ -3168,7 +3176,7 @@ const { selectors, firefox } = require('playwright'); // Or 'chromium' or 'webk
The [WebSocket] class represents websocket connections in the page.
<!-- GEN:toc -->
- [event: 'close'](#event-close-1)
- [event: 'close'](#event-close-2)
- [event: 'error'](#event-error)
- [event: 'messageReceived'](#event-messagereceived)
- [event: 'messageSent'](#event-messagesent)
@ -3423,7 +3431,7 @@ If the function passed to the `worker.evaluateHandle` returns a [Promise], then
### class: BrowserServer
<!-- GEN:toc -->
- [event: 'close'](#event-close-2)
- [event: 'close'](#event-close-3)
- [browserServer.close()](#browserserverclose)
- [browserServer.kill()](#browserserverkill)
- [browserServer.process()](#browserserverprocess)

View file

@ -25,7 +25,6 @@ export interface Browser extends platform.EventEmitterType {
newPage(options?: BrowserContextOptions): Promise<Page>;
isConnected(): boolean;
close(): Promise<void>;
_defaultContext: BrowserContext | undefined;
}
export type ConnectOptions = {

View file

@ -19,6 +19,8 @@ import { Page } from './page';
import * as network from './network';
import * as types from './types';
import { helper } from './helper';
import * as platform from './platform';
import { Events } from './events';
export interface BrowserContextDelegate {
pages(): Promise<Page[]>;
@ -47,12 +49,13 @@ export type BrowserContextOptions = {
permissions?: { [key: string]: string[] };
};
export class BrowserContext {
export class BrowserContext extends platform.EventEmitter {
private readonly _delegate: BrowserContextDelegate;
readonly _options: BrowserContextOptions;
private _closed = false;
constructor(delegate: BrowserContextDelegate, options: BrowserContextOptions) {
super();
this._delegate = delegate;
this._options = { ...options };
if (!this._options.viewport && this._options.viewport !== null)
@ -114,12 +117,18 @@ export class BrowserContext {
return;
await this._delegate.close();
this._closed = true;
this.emit(Events.BrowserContext.Close);
}
static validateOptions(options: BrowserContextOptions) {
if (options.geolocation)
verifyGeolocation(options.geolocation);
}
_browserClosed() {
this._closed = true;
this.emit(Events.BrowserContext.Close);
}
}
function verifyGeolocation(geolocation: types.Geolocation): types.Geolocation {

View file

@ -56,7 +56,11 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
this._client = connection.rootSession;
this._defaultContext = this._createBrowserContext(null, {});
this._connection.on(ConnectionEvents.Disconnected, () => this.emit(CommonEvents.Browser.Disconnected));
this._connection.on(ConnectionEvents.Disconnected, () => {
for (const context of this.contexts())
context._browserClosed();
this.emit(CommonEvents.Browser.Disconnected);
});
this._client.on('Target.targetCreated', this._targetCreated.bind(this));
this._client.on('Target.targetDestroyed', this._targetDestroyed.bind(this));
this._client.on('Target.targetInfoChanged', this._targetInfoChanged.bind(this));

View file

@ -20,6 +20,10 @@ export const Events = {
Disconnected: 'disconnected'
},
BrowserContext: {
Close: 'close'
},
BrowserServer: {
Close: 'close',
},

View file

@ -50,8 +50,11 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
this._defaultContext = this._createBrowserContext(null, {});
this._contexts = new Map();
this._connection.on(ConnectionEvents.Disconnected, () => this.emit(Events.Browser.Disconnected));
this._connection.on(ConnectionEvents.Disconnected, () => {
for (const context of this.contexts())
context._browserClosed();
this.emit(Events.Browser.Disconnected);
});
this._eventListeners = [
helper.addEventListener(this._connection, 'Target.targetCreated', this._onTargetCreated.bind(this)),
helper.addEventListener(this._connection, 'Target.targetDestroyed', this._onTargetDestroyed.bind(this)),

View file

@ -84,7 +84,6 @@ export class WebKit implements BrowserType {
handleSIGINT = true,
handleSIGTERM = true,
handleSIGHUP = true,
timeout = 30000
} = options;
let temporaryUserDataDir: string | null = null;
@ -136,7 +135,6 @@ export class WebKit implements BrowserType {
},
});
const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to WebKit!`);
transport = new PipeTransport(launchedProcess.stdio[3] as NodeJS.WritableStream, launchedProcess.stdio[4] as NodeJS.ReadableStream);
browserServer = new BrowserServer(launchedProcess, gracefullyClose, launchType === 'server' ? await wrapTransportWithWebSocket(transport, port || 0) : null);
return { browserServer, transport };

View file

@ -66,6 +66,8 @@ export class WKBrowser extends platform.EventEmitter implements Browser {
}
_onDisconnect() {
for (const context of this.contexts())
context._browserClosed();
for (const pageProxy of this._pageProxies.values())
pageProxy.dispose();
this._pageProxies.clear();

View file

@ -192,7 +192,7 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
await page.goto(server.EMPTY_PAGE);
const target = await targetPromise;
expect(await target.page()).toBe(page);
await page.close();
await page.context().close();
});
it('should fire target events', async function({browser, newContext, server}) {
const context = await newContext();

View file

@ -172,6 +172,19 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
expect(error.message).toContain('has been closed');
await browserServer.close();
});
it('should emit close events on pages and contexts', async({server}) => {
const browserServer = await playwright.launchServer({...defaultBrowserOptions });
const remote = await playwright.connect({ wsEndpoint: browserServer.wsEndpoint() });
const context = await remote.newContext();
const page = await context.newPage();
let contextClosed = false;
let pageClosed = false;
context.on('close', e => contextClosed = true);
page.on('close', e => pageClosed = true);
await browserServer.close();
expect(contextClosed).toBeTruthy();
expect(pageClosed).toBeTruthy();
});
});
describe('Browser.close', function() {