Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: remove root from WaitForSelectorOptions #8848

Merged
merged 1 commit into from Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be still a breaking change? It looked like root was previously excluded from the API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically since root was exposed in Frame

| 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