mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
fix(page): intersect content quads with viewport (#4277)
In certain cases inline element children might be positioned outside of viewport. In this case, we should intersect all content quads with viewport before we pick one to click into. Fixes #4274.
This commit is contained in:
parent
20988775bf
commit
5ee21d97e7
@ -189,13 +189,17 @@ class ElementHandle extends JSHandle {
|
||||
* @return {!Promise<!{x: number, y: number}>}
|
||||
*/
|
||||
async _clickablePoint() {
|
||||
const result = await this._client.send('DOM.getContentQuads', {
|
||||
objectId: this._remoteObject.objectId
|
||||
}).catch(debugError);
|
||||
const [result, layoutMetrics] = await Promise.all([
|
||||
this._client.send('DOM.getContentQuads', {
|
||||
objectId: this._remoteObject.objectId
|
||||
}).catch(debugError),
|
||||
this._client.send('Page.getLayoutMetrics'),
|
||||
]);
|
||||
if (!result || !result.quads.length)
|
||||
throw new Error('Node is either not visible or not an HTMLElement');
|
||||
// Filter out quads that have too small area to click into.
|
||||
const quads = result.quads.map(quad => this._fromProtocolQuad(quad)).filter(quad => computeQuadArea(quad) > 1);
|
||||
const {clientWidth, clientHeight} = layoutMetrics.layoutViewport;
|
||||
const quads = result.quads.map(quad => this._fromProtocolQuad(quad)).map(quad => this._intersectQuadWithViewport(quad, clientWidth, clientHeight)).filter(quad => computeQuadArea(quad) > 1);
|
||||
if (!quads.length)
|
||||
throw new Error('Node is either not visible or not an HTMLElement');
|
||||
// Return the middle point of the first quad.
|
||||
@ -234,6 +238,19 @@ class ElementHandle extends JSHandle {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<{x: number, y: number}>} quad
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
* @return {!Array<{x: number, y: number}>}
|
||||
*/
|
||||
_intersectQuadWithViewport(quad, width, height) {
|
||||
return quad.map(point => ({
|
||||
x: Math.min(Math.max(point.x, 0), width),
|
||||
y: Math.min(Math.max(point.y, 0), height),
|
||||
}));
|
||||
}
|
||||
|
||||
async hover() {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const {x, y} = await this._clickablePoint();
|
||||
|
@ -50,6 +50,19 @@ module.exports.addTests = function({testRunner, expect}) {
|
||||
]);
|
||||
expect(page.url()).toBe(server.PREFIX + '/wrappedlink.html#clicked');
|
||||
});
|
||||
it_fails_ffox('should click when one of inline box children is outside of viewport', async({page, server}) => {
|
||||
await page.setContent(`
|
||||
<style>
|
||||
i {
|
||||
position: absolute;
|
||||
top: -1000px;
|
||||
}
|
||||
</style>
|
||||
<span onclick='javascript:window.CLICKED = 42;'><i>woof</i><b>doggo</b></span>
|
||||
`);
|
||||
await page.click('span');
|
||||
expect(await page.evaluate(() => window.CLICKED)).toBe(42);
|
||||
});
|
||||
it('should select the text by triple clicking', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.focus('textarea');
|
||||
|
Loading…
Reference in New Issue
Block a user