chore(workers): align worker lifecycle evens with other APIs (#1147)

This commit is contained in:
Yury Semikhatsky 2020-02-27 14:02:48 -08:00 committed by GitHub
parent c6fde22b1f
commit 9d6aa967f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 30 deletions

View File

@ -481,8 +481,7 @@ page.removeListener('request', logRequest);
- [event: 'requestfailed'](#event-requestfailed) - [event: 'requestfailed'](#event-requestfailed)
- [event: 'requestfinished'](#event-requestfinished) - [event: 'requestfinished'](#event-requestfinished)
- [event: 'response'](#event-response) - [event: 'response'](#event-response)
- [event: 'workercreated'](#event-workercreated) - [event: 'worker'](#event-worker)
- [event: 'workerdestroyed'](#event-workerdestroyed)
- [page.$(selector)](#pageselector) - [page.$(selector)](#pageselector)
- [page.$$(selector)](#pageselector-1) - [page.$$(selector)](#pageselector-1)
- [page.$$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args) - [page.$$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args)
@ -653,16 +652,11 @@ Emitted when a request finishes successfully.
Emitted when a [response] is received. Emitted when a [response] is received.
#### event: 'workercreated' #### event: 'worker'
- <[Worker]> - <[Worker]>
Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned by the page. Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned by the page.
#### event: 'workerdestroyed'
- <[Worker]>
Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is terminated.
#### page.$(selector) #### page.$(selector)
- `selector` <[string]> A selector to query page for - `selector` <[string]> A selector to query page for
- returns: <[Promise]<?[ElementHandle]>> - returns: <[Promise]<?[ElementHandle]>>
@ -3272,11 +3266,14 @@ function findFocusedNode(node) {
### class: Worker ### class: Worker
The Worker class represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). The Worker class represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).
The events `workercreated` and `workerdestroyed` are emitted on the page object to signal the worker lifecycle. `worker` event is emitted on the page object to signal a worker creation.
`close` event is emitted on the worker object when the worker is gone.
```js ```js
page.on('workercreated', worker => console.log('Worker created: ' + worker.url())); page.on('worker', worker => {
page.on('workerdestroyed', worker => console.log('Worker destroyed: ' + worker.url())); console.log('Worker created: ' + worker.url());
worker.on('close', worker => console.log('Worker destroyed: ' + worker.url()));
});
console.log('Current workers:'); console.log('Current workers:');
for (const worker of page.workers()) for (const worker of page.workers())
@ -3284,11 +3281,17 @@ for (const worker of page.workers())
``` ```
<!-- GEN:toc --> <!-- GEN:toc -->
- [event: 'close'](#event-close-2)
- [worker.evaluate(pageFunction[, ...args])](#workerevaluatepagefunction-args) - [worker.evaluate(pageFunction[, ...args])](#workerevaluatepagefunction-args)
- [worker.evaluateHandle(pageFunction[, ...args])](#workerevaluatehandlepagefunction-args) - [worker.evaluateHandle(pageFunction[, ...args])](#workerevaluatehandlepagefunction-args)
- [worker.url()](#workerurl) - [worker.url()](#workerurl)
<!-- GEN:stop --> <!-- GEN:stop -->
#### event: 'close'
- <[Worker]>
Emitted when this dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is terminated.
#### worker.evaluate(pageFunction[, ...args]) #### worker.evaluate(pageFunction[, ...args])
- `pageFunction` <[function]|[string]> Function to be evaluated in the worker context - `pageFunction` <[function]|[string]> Function to be evaluated in the worker context
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction` - `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
@ -3314,7 +3317,7 @@ If the function passed to the `worker.evaluateHandle` returns a [Promise], then
### class: BrowserServer ### class: BrowserServer
<!-- GEN:toc --> <!-- GEN:toc -->
- [event: 'close'](#event-close-2) - [event: 'close'](#event-close-3)
- [browserServer.close()](#browserserverclose) - [browserServer.close()](#browserserverclose)
- [browserServer.kill()](#browserserverkill) - [browserServer.kill()](#browserserverkill)
- [browserServer.process()](#browserserverprocess) - [browserServer.process()](#browserserverprocess)

View File

@ -46,7 +46,10 @@ export const Events = {
FrameNavigated: 'framenavigated', FrameNavigated: 'framenavigated',
Load: 'load', Load: 'load',
Popup: 'popup', Popup: 'popup',
WorkerCreated: 'workercreated', Worker: 'worker',
WorkerDestroyed: 'workerdestroyed', },
Worker: {
Close: 'close',
}, },
}; };

View File

@ -534,20 +534,20 @@ export class Page extends platform.EventEmitter {
_addWorker(workerId: string, worker: Worker) { _addWorker(workerId: string, worker: Worker) {
this._workers.set(workerId, worker); this._workers.set(workerId, worker);
this.emit(Events.Page.WorkerCreated, worker); this.emit(Events.Page.Worker, worker);
} }
_removeWorker(workerId: string) { _removeWorker(workerId: string) {
const worker = this._workers.get(workerId); const worker = this._workers.get(workerId);
if (!worker) if (!worker)
return; return;
this.emit(Events.Page.WorkerDestroyed, worker); worker.emit(Events.Worker.Close, worker);
this._workers.delete(workerId); this._workers.delete(workerId);
} }
_clearWorkers() { _clearWorkers() {
for (const [workerId, worker] of this._workers) { for (const [workerId, worker] of this._workers) {
this.emit(Events.Page.WorkerDestroyed, worker); worker.emit(Events.Worker.Close, worker);
this._workers.delete(workerId); this._workers.delete(workerId);
} }
} }
@ -569,13 +569,14 @@ export class Page extends platform.EventEmitter {
} }
} }
export class Worker { export class Worker extends platform.EventEmitter {
private _url: string; private _url: string;
private _executionContextPromise: Promise<js.ExecutionContext>; private _executionContextPromise: Promise<js.ExecutionContext>;
private _executionContextCallback: (value?: js.ExecutionContext) => void; private _executionContextCallback: (value?: js.ExecutionContext) => void;
_existingExecutionContext: js.ExecutionContext | null = null; _existingExecutionContext: js.ExecutionContext | null = null;
constructor(url: string) { constructor(url: string) {
super();
this._url = url; this._url = url;
this._executionContextCallback = () => {}; this._executionContextCallback = () => {};
this._executionContextPromise = new Promise(x => this._executionContextCallback = x); this._executionContextPromise = new Promise(x => this._executionContextCallback = x);

View File

@ -29,7 +29,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
describe('Workers', function() { describe('Workers', function() {
it('Page.workers', async function({page, server}) { it('Page.workers', async function({page, server}) {
await Promise.all([ await Promise.all([
page.waitForEvent('workercreated'), page.waitForEvent('worker'),
page.goto(server.PREFIX + '/worker/worker.html')]); page.goto(server.PREFIX + '/worker/worker.html')]);
const worker = page.workers()[0]; const worker = page.workers()[0];
expect(worker.url()).toContain('worker.js'); expect(worker.url()).toContain('worker.js');
@ -40,11 +40,11 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
expect(page.workers().length).toBe(0); expect(page.workers().length).toBe(0);
}); });
it('should emit created and destroyed events', async function({page}) { it('should emit created and destroyed events', async function({page}) {
const workerCreatedPromise = page.waitForEvent('workercreated'); const workerCreatedPromise = page.waitForEvent('worker');
const workerObj = await page.evaluateHandle(() => new Worker(URL.createObjectURL(new Blob(['1'], {type: 'application/javascript'})))); const workerObj = await page.evaluateHandle(() => new Worker(URL.createObjectURL(new Blob(['1'], {type: 'application/javascript'}))));
const worker = await workerCreatedPromise; const worker = await workerCreatedPromise;
const workerThisObj = await worker.evaluateHandle(() => this); const workerThisObj = await worker.evaluateHandle(() => this);
const workerDestroyedPromise = new Promise(x => page.once('workerdestroyed', x)); const workerDestroyedPromise = new Promise(x => worker.once('close', x));
await page.evaluate(workerObj => workerObj.terminate(), workerObj); await page.evaluate(workerObj => workerObj.terminate(), workerObj);
expect(await workerDestroyedPromise).toBe(worker); expect(await workerDestroyedPromise).toBe(worker);
const error = await workerThisObj.getProperty('self').catch(error => error); const error = await workerThisObj.getProperty('self').catch(error => error);
@ -66,7 +66,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
expect(await (await log.args()[3].getProperty('origin')).jsonValue()).toBe('null'); expect(await (await log.args()[3].getProperty('origin')).jsonValue()).toBe('null');
}); });
it('should evaluate', async function({page}) { it('should evaluate', async function({page}) {
const workerCreatedPromise = page.waitForEvent('workercreated'); const workerCreatedPromise = page.waitForEvent('worker');
page.evaluate(() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))); page.evaluate(() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'}))));
const worker = await workerCreatedPromise; const worker = await workerCreatedPromise;
expect(await worker.evaluate('1+1')).toBe(2); expect(await worker.evaluate('1+1')).toBe(2);
@ -79,31 +79,31 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
}); });
it('should clear upon navigation', async function({server, page}) { it('should clear upon navigation', async function({server, page}) {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const workerCreatedPromise = page.waitForEvent('workercreated'); const workerCreatedPromise = page.waitForEvent('worker');
page.evaluate(() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))); page.evaluate(() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'}))));
await workerCreatedPromise; const worker = await workerCreatedPromise;
expect(page.workers().length).toBe(1); expect(page.workers().length).toBe(1);
let destroyed = false; let destroyed = false;
page.once('workerdestroyed', () => destroyed = true); worker.once('close', () => destroyed = true);
await page.goto(server.PREFIX + '/one-style.html'); await page.goto(server.PREFIX + '/one-style.html');
expect(destroyed).toBe(true); expect(destroyed).toBe(true);
expect(page.workers().length).toBe(0); expect(page.workers().length).toBe(0);
}); });
it('should clear upon cross-process navigation', async function({server, page}) { it('should clear upon cross-process navigation', async function({server, page}) {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const workerCreatedPromise = page.waitForEvent('workercreated'); const workerCreatedPromise = page.waitForEvent('worker');
page.evaluate(() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))); page.evaluate(() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'}))));
await workerCreatedPromise; const worker = await workerCreatedPromise;
expect(page.workers().length).toBe(1); expect(page.workers().length).toBe(1);
let destroyed = false; let destroyed = false;
page.once('workerdestroyed', () => destroyed = true); worker.once('close', () => destroyed = true);
await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
expect(destroyed).toBe(true); expect(destroyed).toBe(true);
expect(page.workers().length).toBe(0); expect(page.workers().length).toBe(0);
}); });
it('should report network activity', async function({page, server}) { it('should report network activity', async function({page, server}) {
const [worker] = await Promise.all([ const [worker] = await Promise.all([
page.waitForEvent('workercreated'), page.waitForEvent('worker'),
page.goto(server.PREFIX + '/worker/worker.html'), page.goto(server.PREFIX + '/worker/worker.html'),
]); ]);
const url = server.PREFIX + '/one-style.css'; const url = server.PREFIX + '/one-style.css';
@ -133,7 +133,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
}); });
false && it.skip(FFOX)('should report web socket activity', async function({page, server}) { false && it.skip(FFOX)('should report web socket activity', async function({page, server}) {
const [worker] = await Promise.all([ const [worker] = await Promise.all([
page.waitForEvent('workercreated'), page.waitForEvent('worker'),
page.goto(server.PREFIX + '/worker/worker.html'), page.goto(server.PREFIX + '/worker/worker.html'),
]); ]);
const log = []; const log = [];