diff --git a/src/common/AriaQueryHandler.ts b/src/common/AriaQueryHandler.ts index cb3fd341dcde6..fd06cfe2b2114 100644 --- a/src/common/AriaQueryHandler.ts +++ b/src/common/AriaQueryHandler.ts @@ -92,8 +92,8 @@ const waitFor = async ( const binding: PageBinding = { name: 'ariaQuerySelector', pptrFunction: async (selector: string) => { - const document = await domWorld._document(); - const element = await queryOne(document, selector); + const root = options.root || (await domWorld._document()); + const element = await queryOne(root, selector); return element; }, }; diff --git a/src/common/DOMWorld.ts b/src/common/DOMWorld.ts index 54b5dc206418c..14d23d0418f13 100644 --- a/src/common/DOMWorld.ts +++ b/src/common/DOMWorld.ts @@ -832,8 +832,9 @@ export class WaitTask { if (this._terminated || runCount !== this._runCount) return; try { if (this._root) { - success = await this._root.evaluateHandle( + success = await context.evaluateHandle( waitForPredicatePageFunction, + this._root, this._predicateBody, this._polling, this._timeout, diff --git a/src/common/JSHandle.ts b/src/common/JSHandle.ts index 43b33235377ab..e6358fba96ef6 100644 --- a/src/common/JSHandle.ts +++ b/src/common/JSHandle.ts @@ -381,7 +381,7 @@ export class ElementHandle< * (30 seconds). Pass `0` to disable timeout. The default value can be changed * by using the {@link Page.setDefaultTimeout} method. */ - waitForSelector( + async waitForSelector( selector: string, options: { visible?: boolean; @@ -389,10 +389,19 @@ export class ElementHandle< timeout?: number; } = {} ): Promise { - return this._context._world.waitForSelector(selector, { + const frame = this._context.frame(); + const secondaryContext = await frame._secondaryWorld.executionContext(); + const adoptedRoot = await secondaryContext._adoptElementHandle(this); + const handle = await frame._secondaryWorld.waitForSelector(selector, { ...options, - root: this, + root: adoptedRoot, }); + await adoptedRoot.dispose(); + if (!handle) return null; + const mainExecutionContext = await frame._mainWorld.executionContext(); + const result = await mainExecutionContext._adoptElementHandle(handle); + await handle.dispose(); + return result; } asElement(): ElementHandle | null { diff --git a/test/ariaqueryhandler.spec.ts b/test/ariaqueryhandler.spec.ts index 2773520853716..504706af88a2d 100644 --- a/test/ariaqueryhandler.spec.ts +++ b/test/ariaqueryhandler.spec.ts @@ -196,6 +196,16 @@ describeChromeOnly('AriaQueryHandler', () => { await page.waitForSelector('aria/[role="button"]'); }); + it('should work for ElementHandler.waitForSelector', async () => { + const { page, server } = getTestState(); + await page.goto(server.EMPTY_PAGE); + await page.evaluate( + () => (document.body.innerHTML = `
`) + ); + const element = await page.$('div'); + await element.waitForSelector('aria/test'); + }); + it('should persist query handler bindings across reloads', async () => { const { page, server } = getTestState(); await page.goto(server.EMPTY_PAGE);