mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat: add waitForXPath to ElementHandle (#8329)
This commit is contained in:
parent
1e82d98027
commit
7eaadafe19
39
docs/api.md
39
docs/api.md
@ -342,6 +342,7 @@
|
||||
* [elementHandle.type(text[, options])](#elementhandletypetext-options)
|
||||
* [elementHandle.uploadFile(...filePaths)](#elementhandleuploadfilefilepaths)
|
||||
* [elementHandle.waitForSelector(selector[, options])](#elementhandlewaitforselectorselector-options)
|
||||
* [elementHandle.waitForXPath(xpath[, options])](#elementhandlewaitforxpathxpath-options)
|
||||
- [class: HTTPRequest](#class-httprequest)
|
||||
* [httpRequest.abort([errorCode], [priority])](#httprequestaborterrorcode-priority)
|
||||
* [httpRequest.abortErrorReason()](#httprequestaborterrorreason)
|
||||
@ -4902,6 +4903,44 @@ Wait for an element matching `selector` to appear within the `elementHandle`’s
|
||||
|
||||
This method does not work across navigations or if the element is detached from DOM.
|
||||
|
||||
#### elementHandle.waitForXPath(xpath[, options])
|
||||
|
||||
- `xpath` <[string]> A [xpath] of an element to wait for
|
||||
- `options` <[Object]> Optional waiting parameters
|
||||
- `visible` <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
|
||||
- `hidden` <[boolean]> wait for element to not be found in the DOM or to be hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
|
||||
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by xpath string is added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is not found in DOM.
|
||||
|
||||
Wait for the `xpath` to appear 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 navigations:
|
||||
|
||||
```js
|
||||
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();
|
||||
})();
|
||||
```
|
||||
|
||||
### class: HTTPRequest
|
||||
|
||||
Whenever the page sends a request, such as for a network resource, the following events are emitted by Puppeteer's page:
|
||||
|
@ -416,6 +416,84 @@ export class ElementHandle<
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* ```js
|
||||
* 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();
|
||||
* })();
|
||||
* ```
|
||||
* @param xpath - A
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/XPath | xpath} of an
|
||||
* element to wait for
|
||||
* @param options - Optional waiting parameters
|
||||
* @returns Promise which resolves when element specified by xpath string is
|
||||
* added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is
|
||||
* not found in DOM.
|
||||
* @remarks
|
||||
* The optional Argument `options` have properties:
|
||||
*
|
||||
* - `visible`: A boolean to wait for element to be present in DOM and to be
|
||||
* visible, i.e. to not have `display: none` or `visibility: hidden` CSS
|
||||
* properties. Defaults to `false`.
|
||||
*
|
||||
* - `hidden`: A boolean wait for element to not be found in the DOM or to be
|
||||
* hidden, i.e. have `display: none` or `visibility: hidden` CSS properties.
|
||||
* Defaults to `false`.
|
||||
*
|
||||
* - `timeout`: A number which is maximum time to wait for in milliseconds.
|
||||
* Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default
|
||||
* value can be changed by using the {@link Page.setDefaultTimeout} method.
|
||||
*/
|
||||
async waitForXPath(
|
||||
xpath: string,
|
||||
options: {
|
||||
visible?: boolean;
|
||||
hidden?: boolean;
|
||||
timeout?: number;
|
||||
} = {}
|
||||
): Promise<ElementHandle | null> {
|
||||
const frame = this._context.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;
|
||||
}
|
||||
|
||||
asElement(): ElementHandle<ElementType> | null {
|
||||
return this;
|
||||
}
|
||||
|
@ -280,6 +280,34 @@ describe('ElementHandle specs', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Element.waitForXPath', () => {
|
||||
it('should wait correctly with waitForXPath on an element', async () => {
|
||||
const { page } = getTestState();
|
||||
// Set the page content after the waitFor has been started.
|
||||
await page.setContent(
|
||||
`<div id=el1>
|
||||
el1
|
||||
<div id=el2>
|
||||
el2
|
||||
</div>
|
||||
</div>
|
||||
<div id=el3>
|
||||
el3
|
||||
</div>`
|
||||
);
|
||||
|
||||
const el2 = await page.waitForSelector('#el1');
|
||||
|
||||
expect(
|
||||
await (await el2.waitForXPath('//div')).evaluate((el) => el.id)
|
||||
).toStrictEqual('el2');
|
||||
|
||||
expect(
|
||||
await (await el2.waitForXPath('.//div')).evaluate((el) => el.id)
|
||||
).toStrictEqual('el2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ElementHandle.hover', function () {
|
||||
it('should work', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
Loading…
Reference in New Issue
Block a user