feat(worker): expose worker's owner frame
This commit is contained in:
parent
a64fc0e45f
commit
5614c75751
|
|
@ -3248,6 +3248,7 @@ for (const worker of page.workers())
|
||||||
<!-- GEN:toc -->
|
<!-- GEN:toc -->
|
||||||
- [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.frame()](#workerframe)
|
||||||
- [worker.url()](#workerurl)
|
- [worker.url()](#workerurl)
|
||||||
<!-- GEN:stop -->
|
<!-- GEN:stop -->
|
||||||
|
|
||||||
|
|
@ -3269,6 +3270,9 @@ The only difference between `worker.evaluate` and `worker.evaluateHandle` is tha
|
||||||
|
|
||||||
If the function passed to the `worker.evaluateHandle` returns a [Promise], then `worker.evaluateHandle` would wait for the promise to resolve and return its value.
|
If the function passed to the `worker.evaluateHandle` returns a [Promise], then `worker.evaluateHandle` would wait for the promise to resolve and return its value.
|
||||||
|
|
||||||
|
#### worker.frame()
|
||||||
|
- returns: <[Frame]> Frame which has created this worker.
|
||||||
|
|
||||||
#### worker.url()
|
#### worker.url()
|
||||||
- returns: <[string]>
|
- returns: <[string]>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
"playwright": {
|
"playwright": {
|
||||||
"chromium_revision": "733125",
|
"chromium_revision": "733125",
|
||||||
"firefox_revision": "1018",
|
"firefox_revision": "1018",
|
||||||
"webkit_revision": "1113"
|
"webkit_revision": "1118"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"unit": "node test/test.js",
|
"unit": "node test/test.js",
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ export class CRPage implements PageDelegate {
|
||||||
return;
|
return;
|
||||||
const url = event.targetInfo.url;
|
const url = event.targetInfo.url;
|
||||||
const session = CRConnection.fromSession(this._client).session(event.sessionId)!;
|
const session = CRConnection.fromSession(this._client).session(event.sessionId)!;
|
||||||
const worker = new Worker(url);
|
const worker = new Worker(url, null as any);
|
||||||
this._page._addWorker(event.sessionId, worker);
|
this._page._addWorker(event.sessionId, worker);
|
||||||
session.once('Runtime.executionContextCreated', async event => {
|
session.once('Runtime.executionContextCreated', async event => {
|
||||||
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,8 @@ export class CRTarget {
|
||||||
if (!this._workerPromise) {
|
if (!this._workerPromise) {
|
||||||
// TODO(einbinder): Make workers send their console logs.
|
// TODO(einbinder): Make workers send their console logs.
|
||||||
this._workerPromise = this._sessionFactory().then(session => {
|
this._workerPromise = this._sessionFactory().then(session => {
|
||||||
const worker = new Worker(this._targetInfo.url);
|
// TODO: we should not reuse Worker class (which is web worker) for service workers.
|
||||||
|
const worker = new Worker(this._targetInfo.url, null as any);
|
||||||
session.once('Runtime.executionContextCreated', async event => {
|
session.once('Runtime.executionContextCreated', async event => {
|
||||||
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
||||||
});
|
});
|
||||||
|
|
@ -132,6 +133,8 @@ export class CRTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
opener(): CRTarget | null {
|
opener(): CRTarget | null {
|
||||||
|
if (this._targetInfo.type === 'worker')
|
||||||
|
return null;
|
||||||
const { openerId } = this._targetInfo;
|
const { openerId } = this._targetInfo;
|
||||||
if (!openerId)
|
if (!openerId)
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ export class FFPage implements PageDelegate {
|
||||||
|
|
||||||
async _onWorkerCreated(event: Protocol.Page.workerCreatedPayload) {
|
async _onWorkerCreated(event: Protocol.Page.workerCreatedPayload) {
|
||||||
const workerId = event.workerId;
|
const workerId = event.workerId;
|
||||||
const worker = new Worker(event.url);
|
const worker = new Worker(event.url, this._page._frameManager.frame(event.frameId)!);
|
||||||
const workerSession = new FFSession(this._session._connection, 'worker', workerId, (message: any) => {
|
const workerSession = new FFSession(this._session._connection, 'worker', workerId, (message: any) => {
|
||||||
this._session.send('Page.sendMessageToWorker', {
|
this._session.send('Page.sendMessageToWorker', {
|
||||||
frameId: event.frameId,
|
frameId: event.frameId,
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ export class FrameManager {
|
||||||
frame._lastDocumentId = documentId;
|
frame._lastDocumentId = documentId;
|
||||||
this.clearFrameLifecycle(frame);
|
this.clearFrameLifecycle(frame);
|
||||||
this.clearWebSockets(frame);
|
this.clearWebSockets(frame);
|
||||||
|
this._page._clearWorkers(frame);
|
||||||
if (!initial) {
|
if (!initial) {
|
||||||
for (const watcher of this._lifecycleWatchers)
|
for (const watcher of this._lifecycleWatchers)
|
||||||
watcher._onCommittedNewDocumentNavigation(frame);
|
watcher._onCommittedNewDocumentNavigation(frame);
|
||||||
|
|
|
||||||
14
src/page.ts
14
src/page.ts
|
|
@ -519,22 +519,26 @@ export class Page extends platform.EventEmitter {
|
||||||
this._workers.delete(workerId);
|
this._workers.delete(workerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
_clearWorkers() {
|
_clearWorkers(frame: frames.Frame) {
|
||||||
for (const [workerId, worker] of this._workers) {
|
for (const [workerId, worker] of this._workers) {
|
||||||
this.emit(Events.Page.WorkerDestroyed, worker);
|
if (worker.frame() !== frame)
|
||||||
|
continue;
|
||||||
this._workers.delete(workerId);
|
this._workers.delete(workerId);
|
||||||
|
this.emit(Events.Page.WorkerDestroyed, worker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Worker {
|
export class Worker {
|
||||||
private _url: string;
|
private _url: string;
|
||||||
|
private _frame: frames.Frame;
|
||||||
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, frame: frames.Frame) {
|
||||||
this._url = url;
|
this._url = url;
|
||||||
|
this._frame = frame;
|
||||||
this._executionContextCallback = () => {};
|
this._executionContextCallback = () => {};
|
||||||
this._executionContextPromise = new Promise(x => this._executionContextCallback = x);
|
this._executionContextPromise = new Promise(x => this._executionContextCallback = x);
|
||||||
}
|
}
|
||||||
|
|
@ -548,6 +552,10 @@ export class Worker {
|
||||||
return this._url;
|
return this._url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame(): frames.Frame {
|
||||||
|
return this._frame;
|
||||||
|
}
|
||||||
|
|
||||||
evaluate: types.Evaluate = async (pageFunction, ...args) => {
|
evaluate: types.Evaluate = async (pageFunction, ...args) => {
|
||||||
return (await this._executionContextPromise).evaluate(pageFunction, ...args as any);
|
return (await this._executionContextPromise).evaluate(pageFunction, ...args as any);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export class WKWorkers {
|
||||||
this.clear();
|
this.clear();
|
||||||
this._sessionListeners = [
|
this._sessionListeners = [
|
||||||
helper.addEventListener(session, 'Worker.workerCreated', async (event: Protocol.Worker.workerCreatedPayload) => {
|
helper.addEventListener(session, 'Worker.workerCreated', async (event: Protocol.Worker.workerCreatedPayload) => {
|
||||||
const worker = new Worker(event.url);
|
const worker = new Worker(event.url, this._page._frameManager.frame(event.frameId));
|
||||||
const workerSession = new WKSession(session.connection, event.workerId, 'Most likely the worker has been closed.', (message: any) => {
|
const workerSession = new WKSession(session.connection, event.workerId, 'Most likely the worker has been closed.', (message: any) => {
|
||||||
session.send('Worker.sendMessageToWorker', {
|
session.send('Worker.sendMessageToWorker', {
|
||||||
workerId: event.workerId,
|
workerId: event.workerId,
|
||||||
|
|
@ -77,7 +77,6 @@ export class WKWorkers {
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
this._page._clearWorkers();
|
|
||||||
this._workerSessions.clear();
|
this._workerSessions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,25 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
|
||||||
expect(destroyed).toBe(true);
|
expect(destroyed).toBe(true);
|
||||||
expect(page.workers().length).toBe(0);
|
expect(page.workers().length).toBe(0);
|
||||||
});
|
});
|
||||||
|
it.skip(CHROMIUM)('should clear upon frame navigation', async function({server, page}) {
|
||||||
|
await page.goto(server.PREFIX + '/frames/one-frame.html');
|
||||||
|
const workerCreatedPromise = page.waitForEvent('workercreated');
|
||||||
|
const frame = page.mainFrame().childFrames()[0];
|
||||||
|
frame.evaluate(() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'}))));
|
||||||
|
await workerCreatedPromise;
|
||||||
|
expect(page.workers().length).toBe(1);
|
||||||
|
expect(page.workers()[0].frame()).toBe(frame);
|
||||||
|
let destroyed = false;
|
||||||
|
page.once('workerdestroyed', () => destroyed = true);
|
||||||
|
let navigated = false;
|
||||||
|
page.once('framenavigated', () => {
|
||||||
|
expect(destroyed).toBe(true);
|
||||||
|
expect(page.workers().length).toBe(0);
|
||||||
|
navigated = true;
|
||||||
|
});
|
||||||
|
await frame.goto(server.PREFIX + '/one-style.html');
|
||||||
|
expect(navigated).toBe(true);
|
||||||
|
});
|
||||||
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('workercreated');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue