fix(scrollIntoView): make it work for nested frames case
This commit is contained in:
parent
8828228702
commit
51bf9f15c8
|
|
@ -445,10 +445,13 @@ export class FrameManager implements PageDelegate {
|
|||
}
|
||||
|
||||
async getContentFrame(handle: dom.ElementHandle): Promise<frames.Frame | null> {
|
||||
const doc = await handle.evaluateHandle(node => node.ownerDocument ? node.ownerDocument.documentElement : null);
|
||||
if (!doc)
|
||||
return null;
|
||||
const nodeInfo = await this._client.send('DOM.describeNode', {
|
||||
objectId: toRemoteObject(handle).objectId
|
||||
objectId: toRemoteObject(doc).objectId
|
||||
});
|
||||
if (typeof nodeInfo.node.frameId !== 'string')
|
||||
if (!nodeInfo || typeof nodeInfo.node.frameId !== 'string')
|
||||
return null;
|
||||
return this._page._frameManager.frame(nodeInfo.node.frameId);
|
||||
}
|
||||
|
|
@ -510,6 +513,16 @@ export class FrameManager implements PageDelegate {
|
|||
throw new Error('Unable to adopt element handle from a different document');
|
||||
return to._createHandle(result.object).asElement()!;
|
||||
}
|
||||
|
||||
async getFrameOwner(frame: frames.Frame): Promise<dom.ElementHandle | null> {
|
||||
if (!frame.parentFrame())
|
||||
return null;
|
||||
const result = await this._client.send('DOM.getFrameOwner', { frameId: frame._id });
|
||||
if (!result)
|
||||
return null;
|
||||
const utilityContext = await frame.parentFrame()._utilityContext();
|
||||
return this.adoptBackendNodeId(result.backendNodeId, utilityContext);
|
||||
}
|
||||
}
|
||||
|
||||
function toRemoteObject(handle: dom.ElementHandle): Protocol.Runtime.RemoteObject {
|
||||
|
|
|
|||
12
src/dom.ts
12
src/dom.ts
|
|
@ -152,6 +152,18 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
}
|
||||
|
||||
async _scrollIntoViewIfNeeded() {
|
||||
const path: frames.Frame[] = [];
|
||||
for (let frame = await this.contentFrame(); frame; frame = frame.parentFrame())
|
||||
path.push(frame);
|
||||
for (const frame of path.reverse()) {
|
||||
const owner = await frame._page._delegate.getFrameOwner(frame);
|
||||
if (owner)
|
||||
await owner._scrollIntoViewIfNeededWithinFrame();
|
||||
}
|
||||
this._scrollIntoViewIfNeededWithinFrame();
|
||||
}
|
||||
|
||||
async _scrollIntoViewIfNeededWithinFrame() {
|
||||
const error = await this.evaluate(async (node: Node, pageJavascriptEnabled: boolean) => {
|
||||
if (!node.isConnected)
|
||||
return 'Node is detached from document';
|
||||
|
|
|
|||
|
|
@ -406,6 +406,10 @@ export class FrameManager implements PageDelegate {
|
|||
assert(false, 'Multiple isolated worlds are not implemented');
|
||||
return handle;
|
||||
}
|
||||
|
||||
async getFrameOwner(frame: frames.Frame): Promise<dom.ElementHandle | null> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeWaitUntil(waitUntil: frames.LifecycleEvent | frames.LifecycleEvent[]): frames.LifecycleEvent[] {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ export interface PageDelegate {
|
|||
isElementHandle(remoteObject: any): boolean;
|
||||
adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>>;
|
||||
getContentFrame(handle: dom.ElementHandle): Promise<frames.Frame | null>;
|
||||
getFrameOwner(frame: frames.Frame): Promise<dom.ElementHandle | null>;
|
||||
getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null>;
|
||||
layoutViewport(): Promise<{ width: number, height: number }>;
|
||||
setInputFiles(handle: dom.ElementHandle, files: input.FilePayload[]): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -487,6 +487,10 @@ export class FrameManager implements PageDelegate {
|
|||
});
|
||||
return to._createHandle(result.object) as dom.ElementHandle<T>;
|
||||
}
|
||||
|
||||
async getFrameOwner(frame: frames.Frame): Promise<dom.ElementHandle | null> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
function toRemoteObject(handle: dom.ElementHandle): Protocol.Runtime.RemoteObject {
|
||||
|
|
|
|||
|
|
@ -261,8 +261,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||
await button.click();
|
||||
expect(await frame.evaluate(() => window.result)).toBe('Clicked');
|
||||
});
|
||||
// @see https://github.com/GoogleChrome/puppeteer/issues/4110
|
||||
xit('should click the button with fixed position inside an iframe', async({page, server}) => {
|
||||
it.skip(WEBKIT || FFOX)('should click the button with fixed position inside an iframe', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
await page.setContent('<div style="width:100px;height:2000px">spacer</div>');
|
||||
|
|
|
|||
|
|
@ -105,10 +105,6 @@ const utils = module.exports = {
|
|||
frame.src = url;
|
||||
frame.id = frameId;
|
||||
document.body.appendChild(frame);
|
||||
// TODO(einbinder) do this right
|
||||
// Access a scriptable global object to ensure JS context is
|
||||
// initialized. WebKit will create it lazily only as need be.
|
||||
frame.contentWindow;
|
||||
await new Promise(x => frame.onload = x);
|
||||
return frame;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue