mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-14 13:45:36 +03:00
fix(click): account for detached elements and iframe overlays (#10206)
This commit is contained in:
parent
1e38ec5fa4
commit
9ec3e7cd52
@ -413,7 +413,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||
return this._finishPointerActionDetectLayoutShift(progress, actionName, point, options, action);
|
||||
}
|
||||
|
||||
private async _finishPointerAction(progress: Progress, actionName: string, point: types.Point, options: types.PointerActionOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions, action: (point: types.Point) => Promise<void>) {
|
||||
private async _finishPointerAction(progress: Progress, actionName: string, point: types.Point, options: types.PointerActionOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions, action: (point: types.Point) => Promise<void>): Promise<'error:notconnected' | { hitTargetDescription: string } | 'done'> {
|
||||
if (!options.force) {
|
||||
if ((options as any).__testHookBeforeHitTarget)
|
||||
await (options as any).__testHookBeforeHitTarget();
|
||||
@ -451,7 +451,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||
return 'done';
|
||||
}
|
||||
|
||||
private async _finishPointerActionDetectLayoutShift(progress: Progress, actionName: string, point: types.Point, options: types.PointerActionOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions, action: (point: types.Point) => Promise<void>) {
|
||||
private async _finishPointerActionDetectLayoutShift(progress: Progress, actionName: string, point: types.Point, options: types.PointerActionOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions, action: (point: types.Point) => Promise<void>): Promise<'error:notconnected' | { hitTargetDescription: string } | 'done'> {
|
||||
await progress.beforeInputAction(this);
|
||||
|
||||
let hitTargetInterceptionHandle: js.JSHandle<HitTargetInterceptionResult> | undefined;
|
||||
|
@ -728,6 +728,11 @@ export class InjectedScript {
|
||||
if (!event.isTrusted)
|
||||
return;
|
||||
|
||||
// Element was detached during the action, for example in some event handler.
|
||||
// If events before that were correctly pointing to it, consider this a valid scenario.
|
||||
if (!element.isConnected)
|
||||
return;
|
||||
|
||||
// Determine the event point. Note that Firefox does not always have window.TouchEvent.
|
||||
const point = (!!window.TouchEvent && (event instanceof window.TouchEvent)) ? event.touches[0] : (event as MouseEvent | PointerEvent);
|
||||
if (!!point && (result === undefined || result === 'done')) {
|
||||
@ -745,7 +750,11 @@ export class InjectedScript {
|
||||
const stop = () => {
|
||||
if (this._hitTargetInterceptor === listener)
|
||||
this._hitTargetInterceptor = undefined;
|
||||
return result!;
|
||||
// If we did not get any events, consider things working. Possible causes:
|
||||
// - JavaScript is disabled (webkit-only).
|
||||
// - Some <iframe> overlays the element from another frame.
|
||||
// - Hovering a disabled control prevents any events from firing.
|
||||
return result || 'done';
|
||||
};
|
||||
|
||||
// Note: this removes previous listener, just in case there are two concurrent clicks
|
||||
|
@ -68,6 +68,19 @@ it('should block click when mousedown succeeds but mouseup fails', async ({ page
|
||||
]);
|
||||
});
|
||||
|
||||
it('should click when element detaches in mousedown', async ({ page, server }) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.$eval('button', button => {
|
||||
button.addEventListener('mousedown', () => {
|
||||
(window as any).result = 'Mousedown';
|
||||
button.remove();
|
||||
});
|
||||
});
|
||||
|
||||
await page.click('button', { timeout: 1000 });
|
||||
expect(await page.evaluate('result')).toBe('Mousedown');
|
||||
});
|
||||
|
||||
it('should not block programmatic events', async ({ page, server }) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.$eval('button', button => {
|
||||
|
Loading…
Reference in New Issue
Block a user