From c8331ec736ac5352f5e0b72e62f39a5bd0bc4249 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Tue, 28 Apr 2020 10:43:48 -0700 Subject: [PATCH] test(click): add a test for 'Element has moved' exception --- src/dom.ts | 4 +++- test/assets/input/animating-button.html | 10 ++++++++++ test/click.spec.js | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/dom.ts b/src/dom.ts index 0fe435a0b5cdb..047ee129f526c 100644 --- a/src/dom.ts +++ b/src/dom.ts @@ -240,6 +240,8 @@ export class ElementHandle extends js.JSHandle { point.x = (point.x * 100 | 0) / 100; point.y = (point.y * 100 | 0) / 100; await this._page.mouse.move(point.x, point.y); // Force any hover effects before waiting for hit target. + if (options && (options as any).__testHookBeforeWaitForHitTarget) + await (options as any).__testHookBeforeWaitForHitTarget(); if (!force) await this._waitForHitTargetAt(point, deadline); @@ -437,7 +439,7 @@ export class ElementHandle extends js.JSHandle { const element = await frame.frameElement(); const box = await element.boundingBox(); if (!box) - throw new Error('Element is not attached to the DOM'); + throw new NotConnectedError(); // Translate from viewport coordinates to frame coordinates. point = { x: point.x - box.x, y: point.y - box.y }; } diff --git a/test/assets/input/animating-button.html b/test/assets/input/animating-button.html index d36176fd924bc..a3a05fd6ab814 100644 --- a/test/assets/input/animating-button.html +++ b/test/assets/input/animating-button.html @@ -21,4 +21,14 @@ if (remove) button.remove(); } +function startJumping() { + const button = document.querySelector('button'); + let x = 0; + const moveIt = () => { + x += 300; + button.style.marginLeft = x + 'px'; + requestAnimationFrame(moveIt); + }; + moveIt(); +} diff --git a/test/click.spec.js b/test/click.spec.js index b93a9f63cc65c..bd5764c964a85 100644 --- a/test/click.spec.js +++ b/test/click.spec.js @@ -571,6 +571,21 @@ describe('Page.click', function() { expect(clicked).toBe(true); expect(await page.evaluate(() => window.clicked)).toBe(true); }); + it('should fail when element moves during hit testing', async({page, server}) => { + await page.goto(server.PREFIX + '/input/animating-button.html'); + await page.evaluate(() => addButton()); + let clicked = false; + const handle = await page.$('button'); + const __testHookBeforeWaitForHitTarget = () => page.evaluate(() => startJumping()); + const promise = handle.click({ timeout: 0, __testHookBeforeWaitForHitTarget }).then(() => clicked = true).catch(e => e); + expect(clicked).toBe(false); + expect(await page.evaluate(() => window.clicked)).toBe(undefined); + await page.evaluate(() => stopButton()); + const error = await promise; + expect(clicked).toBe(false); + expect(error.message).toBe('Element has moved during the action'); + expect(await page.evaluate(() => window.clicked)).toBe(undefined); + }); it('should fail when element is blocked on hover', async({page, server}) => { await page.setContent(`