Skip to content

Commit

Permalink
docs: update custom query handler
Browse files Browse the repository at this point in the history
  • Loading branch information
Lightning00Blade committed Aug 16, 2023
1 parent e12b558 commit c0588f2
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 6 deletions.
96 changes: 93 additions & 3 deletions docs/guides/query-selectors.md → docs/guides/query-selectors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,100 @@ const node = await page.waitForSelector(

Puppeteer provides users the ability to add their own query selectors to Puppeteer using [Puppeteer.registerCustomQueryHandler](../api/puppeteer.registercustomqueryhandler.md). This is useful for creating custom selectors based on framework objects or other vendor-specific objects.

#### Example
#### Basic Custom Selectors

An example of registration of a custom selector called `getById` selector:

```ts
Puppeteer.registerCustomQueryHandler('getById', {
queryOne: (elementOrDocument, selector) => {
if (
// elementOrDocument may be a Node
elementOrDocument instanceof Element ||
elementOrDocument instanceof Document
) {
return elementOrDocument.querySelector(`[id="${CSS.escape(selector)}"]`);
}
return null;
},
// Note: for demonstation perpose only `id` should be page unique
queryAll: (elementOrDocument, selector) => {
if (
// elementOrDocument may be a Node
elementOrDocument instanceof Element ||
elementOrDocument instanceof Document
) {
return elementOrDocument.querySelectorAll(
`[id="${CSS.escape(selector)}"]`
);
}
return [];
},
});
```

You can now use it in these ways:

```ts
const node = await page.waitForSelector('::-p-getById(elementId)');
// OR used in conjunction with other selectors
const moreSpecificNode = await page.waitForSelector(
'.side-bar ::-p-getById(elementId)'
);
```

#### Custom framework components selector

:::caution

Internal library/framework methods can change and/or break at anytime use with caution.

:::

Framework example using `vue` and it's internals to find by component name:

```ts
Puppeteer.registerCustomQueryHandler('vue', {
queryOne: (element, name) => {
const walker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = walker.currentNode;
if (
// @ts-ignore
currentNode.__vnode?.ctx?.type?.name.toLowerCase() ===
name.toLocaleLowerCase()
) {
return currentNode;
}
} while (walker.nextNode());

return null;
},
});
```

Suppose you register a custom selector called `lit`. You can use it like so:
Then we can use as following:

```ts
const node = await page.waitForSelector('::-p-lit(LitElement)');
const element = await page.$('::-p-vue(MyComponent)');
```

#### Web Components

Web Components create their own tag so you can just query them by default using:

```ts
const element = await page.$('my-web-component');
```

To add a some typehiting to your tests you can add the following typing:

```ts
declare global {
interface HTMLElementTagNameMap {
'my-web-component': MyWebComponent;
}
}
```

This will let Puppeteer infer the type from the query above.
3 changes: 0 additions & 3 deletions packages/puppeteer-core/src/common/CustomQueryHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,6 @@ export class CustomQueryHandlerRegistry {
* @internal
*/
register(name: string, handler: CustomQueryHandler): void {
if (this.#handlers.has(name)) {
throw new Error(`Cannot register over existing handler: ${name}`);
}
assert(
!this.#handlers.has(name),
`Cannot register over existing handler: ${name}`
Expand Down

0 comments on commit c0588f2

Please sign in to comment.