fix: revert ExecutionContext reporting. (#3058)

It turned out that almost any usecase requires helper methods to access
DOM inside the ExecutionContext.

Instead of exposing execution contexts as-is, we should introduce
IsolatedWorld as a first-class citizen that will hold execution contexts
inside.
This commit is contained in:
Andrey Lushnikov 2018-08-09 18:14:21 -07:00 committed by GitHub
parent 28ccf5d795
commit be7626fa5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 5 additions and 103 deletions

View File

@ -59,8 +59,6 @@ Next Release: **Aug 9, 2018**
* [event: 'dialog'](#event-dialog) * [event: 'dialog'](#event-dialog)
* [event: 'domcontentloaded'](#event-domcontentloaded) * [event: 'domcontentloaded'](#event-domcontentloaded)
* [event: 'error'](#event-error) * [event: 'error'](#event-error)
* [event: 'executioncontextcreated'](#event-executioncontextcreated)
* [event: 'executioncontextdestroyed'](#event-executioncontextdestroyed)
* [event: 'frameattached'](#event-frameattached) * [event: 'frameattached'](#event-frameattached)
* [event: 'framedetached'](#event-framedetached) * [event: 'framedetached'](#event-framedetached)
* [event: 'framenavigated'](#event-framenavigated) * [event: 'framenavigated'](#event-framenavigated)
@ -183,7 +181,6 @@ Next Release: **Aug 9, 2018**
* [frame.evaluate(pageFunction, ...args)](#frameevaluatepagefunction-args) * [frame.evaluate(pageFunction, ...args)](#frameevaluatepagefunction-args)
* [frame.evaluateHandle(pageFunction, ...args)](#frameevaluatehandlepagefunction-args) * [frame.evaluateHandle(pageFunction, ...args)](#frameevaluatehandlepagefunction-args)
* [frame.executionContext()](#frameexecutioncontext) * [frame.executionContext()](#frameexecutioncontext)
* [frame.executionContexts()](#frameexecutioncontexts)
* [frame.focus(selector)](#framefocusselector) * [frame.focus(selector)](#framefocusselector)
* [frame.hover(selector)](#framehoverselector) * [frame.hover(selector)](#framehoverselector)
* [frame.isDetached()](#frameisdetached) * [frame.isDetached()](#frameisdetached)
@ -203,8 +200,6 @@ Next Release: **Aug 9, 2018**
* [executionContext.evaluate(pageFunction, ...args)](#executioncontextevaluatepagefunction-args) * [executionContext.evaluate(pageFunction, ...args)](#executioncontextevaluatepagefunction-args)
* [executionContext.evaluateHandle(pageFunction, ...args)](#executioncontextevaluatehandlepagefunction-args) * [executionContext.evaluateHandle(pageFunction, ...args)](#executioncontextevaluatehandlepagefunction-args)
* [executionContext.frame()](#executioncontextframe) * [executionContext.frame()](#executioncontextframe)
* [executionContext.isDefault()](#executioncontextisdefault)
* [executionContext.name()](#executioncontextname)
* [executionContext.queryObjects(prototypeHandle)](#executioncontextqueryobjectsprototypehandle) * [executionContext.queryObjects(prototypeHandle)](#executioncontextqueryobjectsprototypehandle)
- [class: JSHandle](#class-jshandle) - [class: JSHandle](#class-jshandle)
* [jsHandle.asElement()](#jshandleaselement) * [jsHandle.asElement()](#jshandleaselement)
@ -804,16 +799,6 @@ Emitted when the page crashes.
> **NOTE** `error` event has a special meaning in Node, see [error events](https://nodejs.org/api/events.html#events_error_events) for details. > **NOTE** `error` event has a special meaning in Node, see [error events](https://nodejs.org/api/events.html#events_error_events) for details.
#### event: 'executioncontextcreated'
- <[ExecutionContext]>
Emitted whenever an execution context is created in one of the page's frames.
#### event: 'executioncontextdestroyed'
- <[ExecutionContext]>
Emitted whenever an execution context is removed from one of the page's frames.
#### event: 'frameattached' #### event: 'frameattached'
- <[Frame]> - <[Frame]>
@ -2248,11 +2233,6 @@ await resultHandle.dispose();
Returns promise that resolves to the frame's default execution context. Returns promise that resolves to the frame's default execution context.
#### frame.executionContexts()
- returns: <[Array]<[ExecutionContext]>>
Returns all execution contexts associated with this frame.
#### frame.focus(selector) #### frame.focus(selector)
- `selector` <[string]> A [selector] of an element to focus. If there are multiple elements satisfying the selector, the first will be focused. - `selector` <[string]> A [selector] of an element to focus. If there are multiple elements satisfying the selector, the first will be focused.
- returns: <[Promise]> Promise which resolves when the element matching `selector` is successfully focused. The promise will be rejected if there is no element matching `selector`. - returns: <[Promise]> Promise which resolves when the element matching `selector` is successfully focused. The promise will be rejected if there is no element matching `selector`.
@ -2452,11 +2432,7 @@ puppeteer.launch().then(async browser => {
The class represents a context for JavaScript execution. A [Page] might have many execution contexts: The class represents a context for JavaScript execution. A [Page] might have many execution contexts:
- each [frame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) has "default" execution context that is - each [frame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) has "default" execution context that is
always created after frame is attached to DOM. This context is returned by the [`frame.executionContext()`](#frameexecutioncontext) method. always created after frame is attached to DOM. This context is returned by the [`frame.executionContext()`](#frameexecutioncontext) method.
- [Extensions](https://developer.chrome.com/extensions)'s content scripts create additional execution contexts. These execution - [Extensions](https://developer.chrome.com/extensions)'s content scripts create additional execution contexts.
contexts can be obtained via the [`frame.executionContexts()`](#frameexecutioncontexts) method.
The execution context lifecycle can be observed with [Page]'s ['executioncontextcreated'](#event-executioncontextcreated) and
['executioncontextdestroyed'](#event-executioncontextdestroyed) events.
Besides pages, execution contexts can be found in [workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). Besides pages, execution contexts can be found in [workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).
@ -2525,19 +2501,6 @@ await resultHandle.dispose();
> **NOTE** Not every execution context is associated with a frame. For example, workers and extensions have execution contexts that are not associated with frames. > **NOTE** Not every execution context is associated with a frame. For example, workers and extensions have execution contexts that are not associated with frames.
#### executionContext.isDefault()
- returns: <[boolean]>
Returns `true` if the execution context is a frame's main execution context; returns `false` otherwise.
#### executionContext.name()
- returns: <[string]>
Returns execution context name, if any. If this execution context is associated with Chrome Extension's content
script, this will return extension's name.
#### executionContext.queryObjects(prototypeHandle) #### executionContext.queryObjects(prototypeHandle)
- `prototypeHandle` <[JSHandle]> A handle to the object prototype. - `prototypeHandle` <[JSHandle]> A handle to the object prototype.
- returns: <[JSHandle]> A handle to an array of objects with this prototype - returns: <[JSHandle]> A handle to an array of objects with this prototype

View File

@ -31,24 +31,9 @@ class ExecutionContext {
this._frame = frame; this._frame = frame;
this._contextId = contextPayload.id; this._contextId = contextPayload.id;
this._isDefault = contextPayload.auxData ? !!contextPayload.auxData['isDefault'] : false; this._isDefault = contextPayload.auxData ? !!contextPayload.auxData['isDefault'] : false;
this._name = contextPayload.name;
this._objectHandleFactory = objectHandleFactory; this._objectHandleFactory = objectHandleFactory;
} }
/**
* @return {string}
*/
name() {
return this._name;
}
/**
* @return {boolean}
*/
isDefault() {
return this._isDefault;
}
/** /**
* @return {?Puppeteer.Frame} * @return {?Puppeteer.Frame}
*/ */

View File

@ -188,7 +188,6 @@ class FrameManager extends EventEmitter {
this._contextIdToContext.set(contextPayload.id, context); this._contextIdToContext.set(contextPayload.id, context);
if (frame) if (frame)
frame._addExecutionContext(context); frame._addExecutionContext(context);
this.emit(FrameManager.Events.ExecutionContextCreated, context);
} }
/** /**
@ -201,18 +200,14 @@ class FrameManager extends EventEmitter {
this._contextIdToContext.delete(executionContextId); this._contextIdToContext.delete(executionContextId);
if (context.frame()) if (context.frame())
context.frame()._removeExecutionContext(context); context.frame()._removeExecutionContext(context);
this.emit(FrameManager.Events.ExecutionContextDestroyed, context);
} }
_onExecutionContextsCleared() { _onExecutionContextsCleared() {
const contexts = Array.from(this._contextIdToContext.values()); for (const context of this._contextIdToContext.values()) {
this._contextIdToContext.clear();
for (const context of contexts) {
if (context.frame()) if (context.frame())
context.frame()._removeExecutionContext(context); context.frame()._removeExecutionContext(context);
} }
for (const context of contexts) this._contextIdToContext.clear();
this.emit(FrameManager.Events.ExecutionContextDestroyed, context);
} }
/** /**
@ -281,8 +276,6 @@ class Frame {
this._contextResolveCallback = null; this._contextResolveCallback = null;
this._setDefaultContext(null); this._setDefaultContext(null);
this._executionContexts = new Set();
/** @type {!Set<!WaitTask>} */ /** @type {!Set<!WaitTask>} */
this._waitTasks = new Set(); this._waitTasks = new Set();
this._loaderId = ''; this._loaderId = '';
@ -299,8 +292,7 @@ class Frame {
* @param {!ExecutionContext} context * @param {!ExecutionContext} context
*/ */
_addExecutionContext(context) { _addExecutionContext(context) {
this._executionContexts.add(context); if (context._isDefault)
if (context.isDefault())
this._setDefaultContext(context); this._setDefaultContext(context);
} }
@ -308,8 +300,7 @@ class Frame {
* @param {!ExecutionContext} context * @param {!ExecutionContext} context
*/ */
_removeExecutionContext(context) { _removeExecutionContext(context) {
this._executionContexts.delete(context); if (context._isDefault)
if (context.isDefault())
this._setDefaultContext(null); this._setDefaultContext(null);
} }
@ -337,13 +328,6 @@ class Frame {
return this._contextPromise; return this._contextPromise;
} }
/**
* @return {!Array<!ExecutionContext>}
*/
executionContexts() {
return Array.from(this._executionContexts);
}
/** /**
* @param {function()|string} pageFunction * @param {function()|string} pageFunction
* @param {!Array<*>} args * @param {!Array<*>} args

View File

@ -121,8 +121,6 @@ class Page extends EventEmitter {
this._frameManager.on(FrameManager.Events.FrameAttached, event => this.emit(Page.Events.FrameAttached, event)); this._frameManager.on(FrameManager.Events.FrameAttached, event => this.emit(Page.Events.FrameAttached, event));
this._frameManager.on(FrameManager.Events.FrameDetached, event => this.emit(Page.Events.FrameDetached, event)); this._frameManager.on(FrameManager.Events.FrameDetached, event => this.emit(Page.Events.FrameDetached, event));
this._frameManager.on(FrameManager.Events.FrameNavigated, event => this.emit(Page.Events.FrameNavigated, event)); this._frameManager.on(FrameManager.Events.FrameNavigated, event => this.emit(Page.Events.FrameNavigated, event));
this._frameManager.on(FrameManager.Events.ExecutionContextCreated, event => this.emit(Page.Events.ExecutionContextCreated, event));
this._frameManager.on(FrameManager.Events.ExecutionContextDestroyed, event => this.emit(Page.Events.ExecutionContextDestroyed, event));
this._networkManager.on(NetworkManager.Events.Request, event => this.emit(Page.Events.Request, event)); this._networkManager.on(NetworkManager.Events.Request, event => this.emit(Page.Events.Request, event));
this._networkManager.on(NetworkManager.Events.Response, event => this.emit(Page.Events.Response, event)); this._networkManager.on(NetworkManager.Events.Response, event => this.emit(Page.Events.Response, event));
@ -1130,8 +1128,6 @@ Page.Events = {
Metrics: 'metrics', Metrics: 'metrics',
WorkerCreated: 'workercreated', WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed', WorkerDestroyed: 'workerdestroyed',
ExecutionContextCreated: 'executioncontextcreated',
ExecutionContextDestroyed: 'executioncontextdestroyed',
}; };

View File

@ -117,27 +117,6 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions})
]); ]);
await browser.close(); await browser.close();
}); });
it('should report content script execution contexts', async({server}) => {
const browserWithExtension = await puppeteer.launch(extensionOptions);
const page = await browserWithExtension.newPage();
const [extensionContext, msg] = await Promise.all([
waitEvent(page, 'executioncontextcreated', context => !context.isDefault()),
waitEvent(page, 'console'),
page.goto(server.EMPTY_PAGE)
]);
expect(msg.text()).toBe('hey from the content-script');
expect(page.mainFrame().executionContexts().length).toBe(2);
expect(extensionContext.frame()).toBe(page.mainFrame());
expect(extensionContext.name()).toBe('Simple extension');
expect(await extensionContext.evaluate('thisIsTheContentScript')).toBe(true);
const [destroyedContext] = await Promise.all([
waitEvent(page, 'executioncontextdestroyed', context => !context.isDefault()),
page.reload()
]);
expect(destroyedContext).toBe(extensionContext);
await browserWithExtension.close();
});
}); });
}; };

View File

@ -80,11 +80,6 @@ module.exports.addTests = function({testRunner, expect, headless}) {
const result = await page.evaluate(() => 7 * 3); const result = await page.evaluate(() => 7 * 3);
expect(result).toBe(21); expect(result).toBe(21);
}); });
it('should have nice default execution context', async({page, server}) => {
const executionContext = await page.mainFrame().executionContext();
expect(executionContext.name()).toBe('');
expect(executionContext.isDefault()).toBe(true);
});
it('should throw when evaluation triggers reload', async({page, server}) => { it('should throw when evaluation triggers reload', async({page, server}) => {
let error = null; let error = null;
await page.evaluate(() => { await page.evaluate(() => {