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 17, 2023
1 parent fc08a7d commit cccd2f2
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 6 deletions.
77 changes: 74 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,81 @@ 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
#### Custom Selectors

You can register a custom query handler that allows you to create custom selectors. For example, define a query handler for `getById` selectors:

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

You can now use it as following:

```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

Be careful when relying on internal APIs of libraries or frameworks. They can change at any time.

:::

Find Vue components by name by using Vue internals for querying:

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

return null;
},
});
```

Query the Vue component as following:

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

#### Web Components

Web Components create their own tag so you can query them by the tag name:

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

Suppose you register a custom selector called `lit`. You can use it like so:
Extend `HTMLElementTagNameMap` to define types for custom tags. This allows Puppeteer to infer the return type for the ElementHandle:

```ts
const node = await page.waitForSelector('::-p-lit(LitElement)');
declare global {
interface HTMLElementTagNameMap {
'my-web-component': MyWebComponent;
}
}
```
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 cccd2f2

Please sign in to comment.