diff --git a/docs/api/index.md b/docs/api/index.md index 03f904ace7cdd..af448142dae7f 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -61,63 +61,63 @@ sidebar_label: API ## Interfaces -| Interface | Description | -| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [BoundingBox](./puppeteer.boundingbox.md) | | -| [BoxModel](./puppeteer.boxmodel.md) | | -| [BrowserConnectOptions](./puppeteer.browserconnectoptions.md) | Generic browser options that can be passed when launching any browser or when connecting to an existing browser instance. | -| [BrowserContextOptions](./puppeteer.browsercontextoptions.md) | BrowserContext options. | -| [BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md) | | -| [BrowserFetcherRevisionInfo](./puppeteer.browserfetcherrevisioninfo.md) | | -| [BrowserLaunchArgumentOptions](./puppeteer.browserlaunchargumentoptions.md) | Launcher options that only apply to Chrome. | -| [CDPSessionOnMessageObject](./puppeteer.cdpsessiononmessageobject.md) | | -| [ClickOptions](./puppeteer.clickoptions.md) | | -| [CommonEventEmitter](./puppeteer.commoneventemitter.md) | | -| [ConnectionCallback](./puppeteer.connectioncallback.md) | | -| [ConnectionTransport](./puppeteer.connectiontransport.md) | | -| [ConnectOptions](./puppeteer.connectoptions.md) | | -| [ConsoleMessageLocation](./puppeteer.consolemessagelocation.md) | | -| [ContinueRequestOverrides](./puppeteer.continuerequestoverrides.md) | | -| [CoverageEntry](./puppeteer.coverageentry.md) | The CoverageEntry class represents one entry of the coverage report. | -| [Credentials](./puppeteer.credentials.md) | | -| [CSSCoverageOptions](./puppeteer.csscoverageoptions.md) | Set of configurable options for CSS coverage. | -| [CustomQueryHandler](./puppeteer.customqueryhandler.md) | Contains two functions queryOne and queryAll that can be [registered](./puppeteer.registercustomqueryhandler.md) as alternative querying strategies. The functions queryOne and queryAll are executed in the page context. queryOne should take an Element and a selector string as argument and return a single Element or null if no element is found. queryAll takes the same arguments but should instead return a NodeListOf<Element> or Array<Element> with all the elements that match the given query selector. | -| [Device](./puppeteer.device.md) | | -| [FrameAddScriptTagOptions](./puppeteer.frameaddscripttagoptions.md) | | -| [FrameAddStyleTagOptions](./puppeteer.frameaddstyletagoptions.md) | | -| [FrameWaitForFunctionOptions](./puppeteer.framewaitforfunctionoptions.md) | | -| [GeolocationOptions](./puppeteer.geolocationoptions.md) | | -| [InterceptResolutionState](./puppeteer.interceptresolutionstate.md) | | -| [InternalNetworkConditions](./puppeteer.internalnetworkconditions.md) | | -| [JSCoverageEntry](./puppeteer.jscoverageentry.md) | The CoverageEntry class for JavaScript | -| [JSCoverageOptions](./puppeteer.jscoverageoptions.md) | Set of configurable options for JS coverage. | -| [LaunchOptions](./puppeteer.launchoptions.md) | Generic launch options that can be passed when launching any browser. | -| [MediaFeature](./puppeteer.mediafeature.md) | | -| [Metrics](./puppeteer.metrics.md) | | -| [MouseOptions](./puppeteer.mouseoptions.md) | | -| [MouseWheelOptions](./puppeteer.mousewheeloptions.md) | | -| [NetworkConditions](./puppeteer.networkconditions.md) | | -| [Offset](./puppeteer.offset.md) | | -| [PageEventObject](./puppeteer.pageeventobject.md) |

Denotes the objects received by callback functions for page events.

See [PageEmittedEvents](./puppeteer.pageemittedevents.md) for more detail on the events and when they are emitted.

| -| [PDFMargin](./puppeteer.pdfmargin.md) | | -| [PDFOptions](./puppeteer.pdfoptions.md) | Valid options to configure PDF generation via [Page.pdf()](./puppeteer.page.pdf.md). | -| [Point](./puppeteer.point.md) | | -| [PressOptions](./puppeteer.pressoptions.md) | | -| [ProductLauncher](./puppeteer.productlauncher.md) | Describes a launcher - a class that is able to create and launch a browser instance. | -| [PuppeteerErrors](./puppeteer.puppeteererrors.md) | | -| [PuppeteerLaunchOptions](./puppeteer.puppeteerlaunchoptions.md) | | -| [RemoteAddress](./puppeteer.remoteaddress.md) | | -| [ResponseForRequest](./puppeteer.responseforrequest.md) | Required response data to fulfill a request with. | -| [ScreenshotClip](./puppeteer.screenshotclip.md) | | -| [ScreenshotOptions](./puppeteer.screenshotoptions.md) | | -| [SerializedAXNode](./puppeteer.serializedaxnode.md) | Represents a Node and the properties of it that are relevant to Accessibility. | -| [SnapshotOptions](./puppeteer.snapshotoptions.md) | | -| [TracingOptions](./puppeteer.tracingoptions.md) | | -| [Viewport](./puppeteer.viewport.md) | Sets the viewport of the page. | -| [WaitForOptions](./puppeteer.waitforoptions.md) | | -| [WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md) | | -| [WaitForTargetOptions](./puppeteer.waitfortargetoptions.md) | | -| [WaitTimeoutOptions](./puppeteer.waittimeoutoptions.md) | | +| Interface | Description | +| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [BoundingBox](./puppeteer.boundingbox.md) | | +| [BoxModel](./puppeteer.boxmodel.md) | | +| [BrowserConnectOptions](./puppeteer.browserconnectoptions.md) | Generic browser options that can be passed when launching any browser or when connecting to an existing browser instance. | +| [BrowserContextOptions](./puppeteer.browsercontextoptions.md) | BrowserContext options. | +| [BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md) | | +| [BrowserFetcherRevisionInfo](./puppeteer.browserfetcherrevisioninfo.md) | | +| [BrowserLaunchArgumentOptions](./puppeteer.browserlaunchargumentoptions.md) | Launcher options that only apply to Chrome. | +| [CDPSessionOnMessageObject](./puppeteer.cdpsessiononmessageobject.md) | | +| [ClickOptions](./puppeteer.clickoptions.md) | | +| [CommonEventEmitter](./puppeteer.commoneventemitter.md) | | +| [ConnectionCallback](./puppeteer.connectioncallback.md) | | +| [ConnectionTransport](./puppeteer.connectiontransport.md) | | +| [ConnectOptions](./puppeteer.connectoptions.md) | | +| [ConsoleMessageLocation](./puppeteer.consolemessagelocation.md) | | +| [ContinueRequestOverrides](./puppeteer.continuerequestoverrides.md) | | +| [CoverageEntry](./puppeteer.coverageentry.md) | The CoverageEntry class represents one entry of the coverage report. | +| [Credentials](./puppeteer.credentials.md) | | +| [CSSCoverageOptions](./puppeteer.csscoverageoptions.md) | Set of configurable options for CSS coverage. | +| [CustomQueryHandler](./puppeteer.customqueryhandler.md) | | +| [Device](./puppeteer.device.md) | | +| [FrameAddScriptTagOptions](./puppeteer.frameaddscripttagoptions.md) | | +| [FrameAddStyleTagOptions](./puppeteer.frameaddstyletagoptions.md) | | +| [FrameWaitForFunctionOptions](./puppeteer.framewaitforfunctionoptions.md) | | +| [GeolocationOptions](./puppeteer.geolocationoptions.md) | | +| [InterceptResolutionState](./puppeteer.interceptresolutionstate.md) | | +| [InternalNetworkConditions](./puppeteer.internalnetworkconditions.md) | | +| [JSCoverageEntry](./puppeteer.jscoverageentry.md) | The CoverageEntry class for JavaScript | +| [JSCoverageOptions](./puppeteer.jscoverageoptions.md) | Set of configurable options for JS coverage. | +| [LaunchOptions](./puppeteer.launchoptions.md) | Generic launch options that can be passed when launching any browser. | +| [MediaFeature](./puppeteer.mediafeature.md) | | +| [Metrics](./puppeteer.metrics.md) | | +| [MouseOptions](./puppeteer.mouseoptions.md) | | +| [MouseWheelOptions](./puppeteer.mousewheeloptions.md) | | +| [NetworkConditions](./puppeteer.networkconditions.md) | | +| [Offset](./puppeteer.offset.md) | | +| [PageEventObject](./puppeteer.pageeventobject.md) |

Denotes the objects received by callback functions for page events.

See [PageEmittedEvents](./puppeteer.pageemittedevents.md) for more detail on the events and when they are emitted.

| +| [PDFMargin](./puppeteer.pdfmargin.md) | | +| [PDFOptions](./puppeteer.pdfoptions.md) | Valid options to configure PDF generation via [Page.pdf()](./puppeteer.page.pdf.md). | +| [Point](./puppeteer.point.md) | | +| [PressOptions](./puppeteer.pressoptions.md) | | +| [ProductLauncher](./puppeteer.productlauncher.md) | Describes a launcher - a class that is able to create and launch a browser instance. | +| [PuppeteerErrors](./puppeteer.puppeteererrors.md) | | +| [PuppeteerLaunchOptions](./puppeteer.puppeteerlaunchoptions.md) | | +| [RemoteAddress](./puppeteer.remoteaddress.md) | | +| [ResponseForRequest](./puppeteer.responseforrequest.md) | Required response data to fulfill a request with. | +| [ScreenshotClip](./puppeteer.screenshotclip.md) | | +| [ScreenshotOptions](./puppeteer.screenshotoptions.md) | | +| [SerializedAXNode](./puppeteer.serializedaxnode.md) | Represents a Node and the properties of it that are relevant to Accessibility. | +| [SnapshotOptions](./puppeteer.snapshotoptions.md) | | +| [TracingOptions](./puppeteer.tracingoptions.md) | | +| [Viewport](./puppeteer.viewport.md) | Sets the viewport of the page. | +| [WaitForOptions](./puppeteer.waitforoptions.md) | | +| [WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md) | | +| [WaitForTargetOptions](./puppeteer.waitfortargetoptions.md) | | +| [WaitTimeoutOptions](./puppeteer.waittimeoutoptions.md) | | ## Variables diff --git a/docs/api/puppeteer.customqueryhandler.md b/docs/api/puppeteer.customqueryhandler.md index e2420101f7714..67e1123a24acd 100644 --- a/docs/api/puppeteer.customqueryhandler.md +++ b/docs/api/puppeteer.customqueryhandler.md @@ -4,8 +4,6 @@ sidebar_label: CustomQueryHandler # CustomQueryHandler interface -Contains two functions `queryOne` and `queryAll` that can be [registered](./puppeteer.registercustomqueryhandler.md) as alternative querying strategies. The functions `queryOne` and `queryAll` are executed in the page context. `queryOne` should take an `Element` and a selector string as argument and return a single `Element` or `null` if no element is found. `queryAll` takes the same arguments but should instead return a `NodeListOf` or `Array` with all the elements that match the given query selector. - **Signature:** ```typescript @@ -14,7 +12,7 @@ export interface CustomQueryHandler ## Properties -| Property | Modifiers | Type | Description | -| ------------------------------------------------------- | --------- | ---------------------------------------------------- | ----------------- | -| [queryAll?](./puppeteer.customqueryhandler.queryall.md) | | (element: Node, selector: string) => Node\[\] | (Optional) | -| [queryOne?](./puppeteer.customqueryhandler.queryone.md) | | (element: Node, selector: string) => Node \| null | (Optional) | +| Property | Modifiers | Type | Description | +| ------------------------------------------------------- | --------- | ------------------------------------------------- | ----------------- | +| [queryAll?](./puppeteer.customqueryhandler.queryall.md) | | (node: Node, selector: string) => Node\[\] | (Optional) | +| [queryOne?](./puppeteer.customqueryhandler.queryone.md) | | (node: Node, selector: string) => Node \| null | (Optional) | diff --git a/docs/api/puppeteer.customqueryhandler.queryall.md b/docs/api/puppeteer.customqueryhandler.queryall.md index f6f88e56359e8..d366bb7f62664 100644 --- a/docs/api/puppeteer.customqueryhandler.queryall.md +++ b/docs/api/puppeteer.customqueryhandler.queryall.md @@ -8,6 +8,6 @@ sidebar_label: CustomQueryHandler.queryAll ```typescript interface CustomQueryHandler { - queryAll?: (element: Node, selector: string) => Node[]; + queryAll?: (node: Node, selector: string) => Node[]; } ``` diff --git a/docs/api/puppeteer.customqueryhandler.queryone.md b/docs/api/puppeteer.customqueryhandler.queryone.md index b1cdbf4411f5c..bccfb2f5b3953 100644 --- a/docs/api/puppeteer.customqueryhandler.queryone.md +++ b/docs/api/puppeteer.customqueryhandler.queryone.md @@ -8,6 +8,6 @@ sidebar_label: CustomQueryHandler.queryOne ```typescript interface CustomQueryHandler { - queryOne?: (element: Node, selector: string) => Node | null; + queryOne?: (node: Node, selector: string) => Node | null; } ``` diff --git a/docs/api/puppeteer.elementhandle._x.md b/docs/api/puppeteer.elementhandle._x.md index d1756a75f0019..b5ec2fd47cc47 100644 --- a/docs/api/puppeteer.elementhandle._x.md +++ b/docs/api/puppeteer.elementhandle._x.md @@ -4,7 +4,11 @@ sidebar_label: ElementHandle.$x # ElementHandle.$x() method -The method evaluates the XPath expression relative to the elementHandle. If there are no such elements, the method will resolve to an empty array. +> Warning: This API is now obsolete. +> +> Use [ElementHandle.$$()](./puppeteer.elementhandle.__.md) with the `xpath` prefix. +> +> The method evaluates the XPath expression relative to the elementHandle. If there are no such elements, the method will resolve to an empty array. **Signature:** diff --git a/docs/api/puppeteer.elementhandle.md b/docs/api/puppeteer.elementhandle.md index e5a303a30ebb4..e741b62bea754 100644 --- a/docs/api/puppeteer.elementhandle.md +++ b/docs/api/puppeteer.elementhandle.md @@ -41,54 +41,32 @@ The constructor for this class is marked as internal. Third-party code should no ## Methods -| Method | Modifiers | Description | -| -------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [$(selector)](./puppeteer.elementhandle._.md) | | Runs element.querySelector within the page. | -| [$$(selector)](./puppeteer.elementhandle.__.md) | | Runs element.querySelectorAll within the page. | -| [$$eval(selector, pageFunction, args)](./puppeteer.elementhandle.__eval.md) | |

This method runs document.querySelectorAll within the element and passes it as the first argument to pageFunction. If there's no element matching selector, the method throws an error.

If pageFunction returns a Promise, then frame.$$eval would wait for the promise to resolve and return its value.

| -| [$eval(selector, pageFunction, args)](./puppeteer.elementhandle._eval.md) | |

This method runs document.querySelector within the element and passes it as the first argument to pageFunction. If there's no element matching selector, the method throws an error.

If pageFunction returns a Promise, then frame.$eval would wait for the promise to resolve and return its value.

| -| [$x(expression)](./puppeteer.elementhandle._x.md) | | The method evaluates the XPath expression relative to the elementHandle. If there are no such elements, the method will resolve to an empty array. | -| [asElement()](./puppeteer.elementhandle.aselement.md) | | | -| [boundingBox()](./puppeteer.elementhandle.boundingbox.md) | | This method returns the bounding box of the element (relative to the main frame), or null if the element is not visible. | -| [boxModel()](./puppeteer.elementhandle.boxmodel.md) | | This method returns boxes of the element, or null if the element is not visible. | -| [click(this, options)](./puppeteer.elementhandle.click.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.mouse.md) to click in the center of the element. If the element is detached from DOM, the method throws an error. | -| [clickablePoint(offset)](./puppeteer.elementhandle.clickablepoint.md) | | Returns the middle point within an element unless a specific offset is provided. | -| [contentFrame()](./puppeteer.elementhandle.contentframe.md) | | Resolves to the content frame for element handles referencing iframe nodes, or null otherwise | -| [drag(this, target)](./puppeteer.elementhandle.drag.md) | | This method creates and captures a dragevent from the element. | -| [dragAndDrop(this, target, options)](./puppeteer.elementhandle.draganddrop.md) | | This method triggers a dragenter, dragover, and drop on the element. | -| [dragEnter(this, data)](./puppeteer.elementhandle.dragenter.md) | | This method creates a dragenter event on the element. | -| [dragOver(this, data)](./puppeteer.elementhandle.dragover.md) | | This method creates a dragover event on the element. | -| [drop(this, data)](./puppeteer.elementhandle.drop.md) | | This method triggers a drop on the element. | -| [focus()](./puppeteer.elementhandle.focus.md) | | Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element. | -| [hover(this)](./puppeteer.elementhandle.hover.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.mouse.md) to hover over the center of the element. If the element is detached from DOM, the method throws an error. | -| [isIntersectingViewport(this, options)](./puppeteer.elementhandle.isintersectingviewport.md) | | Resolves to true if the element is visible in the current viewport. | -| [press(key, options)](./puppeteer.elementhandle.press.md) | | Focuses the element, and then uses [Keyboard.down()](./puppeteer.keyboard.down.md) and [Keyboard.up()](./puppeteer.keyboard.up.md). | -| [screenshot(this, options)](./puppeteer.elementhandle.screenshot.md) | | This method scrolls element into view if needed, and then uses [Page.screenshot()](./puppeteer.page.screenshot.md) to take a screenshot of the element. If the element is detached from DOM, the method throws an error. | -| [select(values)](./puppeteer.elementhandle.select.md) | | Triggers a change and input event once all the provided options have been selected. If there's no <select> element matching selector, the method throws an error. | -| [tap(this)](./puppeteer.elementhandle.tap.md) | | This method scrolls element into view if needed, and then uses [Touchscreen.tap()](./puppeteer.touchscreen.tap.md) to tap in the center of the element. If the element is detached from DOM, the method throws an error. | -| [type(text, options)](./puppeteer.elementhandle.type.md) | |

Focuses the element, and then sends a keydown, keypress/input, and keyup event for each character in the text.

To press a special key, like Control or ArrowDown, use [ElementHandle.press()](./puppeteer.elementhandle.press.md).

| -| [uploadFile(this, filePaths)](./puppeteer.elementhandle.uploadfile.md) | | This method expects elementHandle to point to an [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). | -| [waitForSelector(selector, options)](./puppeteer.elementhandle.waitforselector.md) | |

