Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix!: remove root from WaitForSelectorOptions (#8848)
  • Loading branch information
jrandolf committed Aug 26, 2022
1 parent 498fbf9 commit 1155c8e
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 149 deletions.
10 changes: 5 additions & 5 deletions docs/api/puppeteer.elementhandle.waitforselector.md
Expand Up @@ -14,17 +14,17 @@ Unlike [Frame.waitForSelector()](./puppeteer.frame.waitforselector.md), this met
class ElementHandle {
waitForSelector<Selector extends string>(
selector: Selector,
options?: Exclude<WaitForSelectorOptions, 'root'>
options?: WaitForSelectorOptions
): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
```

## Parameters

| Parameter | Type | Description |
| --------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| selector | Selector | The selector to query and wait for. |
| options | Exclude&lt;[WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md), 'root'&gt; | <i>(Optional)</i> Options for customizing waiting behavior. |
| Parameter | Type | Description |
| --------- | --------------------------------------------------------------- | ----------------------------------------------------------- |
| selector | Selector | The selector to query and wait for. |
| options | [WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md) | <i>(Optional)</i> Options for customizing waiting behavior. |

**Returns:**

Expand Down
10 changes: 5 additions & 5 deletions docs/api/puppeteer.page.waitforselector.md
Expand Up @@ -34,17 +34,17 @@ const puppeteer = require('puppeteer');
class Page {
waitForSelector<Selector extends string>(
selector: Selector,
options?: Exclude<WaitForSelectorOptions, 'root'>
options?: WaitForSelectorOptions
): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
```

## Parameters

| Parameter | Type | Description |
| --------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| selector | Selector | A [selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) of an element to wait for |
| options | Exclude&lt;[WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md), 'root'&gt; | <i>(Optional)</i> Optional waiting parameters |
| Parameter | Type | Description |
| --------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| selector | Selector | A [selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) of an element to wait for |
| options | [WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md) | <i>(Optional)</i> Optional waiting parameters |

**Returns:**

Expand Down
11 changes: 5 additions & 6 deletions docs/api/puppeteer.waitforselectoroptions.md
Expand Up @@ -12,9 +12,8 @@ export interface WaitForSelectorOptions

## Properties

| Property | Modifiers | Type | Description |
| --------------------------------------------------------- | --------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [hidden?](./puppeteer.waitforselectoroptions.hidden.md) | | boolean | <i>(Optional)</i> Wait for the selected element to not be found in the DOM or to be hidden, i.e. have <code>display: none</code> or <code>visibility: hidden</code> CSS properties. |
| [root?](./puppeteer.waitforselectoroptions.root.md) | | [ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt; | <i>(Optional)</i> |
| [timeout?](./puppeteer.waitforselectoroptions.timeout.md) | | number | <p><i>(Optional)</i> Maximum time to wait in milliseconds. Pass <code>0</code> to disable timeout.</p><p>The default value can be changed by using [Page.setDefaultTimeout()](./puppeteer.page.setdefaulttimeout.md)</p> |
| [visible?](./puppeteer.waitforselectoroptions.visible.md) | | boolean | <i>(Optional)</i> Wait for the selected element to be present in DOM and to be visible, i.e. to not have <code>display: none</code> or <code>visibility: hidden</code> CSS properties. |
| Property | Modifiers | Type | Description |
| --------------------------------------------------------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [hidden?](./puppeteer.waitforselectoroptions.hidden.md) | | boolean | <i>(Optional)</i> Wait for the selected element to not be found in the DOM or to be hidden, i.e. have <code>display: none</code> or <code>visibility: hidden</code> CSS properties. |
| [timeout?](./puppeteer.waitforselectoroptions.timeout.md) | | number | <p><i>(Optional)</i> Maximum time to wait in milliseconds. Pass <code>0</code> to disable timeout.</p><p>The default value can be changed by using [Page.setDefaultTimeout()](./puppeteer.page.setdefaulttimeout.md)</p> |
| [visible?](./puppeteer.waitforselectoroptions.visible.md) | | boolean | <i>(Optional)</i> Wait for the selected element to be present in DOM and to be visible, i.e. to not have <code>display: none</code> or <code>visibility: hidden</code> CSS properties. |
17 changes: 0 additions & 17 deletions docs/api/puppeteer.waitforselectoroptions.root.md

This file was deleted.

87 changes: 59 additions & 28 deletions src/common/AriaQueryHandler.ts
Expand Up @@ -18,11 +18,8 @@ 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 {Frame} from './Frame.js';
import {MAIN_WORLD, PageBinding, PUPPETEER_WORLD} from './IsolatedWorld.js';
import {InternalQueryHandler} from './QueryHandler.js';

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

const queryOne = async (
element: ElementHandle<Node>,
selector: string
): Promise<ElementHandle<Node> | null> => {
const exeCtx = element.executionContext();
const queryOneId = async (element: ElementHandle<Node>, selector: string) => {
const {name, role} = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
const res = await queryAXTree(element.client, element, name, role);
if (!res[0] || !res[0].backendDOMNodeId) {
return null;
}
return (await exeCtx._world!.adoptBackendNode(
res[0].backendDOMNodeId
return res[0].backendDOMNodeId;
};

const queryOne: InternalQueryHandler['queryOne'] = async (
element,
selector
) => {
const id = await queryOneId(element, selector);
if (!id) {
return null;
}
return (await element.frame.worlds[MAIN_WORLD].adoptBackendNode(
id
)) as ElementHandle<Node>;
};

const waitFor = async (
isolatedWorld: IsolatedWorld,
selector: string,
options: WaitForSelectorOptions
): Promise<ElementHandle<Element> | null> => {
const waitFor: InternalQueryHandler['waitFor'] = async (
elementOrFrame,
selector,
options
) => {
let frame: Frame;
let element: ElementHandle<Node> | undefined;
if (elementOrFrame instanceof Frame) {
frame = elementOrFrame;
} else {
frame = elementOrFrame.frame;
element = await frame.worlds[PUPPETEER_WORLD].adoptHandle(elementOrFrame);
}
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 id = await queryOneId(
element || (await frame.worlds[PUPPETEER_WORLD].document()),
selector
);
if (!id) {
return null;
}
return (await frame.worlds[PUPPETEER_WORLD].adoptBackendNode(
id
)) as ElementHandle<Node>;
},
};
return (await isolatedWorld._waitForSelectorInPage(
const result = await frame.worlds[PUPPETEER_WORLD]._waitForSelectorInPage(
(_: Element, selector: string) => {
return (
globalThis as unknown as {
ariaQuerySelector(selector: string): void;
ariaQuerySelector(selector: string): Node | null;
}
).ariaQuerySelector(selector);
},
element,
selector,
options,
binding
)) as ElementHandle<Element> | null;
);
if (element) {
await element.dispose();
}
if (!result) {
return null;
}
if (!(result instanceof ElementHandle)) {
await result.dispose();
return null;
}
return result.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
20 changes: 9 additions & 11 deletions src/common/Frame.ts
@@ -1,4 +1,5 @@
import {Protocol} from 'devtools-protocol';
import {assert} from '../util/assert.js';
import {isErrorLike} from '../util/ErrorLike.js';
import {CDPSession} from './Connection.js';
import {ElementHandle} from './ElementHandle.js';
Expand All @@ -15,6 +16,7 @@ import {
} from './IsolatedWorld.js';
import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
import {Page} from './Page.js';
import {getQueryHandlerAndSelector} from './QueryHandler.js';
import {EvaluateFunc, HandleFor, NodeFor} from './types.js';

/**
Expand Down Expand Up @@ -579,18 +581,14 @@ export class Frame {
selector: Selector,
options: WaitForSelectorOptions = {}
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const handle = await this.worlds[PUPPETEER_WORLD].waitForSelector(
selector,
const {updatedSelector, queryHandler} =
getQueryHandlerAndSelector(selector);
assert(queryHandler.waitFor, 'Query handler does not support waiting');
return (await queryHandler.waitFor(
this,
updatedSelector,
options
);
if (!handle) {
return null;
}
const mainHandle = (await this.worlds[MAIN_WORLD].adoptHandle(
handle
)) as ElementHandle<NodeFor<Selector>>;
await handle.dispose();
return mainHandle;
)) as ElementHandle<NodeFor<Selector>> | null;
}

/**
Expand Down

0 comments on commit 1155c8e

Please sign in to comment.