fix(chromium): scroll into view elements inside iframes before waiting (#27394)

This forces iframes to be visible, so that `rAF`s always run.

Fixes #27196.
This commit is contained in:
Dmitry Gozman 2023-10-02 17:21:06 -07:00 committed by GitHub
parent c751bf135e
commit 2aca7fdcc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 13 deletions

View File

@ -361,6 +361,26 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
async _performPointerAction(progress: Progress, actionName: ActionName, waitForEnabled: boolean, action: (point: types.Point) => Promise<void>, forceScrollOptions: ScrollIntoViewOptions | undefined, options: types.PointerActionOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notvisible' | 'error:notconnected' | 'error:notinviewport' | { hitTargetDescription: string } | 'done'> {
const { force = false, position } = options;
const doScrollIntoView = async () => {
if (forceScrollOptions) {
return await this.evaluateInUtility(([injected, node, options]) => {
if (node.nodeType === 1 /* Node.ELEMENT_NODE */)
(node as Node as Element).scrollIntoView(options);
return 'done' as const;
}, forceScrollOptions);
}
return await this._scrollRectIntoViewIfNeeded(position ? { x: position.x, y: position.y, width: 0, height: 0 } : undefined);
};
if (this._frame.parentFrame()) {
// Best-effort scroll to make sure any iframes containing this element are scrolled
// into view and visible, so they are not throttled.
// See https://github.com/microsoft/playwright/issues/27196 for an example.
progress.throwIfAborted(); // Avoid action that has side-effects.
await doScrollIntoView().catch(() => {});
}
if ((options as any).__testHookBeforeStable)
await (options as any).__testHookBeforeStable();
const result = await this._waitForElementStates(progress, waitForEnabled ? ['visible', 'enabled', 'stable'] : ['visible', 'stable'], force);
@ -371,18 +391,9 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
progress.log(' scrolling into view if needed');
progress.throwIfAborted(); // Avoid action that has side-effects.
if (forceScrollOptions) {
const scrolled = await this.evaluateInUtility(([injected, node, options]) => {
if (node.nodeType === 1 /* Node.ELEMENT_NODE */)
(node as Node as Element).scrollIntoView(options);
}, forceScrollOptions);
if (scrolled === 'error:notconnected')
return scrolled;
} else {
const scrolled = await this._scrollRectIntoViewIfNeeded(position ? { x: position.x, y: position.y, width: 0, height: 0 } : undefined);
if (scrolled !== 'done')
return scrolled;
}
const scrolled = await doScrollIntoView();
if (scrolled !== 'done')
return scrolled;
progress.log(' done scrolling');
const maybePoint = position ? await this._offsetPoint(position) : await this._clickablePoint();

View File

@ -101,7 +101,6 @@ it('should scroll into view span element', async ({ page, isAndroid }) => {
it('should scroll into view element in iframe', async ({ page, isAndroid, server, browserName }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/27196' });
it.fixme(isAndroid);
it.fixme(browserName === 'chromium', 'rAFs are paused in cross-origin iframes outside viewport');
await page.goto(server.EMPTY_PAGE);
await page.setContent(`
<div id=big style="height: 10000px;"></div>