Wait for the selector to appear within the element. If at the moment of calling the method the selector already exists, the method will return immediately. If the selector doesn't appear after the timeout milliseconds of waiting, the function will throw.

This method does not work across navigations or if the element is detached from DOM.

| -| [waitForXPath(xpath, options)](./puppeteer.elementhandle.waitforxpath.md) | |

Wait for the xpath within the element. If at the moment of calling the method the xpath already exists, the method will return immediately. If the xpath doesn't appear after the timeout milliseconds of waiting, the function will throw.

If xpath starts with // instead of .//, the dot will be appended automatically.

This method works across navigation

| - -```ts -const puppeteer = require('puppeteer'); -(async () => { - const browser = await puppeteer.launch(); - const page = await browser.newPage(); - let currentURL; - page - .waitForXPath('//img') - .then(() => console.log('First URL with image: ' + currentURL)); - for (currentURL of [ - 'https://example.com', - 'https://google.com', - 'https://bbc.com', - ]) { - await page.goto(currentURL); - } - await browser.close(); -})(); -``` - -| +| Method | Modifiers | Description | +| -------------------------------------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [$(selector)](./puppeteer.elementhandle._.md) | | Runs element.querySelector within the page. | +| [$$(selector)](./puppeteer.elementhandle.__.md) | | Runs element.querySelectorAll within the page. | +| [$$eval(selector, pageFunction, args)](./puppeteer.elementhandle.__eval.md) | |

This method runs document.querySelectorAll within the element and passes it as the first argument to pageFunction. If there's no element matching selector, the method throws an error.

If pageFunction returns a Promise, then frame.$$eval would wait for the promise to resolve and return its value.

| +| [$eval(selector, pageFunction, args)](./puppeteer.elementhandle._eval.md) | |

This method runs document.querySelector within the element and passes it as the first argument to pageFunction. If there's no element matching selector, the method throws an error.

If pageFunction returns a Promise, then frame.$eval would wait for the promise to resolve and return its value.

| +| [$x(expression)](./puppeteer.elementhandle._x.md) | | | +| [asElement()](./puppeteer.elementhandle.aselement.md) | | | +| [boundingBox()](./puppeteer.elementhandle.boundingbox.md) | | This method returns the bounding box of the element (relative to the main frame), or null if the element is not visible. | +| [boxModel()](./puppeteer.elementhandle.boxmodel.md) | | This method returns boxes of the element, or null if the element is not visible. | +| [click(this, options)](./puppeteer.elementhandle.click.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.mouse.md) to click in the center of the element. If the element is detached from DOM, the method throws an error. | +| [clickablePoint(offset)](./puppeteer.elementhandle.clickablepoint.md) | | Returns the middle point within an element unless a specific offset is provided. | +| [contentFrame()](./puppeteer.elementhandle.contentframe.md) | | Resolves to the content frame for element handles referencing iframe nodes, or null otherwise | +| [drag(this, target)](./puppeteer.elementhandle.drag.md) | | This method creates and captures a dragevent from the element. | +| [dragAndDrop(this, target, options)](./puppeteer.elementhandle.draganddrop.md) | | This method triggers a dragenter, dragover, and drop on the element. | +| [dragEnter(this, data)](./puppeteer.elementhandle.dragenter.md) | | This method creates a dragenter event on the element. | +| [dragOver(this, data)](./puppeteer.elementhandle.dragover.md) | | This method creates a dragover event on the element. | +| [drop(this, data)](./puppeteer.elementhandle.drop.md) | | This method triggers a drop on the element. | +| [focus()](./puppeteer.elementhandle.focus.md) | | Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element. | +| [hover(this)](./puppeteer.elementhandle.hover.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.mouse.md) to hover over the center of the element. If the element is detached from DOM, the method throws an error. | +| [isIntersectingViewport(this, options)](./puppeteer.elementhandle.isintersectingviewport.md) | | Resolves to true if the element is visible in the current viewport. | +| [press(key, options)](./puppeteer.elementhandle.press.md) | | Focuses the element, and then uses [Keyboard.down()](./puppeteer.keyboard.down.md) and [Keyboard.up()](./puppeteer.keyboard.up.md). | +| [screenshot(this, options)](./puppeteer.elementhandle.screenshot.md) | | This method scrolls element into view if needed, and then uses [Page.screenshot()](./puppeteer.page.screenshot.md) to take a screenshot of the element. If the element is detached from DOM, the method throws an error. | +| [select(values)](./puppeteer.elementhandle.select.md) | | Triggers a change and input event once all the provided options have been selected. If there's no <select> element matching selector, the method throws an error. | +| [tap(this)](./puppeteer.elementhandle.tap.md) | | This method scrolls element into view if needed, and then uses [Touchscreen.tap()](./puppeteer.touchscreen.tap.md) to tap in the center of the element. If the element is detached from DOM, the method throws an error. | +| [type(text, options)](./puppeteer.elementhandle.type.md) | |

Focuses the element, and then sends a keydown, keypress/input, and keyup event for each character in the text.

To press a special key, like Control or ArrowDown, use [ElementHandle.press()](./puppeteer.elementhandle.press.md).

| +| [uploadFile(this, filePaths)](./puppeteer.elementhandle.uploadfile.md) | | This method expects elementHandle to point to an [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). | +| [waitForSelector(selector, options)](./puppeteer.elementhandle.waitforselector.md) | |

Wait for the selector to appear within the element. If at the moment of calling the method the selector already exists, the method will return immediately. If the selector doesn't appear after the timeout milliseconds of waiting, the function will throw.

This method does not work across navigations or if the element is detached from DOM.

