feat(ElementHandle): implement ElementHandle.contentFrame() (#2094)

This patch adds ElementHandle.contentFrame() method that allows
to get a reference to the Frame owned by the iframe.

Fixes #433.
This commit is contained in:
Andrey Lushnikov 2018-02-23 21:22:53 -08:00 committed by GitHub
parent e2b96df4d7
commit 223b59254c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 2 deletions

View File

@ -187,6 +187,7 @@
* [elementHandle.asElement()](#elementhandleaselement)
* [elementHandle.boundingBox()](#elementhandleboundingbox)
* [elementHandle.click([options])](#elementhandleclickoptions)
* [elementHandle.contentFrame()](#elementhandlecontentframe)
* [elementHandle.dispose()](#elementhandledispose)
* [elementHandle.executionContext()](#elementhandleexecutioncontext)
* [elementHandle.focus()](#elementhandlefocus)
@ -2187,6 +2188,9 @@ This method returns the bounding box of the element (relative to the main frame)
This method scrolls element into view if needed, and then uses [page.mouse](#pagemouse) to click in the center of the element.
If the element is detached from DOM, the method throws an error.
#### elementHandle.contentFrame()
- returns: <[Promise]<?[Frame]>> Resolves to the content frame for element handles referencing iframe nodes, or null otherwise
#### elementHandle.dispose()
- returns: <[Promise]> Promise which resolves when the element handle is successfully disposed.

View File

@ -23,12 +23,14 @@ class ElementHandle extends JSHandle {
* @param {!Puppeteer.CDPSession} client
* @param {!Object} remoteObject
* @param {!Puppeteer.Page} page
* @param {!Puppeteer.FrameManager} frameManager
*/
constructor(context, client, remoteObject, page) {
constructor(context, client, remoteObject, page, frameManager) {
super(context, client, remoteObject);
this._client = client;
this._remoteObject = remoteObject;
this._page = page;
this._frameManager = frameManager;
this._disposed = false;
}
@ -40,6 +42,18 @@ class ElementHandle extends JSHandle {
return this;
}
/**
* @return {!Promise<?Puppeteer.Frame>}
*/
async contentFrame() {
const nodeInfo = await this._client.send('DOM.describeNode', {
objectId: this._remoteObject.objectId
});
if (typeof nodeInfo.node.frameId !== 'string')
return null;
return this._frameManager.frame(nodeInfo.node.frameId);
}
async _scrollIntoViewIfNeeded() {
const error = await this.executionContext().evaluate(element => {
if (!element.isConnected)

View File

@ -196,7 +196,7 @@ class FrameManager extends EventEmitter {
const context = this._contextIdToContext.get(contextId);
console.assert(context, 'INTERNAL ERROR: missing context with id = ' + contextId);
if (remoteObject.subtype === 'node')
return new ElementHandle(context, this._client, remoteObject, this._page);
return new ElementHandle(context, this._client, remoteObject, this._page, this);
return new JSHandle(context, this._client, remoteObject);
}

View File

@ -2039,6 +2039,16 @@ describe('Page', function() {
});
});
describe('ElementHandle.contentFrame', function() {
it('should work', async({page,server}) => {
await page.goto(server.EMPTY_PAGE);
await FrameUtils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
const elementHandle = await page.$('#frame1');
const frame = await elementHandle.contentFrame();
expect(frame).toBe(page.frames()[1]);
});
});
describe('ElementHandle.click', function() {
it('should work', async({page, server}) => {
await page.goto(server.PREFIX + '/input/button.html');