diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index ef8356ca63..23542301fe 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -1256,8 +1256,13 @@ export class Frame extends SdkObject { const pair = await this.resolveFrameForSelectorNoWait(selector, options); if (!pair) return false; - const element = await this._page.selectors.query(pair.frame, pair.info); - return element ? await element.isVisible() : false; + const context = await pair.frame._context(pair.info.world); + const injectedScript = await context.injectedScript(); + return await injectedScript.evaluate((injected, { parsed, strict }) => { + const element = injected.querySelector(parsed, document, strict); + const state = element ? injected.elementState(element, 'visible') : false; + return state === 'error:notconnected' ? false : state; + }, { parsed: pair.info.parsed, strict: pair.info.strict }); }, this._page._timeoutSettings.timeout({})); } diff --git a/tests/page/elementhandle-convenience.spec.ts b/tests/page/elementhandle-convenience.spec.ts index ff17d8c9c5..0d5ed7ee28 100644 --- a/tests/page/elementhandle-convenience.spec.ts +++ b/tests/page/elementhandle-convenience.spec.ts @@ -308,3 +308,25 @@ it('isChecked should work', async ({ page }) => { const error = await page.isChecked('div').catch(e => e); expect(error.message).toContain('Not a checkbox or radio button'); }); + +it('isVisible should be atomic', async ({ playwright, page }) => { + const createDummySelector = () => ({ + query(root, selector) { + const result = root.querySelector(selector); + if (result) + Promise.resolve().then(() => result.style.display = 'none'); + return result; + }, + queryAll(root: HTMLElement, selector: string) { + const result = Array.from(root.querySelectorAll(selector)); + for (const e of result) + Promise.resolve().then(() => (e as HTMLElement).style.display = 'none'); + return result; + } + }); + await playwright.selectors.register('isVisible', createDummySelector); + await page.setContent(`
Hello
`); + const result = await page.isVisible('isVisible=div'); + expect(result).toBe(true); + expect(await page.evaluate(() => document.querySelector('div').style.display)).toBe('none'); +});