| +| [waitForXPath(xpath, options)](./puppeteer.elementhandle.waitforxpath.md) | | | diff --git a/docs/api/puppeteer.elementhandle.waitforxpath.md b/docs/api/puppeteer.elementhandle.waitforxpath.md index 631eefcb14bf6..1a626e6c92fbe 100644 --- a/docs/api/puppeteer.elementhandle.waitforxpath.md +++ b/docs/api/puppeteer.elementhandle.waitforxpath.md @@ -4,31 +4,35 @@ sidebar_label: ElementHandle.waitForXPath # ElementHandle.waitForXPath() method -Wait for the `xpath` within the element. If at the moment of calling the method the `xpath` already exists, the method will return immediately. If the `xpath` doesn't appear after the `timeout` milliseconds of waiting, the function will throw. - -If `xpath` starts with `//` instead of `.//`, the dot will be appended automatically. - -This method works across navigation - -```ts -const puppeteer = require('puppeteer'); -(async () => { - const browser = await puppeteer.launch(); - const page = await browser.newPage(); - let currentURL; - page - .waitForXPath('//img') - .then(() => console.log('First URL with image: ' + currentURL)); - for (currentURL of [ - 'https://example.com', - 'https://google.com', - 'https://bbc.com', - ]) { - await page.goto(currentURL); - } - await browser.close(); -})(); -``` +> Warning: This API is now obsolete. +> +> Use [ElementHandle.waitForSelector()](./puppeteer.elementhandle.waitforselector.md) with the `xpath` prefix. +> +> Wait for the `xpath` within the element. If at the moment of calling the method the `xpath` already exists, the method will return immediately. If the `xpath` doesn't appear after the `timeout` milliseconds of waiting, the function will throw. +> +> If `xpath` starts with `//` instead of `.//`, the dot will be appended automatically. +> +> This method works across navigation +> +> ```ts +> const puppeteer = require('puppeteer'); +> (async () => { +> const browser = await puppeteer.launch(); +> const page = await browser.newPage(); +> let currentURL; +> page +> .waitForXPath('//img') +> .then(() => console.log('First URL with image: ' + currentURL)); +> for (currentURL of [ +> 'https://example.com', +> 'https://google.com', +> 'https://bbc.com', +> ]) { +> await page.goto(currentURL); +> } +> await browser.close(); +> })(); +> ``` **Signature:** diff --git a/docs/api/puppeteer.frame.waitforxpath.md b/docs/api/puppeteer.frame.waitforxpath.md index b03f1e2c63a03..c791a19ccaaef 100644 --- a/docs/api/puppeteer.frame.waitforxpath.md +++ b/docs/api/puppeteer.frame.waitforxpath.md @@ -4,6 +4,14 @@ sidebar_label: Frame.waitForXPath # Frame.waitForXPath() method +> Warning: This API is now obsolete. +> +> Use [Frame.waitForSelector()](./puppeteer.frame.waitforselector.md) with the `xpath` prefix. +> +> Wait for the `xpath` to appear in page. If at the moment of calling the method the `xpath` already exists, the method will return immediately. If the xpath doesn't appear after the `timeout` milliseconds of waiting, the function will throw. +> +> For a code example, see the example for [Frame.waitForSelector()](./puppeteer.frame.waitforselector.md). That function behaves identically other than taking a CSS selector rather than an XPath. + **Signature:** ```typescript @@ -25,9 +33,3 @@ class Frame { **Returns:** Promise<[ElementHandle](./puppeteer.elementhandle.md)<Node> \| null> - -## Remarks - -Wait for the `xpath` to appear in page. If at the moment of calling the method the `xpath` already exists, the method will return immediately. If the xpath doesn't appear after the `timeout` milliseconds of waiting, the function will throw. - -For a code example, see the example for [Frame.waitForSelector()](./puppeteer.frame.waitforselector.md). That function behaves identically other than taking a CSS selector rather than an XPath. diff --git a/src/common/AriaQueryHandler.ts b/src/common/AriaQueryHandler.ts index 466e158951264..a2f82ccc89c65 100644 --- a/src/common/AriaQueryHandler.ts +++ b/src/common/AriaQueryHandler.ts @@ -114,7 +114,7 @@ const waitFor = async ( return (await domWorld._waitForSelectorInPage( (_: Element, selector: string) => { return ( - globalThis as any as unknown as { + globalThis as unknown as { ariaQuerySelector(selector: string): void; } ).ariaQuerySelector(selector); diff --git a/src/common/DOMWorld.ts b/src/common/DOMWorld.ts index a6d7d05141082..1db47d1fd5296 100644 --- a/src/common/DOMWorld.ts +++ b/src/common/DOMWorld.ts @@ -717,52 +717,6 @@ export class DOMWorld { return elementHandle; } - async waitForXPath( - xpath: string, - options: WaitForSelectorOptions - ): Promise | null> { - const { - visible: waitForVisible = false, - hidden: waitForHidden = false, - timeout = this.#timeoutSettings.timeout(), - } = options; - const polling = waitForVisible || waitForHidden ? 'raf' : 'mutation'; - const title = `XPath \`${xpath}\`${waitForHidden ? ' to be hidden' : ''}`; - function predicate( - root: Element | Document, - xpath: string, - waitForVisible: boolean, - waitForHidden: boolean - ): Node | null | boolean { - const node = document.evaluate( - xpath, - root, - null, - XPathResult.FIRST_ORDERED_NODE_TYPE, - null - ).singleNodeValue; - return checkWaitForOptions(node, waitForVisible, waitForHidden); - } - const waitTaskOptions: WaitTaskOptions = { - domWorld: this, - predicateBody: makePredicateString(predicate), - predicateAcceptsContextElement: true, - title, - polling, - timeout, - args: [xpath, waitForVisible, waitForHidden], - root: options.root, - }; - const waitTask = new WaitTask(waitTaskOptions); - const jsHandle = await waitTask.promise; - const elementHandle = jsHandle.asElement(); - if (!elementHandle) { - await jsHandle.dispose(); - return null; - } - return elementHandle; - } - waitForFunction( pageFunction: Function | string, options: {polling?: string | number; timeout?: number} = {}, diff --git a/src/common/ElementHandle.ts b/src/common/ElementHandle.ts index dbd7d8ccf9217..30afec75d1db0 100644 --- a/src/common/ElementHandle.ts +++ b/src/common/ElementHandle.ts @@ -140,6 +140,8 @@ export class ElementHandle< } /** + * @deprecated Use {@link ElementHandle.waitForSelector} with the `xpath` prefix. + * * Wait for the `xpath` within the element. If at the moment of calling the * method the `xpath` already exists, the method will return immediately. If * the `xpath` doesn't appear after the `timeout` milliseconds of waiting, the @@ -197,27 +199,7 @@ export class ElementHandle< timeout?: number; } = {} ): Promise | null> { - const frame = this._context.frame(); - assert(frame); - const secondaryContext = await frame._secondaryWorld.executionContext(); - const adoptedRoot = await secondaryContext._adoptElementHandle(this); - xpath = xpath.startsWith('//') ? '.' + xpath : xpath; - if (!xpath.startsWith('.//')) { - await adoptedRoot.dispose(); - throw new Error('Unsupported xpath expression: ' + xpath); - } - const handle = await frame._secondaryWorld.waitForXPath(xpath, { - ...options, - root: adoptedRoot, - }); - await adoptedRoot.dispose(); - if (!handle) { - return null; - } - const mainExecutionContext = await frame._mainWorld.executionContext(); - const result = await mainExecutionContext._adoptElementHandle(handle); - await handle.dispose(); - return result; + return this.waitForSelector(`xpath/${xpath}`, options); } override asElement(): ElementHandle | null { @@ -964,36 +946,14 @@ export class ElementHandle< } /** + * @deprecated Use {@link ElementHandle.$$} with the `xpath` prefix. + * * The method evaluates the XPath expression relative to the elementHandle. * If there are no such elements, the method will resolve to an empty array. * @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate} */ async $x(expression: string): Promise>> { - const arrayHandle = await this.evaluateHandle((element, expression) => { - const doc = element.ownerDocument || document; - const iterator = doc.evaluate( - expression, - element, - null, - XPathResult.ORDERED_NODE_ITERATOR_TYPE - ); - const array = []; - let item; - while ((item = iterator.iterateNext())) { - array.push(item); - } - return array; - }, expression); - const properties = await arrayHandle.getProperties(); - await arrayHandle.dispose(); - const result = []; - for (const property of properties.values()) { - const elementHandle = property.asElement(); - if (elementHandle) { - result.push(elementHandle); - } - } - return result; + return this.$$(`xpath/${expression}`); } /** diff --git a/src/common/FrameManager.ts b/src/common/FrameManager.ts index 25f8067f2da05..ec23b7616361a 100644 --- a/src/common/FrameManager.ts +++ b/src/common/FrameManager.ts @@ -1374,7 +1374,8 @@ export class Frame { } /** - * @remarks + * @deprecated Use {@link Frame.waitForSelector} with the `xpath` prefix. + * * Wait for the `xpath` to appear in page. If at the moment of calling the * method the `xpath` already exists, the method will return immediately. If * the xpath doesn't appear after the `timeout` milliseconds of waiting, the @@ -1392,14 +1393,7 @@ export class Frame { xpath: string, options: WaitForSelectorOptions = {} ): Promise | null> { - const handle = await this._secondaryWorld.waitForXPath(xpath, options); - if (!handle) { - return null; - } - const mainExecutionContext = await this._mainWorld.executionContext(); - const result = await mainExecutionContext._adoptElementHandle(handle); - await handle.dispose(); - return result; + return this.waitForSelector(`xpath/${xpath}`, options); } /** diff --git a/src/common/QueryHandler.ts b/src/common/QueryHandler.ts index f9a140f8f79db..240f50dbab326 100644 --- a/src/common/QueryHandler.ts +++ b/src/common/QueryHandler.ts @@ -19,47 +19,66 @@ import {DOMWorld, WaitForSelectorOptions} from './DOMWorld.js'; import {ElementHandle} from './ElementHandle.js'; import {JSHandle} from './JSHandle.js'; +/** + * @public + */ +export interface CustomQueryHandler { + /** + * @returns A {@link Node} matching the given {@link selector} from {@link node}. + */ + queryOne?: (node: Node, selector: string) => Node | null; + /** + * @returns Some {@link Node}s matching the given {@link selector} from {@link node}. + */ + queryAll?: (node: Node, selector: string) => Node[]; +} + /** * @internal */ export interface InternalQueryHandler { + /** + * Queries for a single node given a selector and {@link ElementHandle}. + * + * Akin to {@link Window.prototype.querySelector}. + */ queryOne?: ( element: ElementHandle, selector: string ) => Promise | null>; + /** + * Queries for multiple nodes given a selector and {@link ElementHandle}. + * + * Akin to {@link Window.prototype.querySelectorAll}. + */ queryAll?: ( element: ElementHandle, selector: string ) => Promise>>; - + /** + * Queries for multiple nodes given a selector and {@link ElementHandle}. + * Unlike {@link queryAll}, this returns a handle to a node array. + * + * Akin to {@link Window.prototype.querySelectorAll}. + */ + queryAllArray?: ( + element: ElementHandle, + selector: string + ) => Promise>; + /** + * Waits until a single node appears for a given selector and + * {@link ElementHandle}. + * + * Akin to {@link Window.prototype.querySelectorAll}. + */ waitFor?: ( domWorld: DOMWorld, selector: string, options: WaitForSelectorOptions ) => Promise | null>; - queryAllArray?: ( - element: ElementHandle, - selector: string - ) => Promise>; } -/** - * Contains two functions `queryOne` and `queryAll` that can - * be {@link registerCustomQueryHandler | registered} - * as alternative querying strategies. The functions `queryOne` and `queryAll` - * are executed in the page context. `queryOne` should take an `Element` and a - * selector string as argument and return a single `Element` or `null` if no - * element is found. `queryAll` takes the same arguments but should instead - * return a `NodeListOf` or `Array` with all the elements - * that match the given query selector. - * @public - */ -export interface CustomQueryHandler { - queryOne?: (element: Node, selector: string) => Node | null; - queryAll?: (element: Node, selector: string) => Node[]; -} - -function createInternalQueryHandler( +function internalizeCustomQueryHandler( handler: CustomQueryHandler ): InternalQueryHandler { const internalHandler: InternalQueryHandler = {}; @@ -114,7 +133,7 @@ function createInternalQueryHandler( return internalHandler; } -const defaultHandler = createInternalQueryHandler({ +const defaultHandler = internalizeCustomQueryHandler({ queryOne: (element, selector) => { if (!('querySelector' in element)) { throw new Error( @@ -141,7 +160,7 @@ const defaultHandler = createInternalQueryHandler({ }, }); -const pierceHandler = createInternalQueryHandler({ +const pierceHandler = internalizeCustomQueryHandler({ queryOne: (element, selector) => { let found: Node | null = null; const search = (root: Node) => { @@ -191,11 +210,60 @@ const pierceHandler = createInternalQueryHandler({ }, }); -const builtInHandlers = new Map([ - ['aria', ariaHandler], - ['pierce', pierceHandler], +const xpathHandler = internalizeCustomQueryHandler({ + queryOne: (element, selector) => { + const doc = element.ownerDocument || document; + const result = doc.evaluate( + selector, + element, + null, + XPathResult.FIRST_ORDERED_NODE_TYPE + ); + return result.singleNodeValue; + }, + + queryAll: (element, selector) => { + const doc = element.ownerDocument || document; + const iterator = doc.evaluate( + selector, + element, + null, + XPathResult.ORDERED_NODE_ITERATOR_TYPE + ); + const array: Node[] = []; + let item; + while ((item = iterator.iterateNext())) { + array.push(item); + } + return array; + }, +}); + +const transformXPathSelector = (selector: string): string => { + if (selector.startsWith('//')) { + selector = `.${selector}`; + } + return selector; +}; + +const INTERNAL_QUERY_HANDLERS = new Map< + string, + [ + handler: InternalQueryHandler, + transformSelector?: (selector: string) => string + ] +>([ + ['aria', [ariaHandler]], + ['pierce', [pierceHandler]], + ['xpath', [xpathHandler, transformXPathSelector]], ]); -const queryHandlers = new Map(builtInHandlers); +const QUERY_HANDLERS = new Map< + string, + [ + handler: InternalQueryHandler, + transformSelector?: (selector: string) => string + ] +>(); /** * Registers a {@link CustomQueryHandler | custom query handler}. @@ -222,7 +290,10 @@ export function registerCustomQueryHandler( name: string, handler: CustomQueryHandler ): void { - if (queryHandlers.get(name)) { + if (INTERNAL_QUERY_HANDLERS.has(name)) { + throw new Error(`A query handler named "${name}" already exists`); + } + if (QUERY_HANDLERS.has(name)) { throw new Error(`A custom query handler named "${name}" already exists`); } @@ -231,9 +302,7 @@ export function registerCustomQueryHandler( throw new Error(`Custom query handler names may only contain [a-zA-Z]`); } - const internalHandler = createInternalQueryHandler(handler); - - queryHandlers.set(name, internalHandler); + QUERY_HANDLERS.set(name, [internalizeCustomQueryHandler(handler)]); } /** @@ -242,9 +311,7 @@ export function registerCustomQueryHandler( * @public */ export function unregisterCustomQueryHandler(name: string): void { - if (queryHandlers.has(name) && !builtInHandlers.has(name)) { - queryHandlers.delete(name); - } + QUERY_HANDLERS.delete(name); } /** @@ -253,9 +320,7 @@ export function unregisterCustomQueryHandler(name: string): void { * @public */ export function customQueryHandlerNames(): string[] { - return [...queryHandlers.keys()].filter(name => { - return !builtInHandlers.has(name); - }); + return [...QUERY_HANDLERS.keys()]; } /** @@ -264,9 +329,11 @@ export function customQueryHandlerNames(): string[] { * @public */ export function clearCustomQueryHandlers(): void { - customQueryHandlerNames().forEach(unregisterCustomQueryHandler); + QUERY_HANDLERS.clear(); } +const CUSTOM_QUERY_SEPARATORS = ['=', '/']; + /** * @internal */ @@ -274,23 +341,19 @@ export function getQueryHandlerAndSelector(selector: string): { updatedSelector: string; queryHandler: InternalQueryHandler; } { - const hasCustomQueryHandler = /^[a-zA-Z]+\//.test(selector); - if (!hasCustomQueryHandler) { - return {updatedSelector: selector, queryHandler: defaultHandler}; - } - - const index = selector.indexOf('/'); - const name = selector.slice(0, index); - const updatedSelector = selector.slice(index + 1); - const queryHandler = queryHandlers.get(name); - if (!queryHandler) { - throw new Error( - `Query set to use "${name}", but no query handler of that name was found` - ); + for (const handlerMap of [QUERY_HANDLERS, INTERNAL_QUERY_HANDLERS]) { + for (const [name, [queryHandler, transformSelector]] of handlerMap) { + for (const separator of CUSTOM_QUERY_SEPARATORS) { + const prefix = `${name}${separator}`; + if (selector.startsWith(prefix)) { + selector = selector.slice(prefix.length); + if (transformSelector) { + selector = transformSelector(selector); + } + return {updatedSelector: selector, queryHandler}; + } + } + } } - - return { - updatedSelector, - queryHandler, - }; + return {updatedSelector: selector, queryHandler: defaultHandler}; } diff --git a/test/src/elementhandle.spec.ts b/test/src/elementhandle.spec.ts index 3a11c2b152463..b066c8c8dbe95 100644 --- a/test/src/elementhandle.spec.ts +++ b/test/src/elementhandle.spec.ts @@ -319,12 +319,12 @@ describe('ElementHandle specs', function () { ` ); - const el2 = (await page.waitForSelector( + const el1 = (await page.waitForSelector( '#el1' )) as ElementHandle; for (const path of ['//div', './/div']) { - const e = (await el2.waitForXPath( + const e = (await el1.waitForXPath( path )) as ElementHandle; expect( @@ -423,10 +423,8 @@ describe('ElementHandle specs', function () { await page.$('getById/foo'); throw new Error('Custom query handler name not set - throw expected'); } catch (error) { - expect(error).toStrictEqual( - new Error( - 'Query set to use "getById", but no query handler of that name was found' - ) + expect(error).not.toStrictEqual( + new Error('Custom query handler name not set - throw expected') ); } const handlerNamesAfterUnregistering = diff --git a/test/src/queryhandler.spec.ts b/test/src/queryhandler.spec.ts new file mode 100644 index 0000000000000..30e5d69254d52 --- /dev/null +++ b/test/src/queryhandler.spec.ts @@ -0,0 +1,160 @@ +/** + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import expect from 'expect'; +import {ElementHandle} from '../../lib/cjs/puppeteer/common/ElementHandle.js'; +import { + getTestState, + setupTestBrowserHooks, + setupTestPageAndContextHooks, +} from './mocha-utils.js'; + +describe('Query handler tests', function () { + setupTestBrowserHooks(); + setupTestPageAndContextHooks(); + + describe('Pierce selectors', function () { + beforeEach(async () => { + const {page} = getTestState(); + await page.setContent( + `` + ); + }); + it('should find first element in shadow', async () => { + const {page} = getTestState(); + const div = (await page.$('pierce/.foo')) as ElementHandle; + const text = await div.evaluate(element => { + return element.textContent; + }); + expect(text).toBe('Hello'); + }); + it('should find all elements in shadow', async () => { + const {page} = getTestState(); + const divs = (await page.$$('pierce/.foo')) as Array< + ElementHandle + >; + const text = await Promise.all( + divs.map(div => { + return div.evaluate(element => { + return element.textContent; + }); + }) + ); + expect(text.join(' ')).toBe('Hello World'); + }); + it('should find first child element', async () => { + const {page} = getTestState(); + const parentElement = (await page.$('html > div'))!; + const childElement = (await parentElement.$( + 'pierce/div' + )) as ElementHandle; + const text = await childElement.evaluate(element => { + return element.textContent; + }); + expect(text).toBe('Hello'); + }); + it('should find all child elements', async () => { + const {page} = getTestState(); + const parentElement = (await page.$('html > div'))!; + const childElements = (await parentElement.$$('pierce/div')) as Array< + ElementHandle + >; + const text = await Promise.all( + childElements.map(div => { + return div.evaluate(element => { + return element.textContent; + }); + }) + ); + expect(text.join(' ')).toBe('Hello World'); + }); + }); + + describe('XPath selectors', function () { + describe('in Page', function () { + it('should query existing element', async () => { + const {page} = getTestState(); + + await page.setContent('
test
'); + + expect(await page.$('xpath/html/body/section')).toBeTruthy(); + expect((await page.$$('xpath/html/body/section')).length).toBe(1); + }); + it('should return empty array for non-existing element', async () => { + const {page} = getTestState(); + + expect( + await page.$('xpath/html/body/non-existing-element') + ).toBeFalsy(); + expect( + (await page.$$('xpath/html/body/non-existing-element')).length + ).toBe(0); + }); + it('should return first element', async () => { + const {page} = getTestState(); + + await page.setContent('
a
'); + + const element = await page.$('xpath/html/body/div'); + expect( + await element?.evaluate(e => { + return e.textContent === 'a'; + }) + ).toBeTruthy(); + }); + it('should return multiple elements', async () => { + const {page} = getTestState(); + + await page.setContent('
'); + + const elements = await page.$$('xpath/html/body/div'); + expect(elements.length).toBe(2); + }); + }); + describe('in ElementHandles', function () { + it('should query existing element', async () => { + const {page} = getTestState(); + + await page.setContent('
a
'); + + const elementHandle = (await page.$('div'))!; + expect(await elementHandle.$(`xpath/span`)).toBeTruthy(); + expect((await elementHandle.$$(`xpath/span`)).length).toBe(1); + }); + + it('should return null for non-existing element', async () => { + const {page} = getTestState(); + + await page.setContent('
a
'); + + const elementHandle = (await page.$('div'))!; + expect(await elementHandle.$(`xpath/span`)).toBeFalsy(); + expect((await elementHandle.$$(`xpath/span`)).length).toBe(0); + }); + }); + }); +}); diff --git a/test/src/queryselector.spec.ts b/test/src/queryselector.spec.ts index 24f81da586747..7eeab8e44e7f6 100644 --- a/test/src/queryselector.spec.ts +++ b/test/src/queryselector.spec.ts @@ -14,13 +14,12 @@ * limitations under the License. */ import expect from 'expect'; +import {CustomQueryHandler} from '../../lib/cjs/puppeteer/common/QueryHandler.js'; import { getTestState, setupTestBrowserHooks, setupTestPageAndContextHooks, } from './mocha-utils.js'; -import {CustomQueryHandler} from '../../lib/cjs/puppeteer/common/QueryHandler.js'; -import {ElementHandle} from '../../lib/cjs/puppeteer/common/ElementHandle.js'; describe('querySelector', function () { setupTestBrowserHooks(); @@ -79,75 +78,6 @@ describe('querySelector', function () { }); }); - describe('pierceHandler', function () { - beforeEach(async () => { - const {page} = getTestState(); - await page.setContent( - `` - ); - }); - it('should find first element in shadow', async () => { - const {page} = getTestState(); - const div = (await page.$('pierce/.foo')) as ElementHandle; - const text = await div.evaluate(element => { - return element.textContent; - }); - expect(text).toBe('Hello'); - }); - it('should find all elements in shadow', async () => { - const {page} = getTestState(); - const divs = (await page.$$('pierce/.foo')) as Array< - ElementHandle - >; - const text = await Promise.all( - divs.map(div => { - return div.evaluate(element => { - return element.textContent; - }); - }) - ); - expect(text.join(' ')).toBe('Hello World'); - }); - it('should find first child element', async () => { - const {page} = getTestState(); - const parentElement = (await page.$('html > div'))!; - const childElement = (await parentElement.$( - 'pierce/div' - )) as ElementHandle; - const text = await childElement.evaluate(element => { - return element.textContent; - }); - expect(text).toBe('Hello'); - }); - it('should find all child elements', async () => { - const {page} = getTestState(); - const parentElement = (await page.$('html > div'))!; - const childElements = (await parentElement.$$('pierce/div')) as Array< - ElementHandle - >; - const text = await Promise.all( - childElements.map(div => { - return div.evaluate(element => { - return element.textContent; - }); - }) - ); - expect(text.join(' ')).toBe('Hello World'); - }); - }); - // The tests for $$eval are repeated later in this file in the test group 'QueryAll'. // This is done to also test a query handler where QueryAll returns an Element[] // as opposed to NodeListOf. @@ -256,7 +186,7 @@ describe('querySelector', function () { }); }); - describe('Path.$x', function () { + describe('Page.$x', function () { it('should query existing element', async () => { const {page} = getTestState(); diff --git a/test/src/waittask.spec.ts b/test/src/waittask.spec.ts index 81b8809741c96..6eccf9ca89775 100644 --- a/test/src/waittask.spec.ts +++ b/test/src/waittask.spec.ts @@ -735,7 +735,7 @@ describe('waittask specs', function () { }); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error?.message).toContain( - 'waiting for XPath `//div` failed: timeout' + 'waiting for selector `.//div` failed: timeout 10ms exceeded' ); }); itFailsFirefox('should run in specified frame', async () => {