chore: move workers into features/ (#29)

This commit is contained in:
Pavel Feldman 2019-11-19 17:32:43 -08:00 committed by Andrey Lushnikov
parent bfcd92da7e
commit 83ed65dce8
8 changed files with 92 additions and 73 deletions

View file

@ -78,8 +78,6 @@
* [event: 'requestfailed'](#event-requestfailed)
* [event: 'requestfinished'](#event-requestfinished)
* [event: 'response'](#event-response)
* [event: 'workercreated'](#event-workercreated)
* [event: 'workerdestroyed'](#event-workerdestroyed)
* [page.$(selector)](#pageselector)
* [page.$$(selector)](#pageselector-1)
* [page.$$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args)
@ -155,12 +153,16 @@
* [page.waitForResponse(urlOrPredicate[, options])](#pagewaitforresponseurlorpredicate-options)
* [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options)
* [page.waitForXPath(xpath[, options])](#pagewaitforxpathxpath-options)
* [page.workers()](#pageworkers)
* [page.workers](#pageworkers)
- [class: Worker](#class-worker)
* [worker.evaluate(pageFunction[, ...args])](#workerevaluatepagefunction-args)
* [worker.evaluateHandle(pageFunction[, ...args])](#workerevaluatehandlepagefunction-args)
* [worker.executionContext()](#workerexecutioncontext)
* [worker.url()](#workerurl)
- [class: Workers](#class-workers)
* [event: 'workercreated'](#event-workercreated)
* [event: 'workerdestroyed'](#event-workerdestroyed)
* [workers.list()](#workerslist)
- [class: Accessibility](#class-accessibility)
* [accessibility.snapshot([options])](#accessibilitysnapshotoptions)
- [class: Keyboard](#class-keyboard)
@ -1065,16 +1067,6 @@ Emitted when a request finishes successfully.
Emitted when a [response] is received.
#### event: 'workercreated'
- <[Worker]>
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)
- `selector` <[string]> A [selector] to query page for
- returns: <[Promise]<?[ElementHandle]>>
@ -2177,9 +2169,8 @@ const playwright = require('playwright');
```
Shortcut for [page.mainFrame().waitForXPath(xpath[, options])](#framewaitforxpathxpath-options).
#### page.workers()
- returns: <[Array]<[Worker]>>
This method returns all of the dedicated [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) associated with the page.
#### page.workers
- returns: <[Workers]>
> **NOTE** This does not contain ServiceWorkers
@ -2225,6 +2216,26 @@ Shortcut for [(await worker.executionContext()).evaluateHandle(pageFunction, ...
#### worker.url()
- returns: <[string]>
### class: Workers
The Workers class represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) collection.
#### event: 'workercreated'
- <[Worker]>
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.
#### workers.list()
- returns: <[Array]<[Worker]>>
This method returns all of the dedicated [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) associated with the page.
> **NOTE** This does not contain ServiceWorkers
### class: Accessibility
The Accessibility class provides methods for inspecting Chromium's accessibility tree. The accessibility tree is used by assistive technology such as [screen readers](https://en.wikipedia.org/wiki/Screen_reader) or [switches](https://en.wikipedia.org/wiki/Switch_access).
@ -2495,22 +2506,22 @@ Dispatches a `mouseup` event.
> **NOTE** Generating a pdf is currently only supported in Chrome headless.
`page.pdf()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call [page.emulateMedia('screen')](#pageemulatemediamediatype) before calling `page.pdf()`:
`pdf.generate()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call [page.emulateMedia('screen')](#pageemulatemediamediatype) before calling `pdf.generate()`:
> **NOTE** By default, `page.pdf()` generates a pdf with modified colors for printing. Use the [`-webkit-print-color-adjust`](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust) property to force rendering of exact colors.
> **NOTE** By default, `pdf.generate()` generates a pdf with modified colors for printing. Use the [`-webkit-print-color-adjust`](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust) property to force rendering of exact colors.
```js
// Generates a PDF with 'screen' media type.
await page.emulateMedia('screen');
await page.pdf({path: 'page.pdf'});
await page.pdf.generate({path: 'page.pdf'});
```
The `width`, `height`, and `margin` options accept values labeled with units. Unlabeled values are treated as pixels.
A few examples:
- `page.pdf({width: 100})` - prints with width set to 100 pixels
- `page.pdf({width: '100px'})` - prints with width set to 100 pixels
- `page.pdf({width: '10cm'})` - prints with width set to 10 centimeters.
- `page.pdf.generate({width: 100})` - prints with width set to 100 pixels
- `page.pdf.generate({width: '100px'})` - prints with width set to 100 pixels
- `page.pdf.generate({width: '10cm'})` - prints with width set to 10 centimeters.
All possible units are:
- `px` - pixel

View file

@ -35,8 +35,6 @@ export const Events = {
Load: 'load',
Metrics: 'metrics',
Popup: 'popup',
WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed',
},
Browser: {
@ -52,4 +50,8 @@ export const Events = {
TargetChanged: 'targetchanged',
},
Workers: {
WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed',
}
};

View file

@ -41,7 +41,8 @@ export = {
TimeoutError: require('./Errors').TimeoutError,
Touchscreen: require('./chromium/Input').Touchscreen,
Tracing: require('./chromium/features/tracing').Tracing,
Worker: require('./chromium/Worker').Worker,
Worker: require('./chromium/features/workers').Worker,
Workers: require('./chromium/features/workers').Workers,
},
Firefox: {
Accessibility: require('./firefox/Accessibility').Accessibility,

View file

@ -25,7 +25,7 @@ import { TimeoutSettings } from '../TimeoutSettings';
import { Accessibility } from './features/accessibility';
import { Browser } from './Browser';
import { BrowserContext } from './BrowserContext';
import { CDPSession, CDPSessionEvents, Connection } from './Connection';
import { CDPSession, CDPSessionEvents } from './Connection';
import { Coverage } from './features/coverage';
import { Dialog, DialogType } from './Dialog';
import { EmulationManager } from './EmulationManager';
@ -40,7 +40,7 @@ import { getExceptionMessage, releaseObject, valueFromRemoteObject } from './pro
import { Target } from './Target';
import { TaskQueue } from './TaskQueue';
import { Tracing } from './features/tracing';
import { Worker } from './Worker';
import { Workers } from './features/workers';
const writeFileAsync = helper.promisify(fs.writeFile);
@ -66,12 +66,12 @@ export class Page extends EventEmitter {
readonly accessibility: Accessibility;
readonly coverage: Coverage;
readonly pdf: PDF;
readonly workers: Workers;
readonly tracing: Tracing;
private _pageBindings = new Map<string, Function>();
_javascriptEnabled = true;
private _viewport: Viewport | null = null;
private _screenshotTaskQueue: TaskQueue;
private _workers = new Map<string, Worker>();
private _fileChooserInterceptionIsDisabled = false;
private _fileChooserInterceptors = new Set<(chooser: FileChooser) => void>();
private _disconnectPromise: Promise<Error> | undefined;
@ -98,6 +98,7 @@ export class Page extends EventEmitter {
this.tracing = new Tracing(client);
this.coverage = new Coverage(client);
this.pdf = new PDF(client);
this.workers = new Workers(client, this._addConsoleMessage.bind(this), this._handleException.bind(this));
this._screenshotTaskQueue = screenshotTaskQueue;
@ -109,17 +110,6 @@ export class Page extends EventEmitter {
}).catch(debugError);
return;
}
const session = Connection.fromSession(client).session(event.sessionId);
const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this));
this._workers.set(event.sessionId, worker);
this.emit(Events.Page.WorkerCreated, worker);
});
client.on('Target.detachedFromTarget', event => {
const worker = this._workers.get(event.sessionId);
if (!worker)
return;
this.emit(Events.Page.WorkerDestroyed, worker);
this._workers.delete(event.sessionId);
});
this._frameManager.on(FrameManagerEvents.FrameAttached, event => this.emit(Events.Page.FrameAttached, event));
@ -238,10 +228,6 @@ export class Page extends EventEmitter {
return this._frameManager.frames();
}
workers(): Worker[] {
return Array.from(this._workers.values());
}
async setRequestInterception(value: boolean) {
return this._frameManager.networkManager().setRequestInterception(value);
}

View file

@ -21,7 +21,6 @@ import { BrowserContext } from './BrowserContext';
import { CDPSession } from './Connection';
import { Page, Viewport } from './Page';
import { TaskQueue } from './TaskQueue';
import { Worker } from './Worker';
import { Protocol } from './protocol';
export class Target {
@ -33,7 +32,6 @@ export class Target {
private _defaultViewport: Viewport;
private _screenshotTaskQueue: TaskQueue;
private _pagePromise: Promise<Page> | null = null;
private _workerPromise: Promise<Worker> | null = null;
_initializedPromise: Promise<boolean>;
_initializedCallback: (value?: unknown) => void;
_isClosedPromise: Promise<void>;
@ -85,17 +83,6 @@ export class Target {
return this._pagePromise;
}
async worker(): Promise<Worker | null> {
if (this._targetInfo.type !== 'service_worker' && this._targetInfo.type !== 'shared_worker')
return null;
if (!this._workerPromise) {
// TODO(einbinder): Make workers send their console logs.
this._workerPromise = this._sessionFactory()
.then(client => new Worker(client, this._targetInfo.url, () => {} /* consoleAPICalled */, () => {} /* exceptionThrown */));
}
return this._workerPromise;
}
url(): string {
return this._targetInfo.url;
}

View file

@ -1,4 +1,4 @@
const utils = require('./utils');
const utils = require('../../../test/utils');
const {waitEvent} = utils;
module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
@ -9,22 +9,22 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
describe.skip(FFOX || WEBKIT)('Workers', function() {
it('Page.workers', async function({page, server}) {
await Promise.all([
new Promise(x => page.once('workercreated', x)),
new Promise(x => page.workers.once('workercreated', x)),
page.goto(server.PREFIX + '/worker/worker.html')]);
const worker = page.workers()[0];
const worker = page.workers.list()[0];
expect(worker.url()).toContain('worker.js');
expect(await worker.evaluate(() => self.workerFunction())).toBe('worker function result');
expect(await worker.evaluate(() => self['workerFunction']())).toBe('worker function result');
await page.goto(server.EMPTY_PAGE);
expect(page.workers().length).toBe(0);
expect(page.workers.list().length).toBe(0);
});
it('should emit created and destroyed events', async function({page}) {
const workerCreatedPromise = new Promise(x => page.once('workercreated', x));
const workerCreatedPromise = new Promise(x => page.workers.once('workercreated', x));
const workerObj = await page.evaluateHandle(() => new Worker('data:text/javascript,1'));
const worker = await workerCreatedPromise;
const workerThisObj = await worker.evaluateHandle(() => this);
const workerDestroyedPromise = new Promise(x => page.once('workerdestroyed', x));
const workerDestroyedPromise = new Promise(x => page.workers.once('workerdestroyed', x));
await page.evaluate(workerObj => workerObj.terminate(), workerObj);
expect(await workerDestroyedPromise).toBe(worker);
const error = await workerThisObj.getProperty('self').catch(error => error);
@ -51,7 +51,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(await (await log.args()[3].getProperty('origin')).jsonValue()).toBe('null');
});
it('should have an execution context', async function({page}) {
const workerCreatedPromise = new Promise(x => page.once('workercreated', x));
const workerCreatedPromise = new Promise(x => page.workers.once('workercreated', x));
await page.evaluate(() => new Worker(`data:text/javascript,console.log(1)`));
const worker = await workerCreatedPromise;
expect(await (await worker.executionContext()).evaluate('1+1')).toBe(2);

View file

@ -15,11 +15,43 @@
* limitations under the License.
*/
import { EventEmitter } from 'events';
import { CDPSession } from './Connection';
import { ExecutionContext } from './ExecutionContext';
import { debugError } from '../helper';
import { JSHandle } from './JSHandle';
import { Protocol } from './protocol';
import { CDPSession, Connection } from '../Connection';
import { ExecutionContext } from '../ExecutionContext';
import { debugError } from '../../helper';
import { JSHandle } from '../JSHandle';
import { Protocol } from '../protocol';
import { Events } from '../../Events';
type AddToConsoleCallback = (type: string, args: JSHandle[], stackTrace: Protocol.Runtime.StackTrace | undefined) => void;
type HandleExceptionCallback = (exceptionDetails: Protocol.Runtime.ExceptionDetails) => void;
export class Workers extends EventEmitter {
private _workers = new Map<string, Worker>();
constructor(client: CDPSession, addToConsole: AddToConsoleCallback, handleException: HandleExceptionCallback) {
super();
client.on('Target.attachedToTarget', event => {
if (event.targetInfo.type !== 'worker')
return;
const session = Connection.fromSession(client).session(event.sessionId);
const worker = new Worker(session, event.targetInfo.url, addToConsole, handleException);
this._workers.set(event.sessionId, worker);
this.emit(Events.Workers.WorkerCreated, worker);
});
client.on('Target.detachedFromTarget', event => {
const worker = this._workers.get(event.sessionId);
if (!worker)
return;
this.emit(Events.Workers.WorkerDestroyed, worker);
this._workers.delete(event.sessionId);
});
}
list(): Worker[] {
return Array.from(this._workers.values());
}
}
export class Worker extends EventEmitter {
private _client: CDPSession;
@ -27,7 +59,7 @@ export class Worker extends EventEmitter {
private _executionContextPromise: Promise<ExecutionContext>;
private _executionContextCallback: (value?: ExecutionContext) => void;
constructor(client: CDPSession, url: string, consoleAPICalled: (arg0: string, arg1: JSHandle[], arg2: Protocol.Runtime.StackTrace | undefined) => void, exceptionThrown: (arg0: Protocol.Runtime.ExceptionDetails) => void) {
constructor(client: CDPSession, url: string, addToConsole: AddToConsoleCallback, handleException: HandleExceptionCallback) {
super();
this._client = client;
this._url = url;
@ -41,8 +73,8 @@ export class Worker extends EventEmitter {
// This might fail if the target is closed before we recieve all execution contexts.
this._client.send('Runtime.enable', {}).catch(debugError);
this._client.on('Runtime.consoleAPICalled', event => consoleAPICalled(event.type, event.args.map(jsHandleFactory), event.stackTrace));
this._client.on('Runtime.exceptionThrown', exception => exceptionThrown(exception.exceptionDetails));
this._client.on('Runtime.consoleAPICalled', event => addToConsole(event.type, event.args.map(jsHandleFactory), event.stackTrace));
this._client.on('Runtime.exceptionThrown', exception => handleException(exception.exceptionDetails));
}
url(): string {

View file

@ -154,7 +154,7 @@ module.exports.addTests = ({testRunner, product, playwrightPath}) => {
require('./target.spec.js').addTests(testOptions);
require('./touchscreen.spec.js').addTests(testOptions);
require('./waittask.spec.js').addTests(testOptions);
require('./worker.spec.js').addTests(testOptions);
require('../src/chromium/features/workers.spec.js').addTests(testOptions);
if (CHROME) {
require('./CDPSession.spec.js').addTests(testOptions);
require('../src/chromium/features/coverage.spec.js').addTests(testOptions);