Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: move workers into features/ #29

Merged
merged 1 commit into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 33 additions & 22 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]>>
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions src/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ export const Events = {
Load: 'load',
Metrics: 'metrics',
Popup: 'popup',
WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed',
},

Browser: {
Expand All @@ -52,4 +50,8 @@ export const Events = {
TargetChanged: 'targetchanged',
},

Workers: {
WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed',
}
};
3 changes: 2 additions & 1 deletion src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
22 changes: 4 additions & 18 deletions src/chromium/Page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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);

Expand All @@ -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;
Expand All @@ -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;

Expand All @@ -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));
Expand Down Expand Up @@ -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);
}
Expand Down
13 changes: 0 additions & 13 deletions src/chromium/Target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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>;
Expand Down Expand Up @@ -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;
}
Expand Down
16 changes: 8 additions & 8 deletions test/worker.spec.js → src/chromium/features/workers.spec.js
Original file line number Diff line number Diff line change
@@ -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}) {
Expand All @@ -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);
Expand All @@ -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);
Expand Down
48 changes: 40 additions & 8 deletions src/chromium/Worker.ts → src/chromium/features/workers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,51 @@
* 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;
private _url: string;
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;
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion test/playwright.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down