Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ const iPhone11 = devices['iPhone 11 Pro'];
(async () => {
const browser = await webkit.launch();
const context = await browser.newContext({
viewport: iPhone11.viewport,
userAgent: iPhone11.userAgent,
...iPhone11,
geolocation: { longitude: 12.492507, latitude: 41.889938 },
permissions: ['geolocation']
});
Expand Down
16 changes: 15 additions & 1 deletion src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import * as debug from 'debug';
import * as fs from 'fs';
import * as mime from 'mime';
import * as path from 'path';
Expand All @@ -36,6 +37,8 @@ export type ClickOptions = PointerActionOptions & input.MouseClickOptions;

export type MultiClickOptions = PointerActionOptions & input.MouseMultiClickOptions;

const debugInput = debug('pw:input');

export class FrameExecutionContext extends js.ExecutionContext {
readonly frame: frames.Frame;
private _injectedPromise?: Promise<js.JSHandle>;
Expand Down Expand Up @@ -112,7 +115,9 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
}

async _scrollRectIntoViewIfNeeded(rect?: types.Rect): Promise<void> {
debugInput('scrolling into veiw if needed...');
await this._page._delegate.scrollRectIntoViewIfNeeded(this, rect);
debugInput('...done');
}

async scrollIntoViewIfNeeded() {
Expand Down Expand Up @@ -186,11 +191,16 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
if (!force)
await this._waitForHitTargetAt(point, options);

point.x = (point.x * 100 | 0) / 100;
point.y = (point.y * 100 | 0) / 100;

await this._page._frameManager.waitForNavigationsCreatedBy(async () => {
let restoreModifiers: input.Modifier[] | undefined;
if (options && options.modifiers)
restoreModifiers = await this._page.keyboard._ensureModifiers(options.modifiers);
debugInput('performing input action...');
await action(point);
debugInput('...done');
if (restoreModifiers)
await this._page.keyboard._ensureModifiers(restoreModifiers);
}, options, true);
Expand Down Expand Up @@ -356,13 +366,16 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
}

async _waitForDisplayedAtStablePosition(options: types.TimeoutOptions = {}): Promise<void> {
debugInput('waiting for element to be displayed and not moving...');
const stablePromise = this._evaluateInUtility(({ injected, node }, timeout) => {
return injected.waitForDisplayedAtStablePosition(node, timeout);
}, options.timeout || 0);
await helper.waitWithTimeout(stablePromise, 'element to be displayed and not moving', options.timeout || 0);
debugInput('...done');
}

async _waitForHitTargetAt(point: types.Point, options: types.TimeoutOptions = {}): Promise<void> {
debugInput(`waiting for element to receive pointer events at (${point.x},${point.y}) ...`);
const frame = await this.ownerFrame();
if (frame && frame.parentFrame()) {
const element = await frame.frameElement();
Expand All @@ -375,7 +388,8 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
const hitTargetPromise = this._evaluateInUtility(({ injected, node }, { timeout, point }) => {
return injected.waitForHitTargetAt(node, timeout, point);
}, { timeout: options.timeout || 0, point });
await helper.waitWithTimeout(hitTargetPromise, 'element to receive mouse events', options.timeout || 0);
await helper.waitWithTimeout(hitTargetPromise, 'element to receive pointer events', options.timeout || 0);
debugInput('...done');
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/injected/injected.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,9 @@ class Injected {
}

async waitForHitTargetAt(node: Node, timeout: number, point: types.Point) {
const element = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement;
let element = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement;
while (element && window.getComputedStyle(element).pointerEvents === 'none')
element = element.parentElement;
if (!element)
throw new Error('Element is not attached to the DOM');
const result = await this.poll('raf', timeout, () => {
Expand Down
4 changes: 4 additions & 0 deletions test/click.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,10 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
expect(await page.evaluate(() => window.result)).toBe('Was not clicked');
});

it('should climb dom for pointer-events:none targets', async({page, server}) => {
await page.setContent('<button><label style="pointer-events:none">Click target</label></button>')
await page.click('text=Click target');
});
it('should update modifiers correctly', async({page, server}) => {
await page.goto(server.PREFIX + '/input/button.html');
await page.click('button', { modifiers: ['Shift'] });
Expand Down