From 7d753e80ec326157feb7fa18d3bb51d00ccb5d30 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 4 Oct 2024 15:24:35 +0100 Subject: [PATCH] fix: throw when element handle is detached while waiting for selector --- packages/playwright-core/src/server/frames.ts | 2 ++ tests/page/page-wait-for-selector-2.spec.ts | 28 +++++++++++++++++++ tests/page/selectors-frame.spec.ts | 11 -------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index d107a7f981..70a699889a 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -805,6 +805,8 @@ export class Frame extends SdkObject { return continuePolling; } const result = await resolved.injected.evaluateHandle((injected, { info, root }) => { + if (root && !root.isConnected) + throw injected.createStacklessError('Element is not attached to the DOM'); const elements = injected.querySelectorAll(info.parsed, root || document); const element: Element | undefined = elements[0]; const visible = element ? injected.utils.isElementVisible(element) : false; diff --git a/tests/page/page-wait-for-selector-2.spec.ts b/tests/page/page-wait-for-selector-2.spec.ts index 5a23e581c7..4f473f86f2 100644 --- a/tests/page/page-wait-for-selector-2.spec.ts +++ b/tests/page/page-wait-for-selector-2.spec.ts @@ -328,3 +328,31 @@ it('should fail when navigating while on handle', async ({ page, mode, server }) const error = await body.waitForSelector('div', { __testHookBeforeAdoptNode } as any).catch(e => e); expect(error.message).toContain(`waiting for locator('div') to be visible`); }); + +it('should fail if element handle was detached while waiting', async ({ page, server }) => { + await page.setContent(``); + const button = await page.$('button'); + const promise = button.waitForSelector('something').catch(e => e); + await page.waitForTimeout(100); + await page.evaluate(() => document.body.innerText = ''); + const error = await promise; + expect(error.message).toContain('Element is not attached to the DOM'); +}); + +it('should succeed if element handle was detached while waiting for hidden', async ({ page, server }) => { + await page.setContent(``); + const button = await page.$('button'); + const promise = button.waitForSelector('something', { state: 'hidden' }); + await page.waitForTimeout(100); + await page.evaluate(() => document.body.innerText = ''); + await promise; +}); + +it('should succeed if element handle was detached while waiting for detached', async ({ page, server }) => { + await page.setContent(``); + const button = await page.$('button'); + const promise = button.waitForSelector('something', { state: 'detached' }); + await page.waitForTimeout(100); + await page.evaluate(() => document.body.innerText = ''); + await promise; +}); diff --git a/tests/page/selectors-frame.spec.ts b/tests/page/selectors-frame.spec.ts index c32a00e8e9..fda55e9958 100644 --- a/tests/page/selectors-frame.spec.ts +++ b/tests/page/selectors-frame.spec.ts @@ -308,17 +308,6 @@ it('click should survive navigation', async ({ page, server }) => { await promise; }); -it('should fail if element removed while waiting on element handle', async ({ page, server }) => { - it.fixme(); - await routeIframe(page); - await page.goto(server.PREFIX + '/iframe.html'); - const button = await page.$('button'); - const promise = button.waitForSelector('something'); - await page.waitForTimeout(100); - await page.evaluate(() => document.body.innerText = ''); - await promise; -}); - it('should non work for non-frame', async ({ page, server }) => { await routeIframe(page); await page.setContent('
');