Skip to content

Commit af2340c

Browse files
authored
fix(click): explicitly fail when element detached during click (#1835)
We used to timeout instead.
1 parent 629b772 commit af2340c

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

src/injected/injected.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,12 +286,16 @@ class Injected {
286286
// and only force layout during actual rafs as a small optimisation.
287287
if (++counter === 1)
288288
return false;
289+
if (!node.isConnected)
290+
return 'Element is not attached to the DOM';
289291
const clientRect = element.getBoundingClientRect();
290292
const rect = { x: clientRect.top, y: clientRect.left, width: clientRect.width, height: clientRect.height };
291293
const isDisplayedAndStable = lastRect && rect.x === lastRect.x && rect.y === lastRect.y && rect.width === lastRect.width && rect.height === lastRect.height && rect.width > 0 && rect.height > 0;
292294
lastRect = rect;
293295
return isDisplayedAndStable;
294296
});
297+
if (typeof result === 'string')
298+
throw new Error(result);
295299
if (!result)
296300
throw new Error(`waiting for element to be displayed and not moving failed: timeout exceeded`);
297301
}
@@ -303,11 +307,15 @@ class Injected {
303307
if (!element)
304308
throw new Error('Element is not attached to the DOM');
305309
const result = await this.poll('raf', timeout, () => {
310+
if (!element!.isConnected)
311+
return 'Element is not attached to the DOM';
306312
let hitElement = this._deepElementFromPoint(document, point.x, point.y);
307313
while (hitElement && hitElement !== element)
308314
hitElement = this._parentElementOrShadowHost(hitElement);
309315
return hitElement === element;
310316
});
317+
if (typeof result === 'string')
318+
throw new Error(result);
311319
if (!result)
312320
throw new Error(`waiting for element to receive mouse events failed: timeout exceeded`);
313321
}

test/click.spec.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,25 @@ describe('Page.click', function() {
554554
if (error2)
555555
expect(error2.message).toContain('timeout exceeded');
556556
});
557+
it('should fail when element detaches after animation', async({page, server}) => {
558+
await page.setContent(`<style>body, html { margin: 0; padding: 0; }</style><button onclick="window.clicked=true">Click me</button>`);
559+
await page.$eval('button', button => {
560+
button.style.transition = 'margin-left 100000ms linear';
561+
});
562+
await page.$eval('button', button => {
563+
button.style.marginLeft = '100000px';
564+
});
565+
const handle = await page.$('button');
566+
const promise = handle.click().catch(e => e);
567+
await page.$eval('button', button => {
568+
button.style.marginLeft = button.getBoundingClientRect().left + 'px';
569+
button.style.transition = '';
570+
button.remove();
571+
});
572+
const error = await promise;
573+
expect(await page.evaluate(() => window.clicked)).toBe(undefined);
574+
expect(error.message).toContain('Element is not attached to the DOM');
575+
});
557576
});
558577

559578
describe('Page.check', function() {

0 commit comments

Comments
 (0)