Skip to content

Commit

Permalink
feat(workers): create workers from service workers and shared workers (
Browse files Browse the repository at this point in the history
…puppeteer#4397)

This allows users to easily evaluate javascript inside service workers and shared workers by creating a Worker object for them.
  • Loading branch information
JoelEinbinder authored and aslushnikov committed May 10, 2019
1 parent ef24c69 commit 1516e0d
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 4 deletions.
10 changes: 8 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@
* [target.page()](#targetpage)
* [target.type()](#targettype)
* [target.url()](#targeturl)
* [target.worker()](#targetworker)
- [class: CDPSession](#class-cdpsession)
* [cdpSession.detach()](#cdpsessiondetach)
* [cdpSession.send(method[, params])](#cdpsessionsendmethod-params)
Expand Down Expand Up @@ -3479,13 +3480,18 @@ Get the target that opened this target. Top-level targets return `null`.
If the target is not of type `"page"` or `"background_page"`, returns `null`.

#### target.type()
- returns: <"page"|"background_page"|"service_worker"|"other"|"browser">
- returns: <"page"|"background_page"|"service_worker"|"shared_worker"|"other"|"browser">

Identifies what kind of target this is. Can be `"page"`, [`"background_page"`](https://developer.chrome.com/extensions/background_pages), `"service_worker"`, `"browser"` or `"other"`.
Identifies what kind of target this is. Can be `"page"`, [`"background_page"`](https://developer.chrome.com/extensions/background_pages), `"service_worker"`, `"shared_worker"`, `"browser"` or `"other"`.

#### target.url()
- returns: <[string]>

#### target.worker()
- returns: <[Promise]<?[Worker]>>

If the target is not of type `"service_worker"` or `"shared_worker"`, returns `null`.

### class: CDPSession

* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
Expand Down
29 changes: 27 additions & 2 deletions lib/Target.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

const {Events} = require('./Events');
const {Page} = require('./Page');
const {Worker} = require('./Worker');
const {Connection} = require('./Connection');

class Target {
/**
Expand All @@ -36,6 +38,8 @@ class Target {
this._screenshotTaskQueue = screenshotTaskQueue;
/** @type {?Promise<!Puppeteer.Page>} */
this._pagePromise = null;
/** @type {?Promise<!Worker>} */
this._workerPromise = null;
this._initializedPromise = new Promise(fulfill => this._initializedCallback = fulfill).then(async success => {
if (!success)
return false;
Expand Down Expand Up @@ -73,6 +77,27 @@ class Target {
return this._pagePromise;
}

/**
* @return {!Promise<?Worker>}
*/
async worker() {
if (this._targetInfo.type !== 'service_worker' && this._targetInfo.type !== 'shared_worker')
return null;
if (!this._workerPromise) {
this._workerPromise = this._sessionFactory().then(async client => {
// Top level workers have a fake page wrapping the actual worker.
const [targetAttached] = await Promise.all([
new Promise(x => client.once('Target.attachedToTarget', x)),
client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}),
]);
const session = Connection.fromSession(client).session(targetAttached.sessionId);
// TODO(einbinder): Make workers send their console logs.
return new Worker(session, this._targetInfo.url, () => {} /* consoleAPICalled */, () => {} /* exceptionThrown */);
});
}
return this._workerPromise;
}

/**
* @return {string}
*/
Expand All @@ -81,11 +106,11 @@ class Target {
}

/**
* @return {"page"|"background_page"|"service_worker"|"other"|"browser"}
* @return {"page"|"background_page"|"service_worker"|"shared_worker"|"other"|"browser"}
*/
type() {
const type = this._targetInfo.type;
if (type === 'page' || type === 'background_page' || type === 'service_worker' || type === 'browser')
if (type === 'page' || type === 'background_page' || type === 'service_worker' || type === 'shared_worker' || type === 'browser')
return type;
return 'other';
}
Expand Down
16 changes: 16 additions & 0 deletions test/target.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,22 @@ module.exports.addTests = function({testRunner, expect, puppeteer}) {
await page.evaluate(() => window.registrationPromise.then(registration => registration.unregister()));
expect(await destroyedTarget).toBe(await createdTarget);
});
it_fails_ffox('should create a worker from a service worker', async({page, server, context}) => {
await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html');

const target = await context.waitForTarget(target => target.type() === 'service_worker');
const worker = await target.worker();
expect(await worker.evaluate(() => self.toString())).toBe('[object ServiceWorkerGlobalScope]');
});
it_fails_ffox('should create a worker from a shared worker', async({page, server, context}) => {
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => {
new SharedWorker('data:text/javascript,console.log("hi")');
});
const target = await context.waitForTarget(target => target.type() === 'shared_worker');
const worker = await target.worker();
expect(await worker.evaluate(() => self.toString())).toBe('[object SharedWorkerGlobalScope]');
});
it('should report when a target url changes', async({page, server, context}) => {
await page.goto(server.EMPTY_PAGE);
let changedTarget = new Promise(fulfill => context.once('targetchanged', target => fulfill(target)));
Expand Down

0 comments on commit 1516e0d

Please sign in to comment.