Skip to content

Commit

Permalink
fix!: remove root from WaitForSelectorOptions
Browse files Browse the repository at this point in the history
  • Loading branch information
jrandolf committed Aug 25, 2022
1 parent 6a330f8 commit 490ea15
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 103 deletions.
54 changes: 31 additions & 23 deletions src/common/AriaQueryHandler.ts
Expand Up @@ -18,11 +18,7 @@ import {Protocol} from 'devtools-protocol';
import {assert} from '../util/assert.js';
import {CDPSession} from './Connection.js';
import {ElementHandle} from './ElementHandle.js';
import {
IsolatedWorld,
PageBinding,
WaitForSelectorOptions,
} from './IsolatedWorld.js';
import {MAIN_WORLD, PageBinding, PUPPETEER_WORLD} from './IsolatedWorld.js';
import {InternalQueryHandler} from './QueryHandler.js';

async function queryAXTree(
Expand Down Expand Up @@ -89,10 +85,10 @@ function parseAriaSelector(selector: string): ARIAQueryOption {
return queryOptions;
}

const queryOne = async (
element: ElementHandle<Node>,
selector: string
): Promise<ElementHandle<Node> | null> => {
const queryOne: InternalQueryHandler['queryOne'] = async (
element,
selector
) => {
const exeCtx = element.executionContext();
const {name, role} = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
Expand All @@ -104,37 +100,49 @@ const queryOne = async (
)) as ElementHandle<Node>;
};

const waitFor = async (
isolatedWorld: IsolatedWorld,
selector: string,
options: WaitForSelectorOptions
): Promise<ElementHandle<Element> | null> => {
const waitFor: InternalQueryHandler['waitFor'] = async (
element,
selector,
options
) => {
element = await element.frame.worlds[PUPPETEER_WORLD].adoptHandle(element);
const binding: PageBinding = {
name: 'ariaQuerySelector',
pptrFunction: async (selector: string) => {
const root = options.root || (await isolatedWorld.document());
const element = await queryOne(root, selector);
return element;
const result = await queryOne(element, selector);
return result;
},
};
return (await isolatedWorld._waitForSelectorInPage(
const result = await element.frame.worlds[
PUPPETEER_WORLD
]._waitForSelectorInPage(
(_: Element, selector: string) => {
return (
globalThis as unknown as {
ariaQuerySelector(selector: string): void;
}
).ariaQuerySelector(selector);
},
element,
selector,
options,
binding
)) as ElementHandle<Element> | null;
);
await element.dispose();
if (!result) {
return null;
}
if (!(result instanceof ElementHandle)) {
await result.dispose();
return null;
}
return element.frame.worlds[MAIN_WORLD].transferHandle(result);
};

const queryAll = async (
element: ElementHandle<Node>,
selector: string
): Promise<Array<ElementHandle<Node>>> => {
const queryAll: InternalQueryHandler['queryAll'] = async (
element,
selector
) => {
const exeCtx = element.executionContext();
const {name, role} = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
Expand Down
34 changes: 10 additions & 24 deletions src/common/ElementHandle.ts
Expand Up @@ -3,11 +3,7 @@ import {assert} from '../util/assert.js';
import {ExecutionContext} from './ExecutionContext.js';
import {Frame} from './Frame.js';
import {FrameManager} from './FrameManager.js';
import {
MAIN_WORLD,
PUPPETEER_WORLD,
WaitForSelectorOptions,
} from './IsolatedWorld.js';
import {WaitForSelectorOptions} from './IsolatedWorld.js';
import {
BoundingBox,
BoxModel,
Expand Down Expand Up @@ -310,26 +306,16 @@ export class ElementHandle<
*/
async waitForSelector<Selector extends string>(
selector: Selector,
options: Exclude<WaitForSelectorOptions, 'root'> = {}
options: WaitForSelectorOptions = {}
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const frame = this.#frame;
const adoptedRoot = await frame.worlds[PUPPETEER_WORLD].adoptHandle(this);
const handle = await frame.worlds[PUPPETEER_WORLD].waitForSelector(
selector,
{
...options,
root: adoptedRoot,
}
);
await adoptedRoot.dispose();
if (!handle) {
return null;
}
const result = (await frame.worlds[MAIN_WORLD].adoptHandle(
handle
)) as ElementHandle<NodeFor<Selector>>;
await handle.dispose();
return result;
const {updatedSelector, queryHandler} =
getQueryHandlerAndSelector(selector);
assert(queryHandler.waitFor, 'Query handler does not support waiting');
return (await queryHandler.waitFor(
this,
updatedSelector,
options
)) as ElementHandle<NodeFor<Selector>> | null;
}

/**
Expand Down
14 changes: 2 additions & 12 deletions src/common/Frame.ts
Expand Up @@ -579,18 +579,8 @@ export class Frame {
selector: Selector,
options: WaitForSelectorOptions = {}
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const handle = await this.worlds[PUPPETEER_WORLD].waitForSelector(
selector,
options
);
if (!handle) {
return null;
}
const mainHandle = (await this.worlds[MAIN_WORLD].adoptHandle(
handle
)) as ElementHandle<NodeFor<Selector>>;
await handle.dispose();
return mainHandle;
const document = await this.worlds[MAIN_WORLD].document();
return document.waitForSelector(selector, options);
}

/**
Expand Down
48 changes: 15 additions & 33 deletions src/common/IsolatedWorld.ts
Expand Up @@ -16,16 +16,19 @@

import {Protocol} from 'devtools-protocol';
import {assert} from '../util/assert.js';
import {
createDeferredPromise,
DeferredPromise,
} from '../util/DeferredPromise.js';
import {CDPSession} from './Connection.js';
import {ElementHandle} from './ElementHandle.js';
import {TimeoutError} from './Errors.js';
import {ExecutionContext} from './ExecutionContext.js';
import {FrameManager} from './FrameManager.js';
import {Frame} from './Frame.js';
import {FrameManager} from './FrameManager.js';
import {MouseButton} from './Input.js';
import {JSHandle} from './JSHandle.js';
import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
import {getQueryHandlerAndSelector} from './QueryHandler.js';
import {TimeoutSettings} from './TimeoutSettings.js';
import {EvaluateFunc, HandleFor, NodeFor} from './types.js';
import {
Expand All @@ -37,10 +40,6 @@ import {
makePredicateString,
pageBindingInitString,
} from './util.js';
import {
createDeferredPromise,
DeferredPromise,
} from '../util/DeferredPromise.js';

// predicateQueryHandler and checkWaitForOptions are declared here so that
// TypeScript knows about them when used in the predicate function below.
Expand Down Expand Up @@ -80,10 +79,6 @@ export interface WaitForSelectorOptions {
* @defaultValue `30000` (30 seconds)
*/
timeout?: number;
/**
* @deprecated Do not use. Use the {@link ElementHandle.waitForSelector}
*/
root?: ElementHandle<Node>;
}

/**
Expand Down Expand Up @@ -294,20 +289,6 @@ export class IsolatedWorld {
return document.$$eval(selector, pageFunction, ...args);
}

async waitForSelector<Selector extends string>(
selector: Selector,
options: WaitForSelectorOptions
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const {updatedSelector, queryHandler} =
getQueryHandlerAndSelector(selector);
assert(queryHandler.waitFor, 'Query handler does not support waiting');
return (await queryHandler.waitFor(
this,
updatedSelector,
options
)) as ElementHandle<NodeFor<Selector>> | null;
}

async content(): Promise<string> {
return await this.evaluate(() => {
let retVal = '';
Expand Down Expand Up @@ -707,10 +688,11 @@ export class IsolatedWorld {

async _waitForSelectorInPage(
queryOne: Function,
root: ElementHandle<Node>,
selector: string,
options: WaitForSelectorOptions,
binding?: PageBinding
): Promise<ElementHandle<Node> | null> {
): Promise<JSHandle<unknown> | null> {
const {
visible: waitForVisible = false,
hidden: waitForHidden = false,
Expand Down Expand Up @@ -738,16 +720,10 @@ export class IsolatedWorld {
timeout,
args: [selector, waitForVisible, waitForHidden],
binding,
root: options.root,
root,
};
const waitTask = new WaitTask(waitTaskOptions);
const jsHandle = await waitTask.promise;
const elementHandle = jsHandle.asElement();
if (!elementHandle) {
await jsHandle.dispose();
return null;
}
return elementHandle;
return waitTask.promise;
}

waitForFunction(
Expand Down Expand Up @@ -798,6 +774,12 @@ export class IsolatedWorld {
});
return (await this.adoptBackendNode(nodeInfo.node.backendNodeId)) as T;
}

async transferHandle<T extends JSHandle<Node>>(handle: T): Promise<T> {
const result = this.adoptHandle(handle);
await handle.dispose();
return result;
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/common/Page.ts
Expand Up @@ -3396,7 +3396,7 @@ export class Page extends EventEmitter {
*/
async waitForSelector<Selector extends string>(
selector: Selector,
options: Exclude<WaitForSelectorOptions, 'root'> = {}
options: WaitForSelectorOptions = {}
): Promise<ElementHandle<NodeFor<Selector>> | null> {
return await this.mainFrame().waitForSelector(selector, options);
}
Expand Down
32 changes: 22 additions & 10 deletions src/common/QueryHandler.ts
Expand Up @@ -16,7 +16,11 @@

import {ariaHandler} from './AriaQueryHandler.js';
import {ElementHandle} from './ElementHandle.js';
import {IsolatedWorld, WaitForSelectorOptions} from './IsolatedWorld.js';
import {
MAIN_WORLD,
PUPPETEER_WORLD,
WaitForSelectorOptions,
} from './IsolatedWorld.js';

/**
* @public
Expand Down Expand Up @@ -58,11 +62,9 @@ export interface InternalQueryHandler {
/**
* Waits until a single node appears for a given selector and
* {@link ElementHandle}.
*
* Akin to {@link Window.prototype.querySelectorAll}.
*/
waitFor?: (
isolatedWorld: IsolatedWorld,
element: ElementHandle<Node>,
selector: string,
options: WaitForSelectorOptions
) => Promise<ElementHandle<Node> | null>;
Expand All @@ -84,12 +86,22 @@ function internalizeCustomQueryHandler(
await jsHandle.dispose();
return null;
};
internalHandler.waitFor = (
domWorld: IsolatedWorld,
selector: string,
options: WaitForSelectorOptions
) => {
return domWorld._waitForSelectorInPage(queryOne, selector, options);
internalHandler.waitFor = async (element, selector, options) => {
element = await element.frame.worlds[PUPPETEER_WORLD].adoptHandle(
element
);
const result = await element.frame.worlds[
PUPPETEER_WORLD
]._waitForSelectorInPage(queryOne, element, selector, options);
await element.dispose();
if (!result) {
return null;
}
if (!(result instanceof ElementHandle)) {
await result.dispose();
return null;
}
return element.frame.worlds[MAIN_WORLD].transferHandle(result);
};
}

Expand Down

0 comments on commit 490ea15

Please sign in to comment.