mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
fix(Page.click): throw a meaningful message for invisible elements (#1309)
This patch starts throwing a meaningful error message when trying to click the hidden node. References #1294
This commit is contained in:
parent
3cb0f1af34
commit
b58d319926
@ -1786,7 +1786,7 @@ The method runs `element.querySelectorAll` within the page. If no elements match
|
||||
- width <[number]> the width of the element in pixels.
|
||||
- height <[number]> the height of the element in pixels.
|
||||
|
||||
This method returns the bounding box of the element (relative to the main frame), or `null` if element is detached from dom.
|
||||
This method returns the bounding box of the element (relative to the main frame), or `null` if the element is not visible.
|
||||
|
||||
#### elementHandle.click([options])
|
||||
- `options` <[Object]>
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
const path = require('path');
|
||||
const {JSHandle} = require('./ExecutionContext');
|
||||
const {helper} = require('./helper');
|
||||
const {helper, debugError} = require('./helper');
|
||||
|
||||
class ElementHandle extends JSHandle {
|
||||
/**
|
||||
@ -59,6 +59,8 @@ class ElementHandle extends JSHandle {
|
||||
async _visibleCenter() {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const box = await this.boundingBox();
|
||||
if (!box)
|
||||
throw new Error('Node is not visible');
|
||||
return {
|
||||
x: box.x + box.width / 2,
|
||||
y: box.y + box.height / 2
|
||||
@ -116,16 +118,17 @@ class ElementHandle extends JSHandle {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<{x: number, y: number, width: number, height: number}>}
|
||||
* @return {!Promise<?{x: number, y: number, width: number, height: number}>}
|
||||
*/
|
||||
async boundingBox() {
|
||||
const {model} = await this._client.send('DOM.getBoxModel', {
|
||||
const result = await this._client.send('DOM.getBoxModel', {
|
||||
objectId: this._remoteObject.objectId
|
||||
});
|
||||
if (!model)
|
||||
throw new Error('Node is detached from document');
|
||||
}).catch(error => void debugError(error));
|
||||
|
||||
const quad = model.border;
|
||||
if (!result)
|
||||
return null;
|
||||
|
||||
const quad = result.model.border;
|
||||
const x = Math.min(quad[0], quad[2], quad[4], quad[6]);
|
||||
const y = Math.min(quad[1], quad[3], quad[5], quad[7]);
|
||||
const width = Math.max(quad[0], quad[2], quad[4], quad[6]) - x;
|
||||
@ -142,6 +145,8 @@ class ElementHandle extends JSHandle {
|
||||
async screenshot(options = {}) {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const boundingBox = await this.boundingBox();
|
||||
if (!boundingBox)
|
||||
throw new Error('Node is not visible');
|
||||
|
||||
return await this._page.screenshot(Object.assign({}, {
|
||||
clip: boundingBox
|
||||
|
33
test/test.js
33
test/test.js
@ -1688,6 +1688,11 @@ describe('Page', function() {
|
||||
const box = await elementHandle.boundingBox();
|
||||
expect(box).toEqual({ x: 28, y: 260, width: 264, height: 18 });
|
||||
}));
|
||||
it('should return null for invisible elements', SX(async function() {
|
||||
await page.setContent('<div style="display:none">hi</div>');
|
||||
const element = await page.$('div');
|
||||
expect(await element.boundingBox()).toBe(null);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('ElementHandle.click', function() {
|
||||
@ -1718,6 +1723,26 @@ describe('Page', function() {
|
||||
await button.click().catch(err => error = err);
|
||||
expect(error.message).toBe('Node is detached from document');
|
||||
}));
|
||||
it('should throw for hidden nodes', SX(async function() {
|
||||
await page.goto(PREFIX + '/input/button.html');
|
||||
const button = await page.$('button');
|
||||
await page.evaluate(button => button.style.display = 'none', button);
|
||||
const error = await button.click().catch(err => err);
|
||||
expect(error.message).toBe('Node is not visible');
|
||||
}));
|
||||
it('should throw for recursively hidden nodes', SX(async function() {
|
||||
await page.goto(PREFIX + '/input/button.html');
|
||||
const button = await page.$('button');
|
||||
await page.evaluate(button => button.parentElement.style.display = 'none', button);
|
||||
const error = await button.click().catch(err => err);
|
||||
expect(error.message).toBe('Node is not visible');
|
||||
}));
|
||||
it('should throw for <br> elements', SX(async function() {
|
||||
await page.setContent('hello<br>goodbye');
|
||||
const br = await page.$('br');
|
||||
const error = await br.click().catch(err => err);
|
||||
expect(error.message).toBe('Node is not visible');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('ElementHandle.hover', function() {
|
||||
@ -2583,6 +2608,14 @@ describe('Page', function() {
|
||||
expect(await page.evaluate(() => window.innerWidth)).toBe(375);
|
||||
expect(await page.evaluate(() => navigator.userAgent)).toContain('Safari');
|
||||
}));
|
||||
it('should support clicking', SX(async function() {
|
||||
await page.emulate(iPhone);
|
||||
await page.goto(PREFIX + '/input/button.html');
|
||||
const button = await page.$('button');
|
||||
await page.evaluate(button => button.style.marginTop = '200px', button);
|
||||
await button.click();
|
||||
expect(await page.evaluate(() => result)).toBe('Clicked');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Page.emulateMedia', function() {
|
||||
|
Loading…
Reference in New Issue
Block a user