mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
[api] Teach page.evaluate to accept element handles as parameters (#725)
This patch: - teaches `page.evaluate` to accept ElementHandles as parameters - removes `ElementHandle.evaluate` method since it's not needed any more References #382
This commit is contained in:
parent
69e707a2b7
commit
9292a56eaf
49
docs/api.md
49
docs/api.md
@ -116,7 +116,6 @@
|
|||||||
* [class: ElementHandle](#class-elementhandle)
|
* [class: ElementHandle](#class-elementhandle)
|
||||||
+ [elementHandle.click([options])](#elementhandleclickoptions)
|
+ [elementHandle.click([options])](#elementhandleclickoptions)
|
||||||
+ [elementHandle.dispose()](#elementhandledispose)
|
+ [elementHandle.dispose()](#elementhandledispose)
|
||||||
+ [elementHandle.evaluate(pageFunction, ...args)](#elementhandleevaluatepagefunction-args)
|
|
||||||
+ [elementHandle.hover()](#elementhandlehover)
|
+ [elementHandle.hover()](#elementhandlehover)
|
||||||
+ [elementHandle.tap()](#elementhandletap)
|
+ [elementHandle.tap()](#elementhandletap)
|
||||||
+ [elementHandle.uploadFile(...filePaths)](#elementhandleuploadfilefilepaths)
|
+ [elementHandle.uploadFile(...filePaths)](#elementhandleuploadfilefilepaths)
|
||||||
@ -333,7 +332,7 @@ Shortcut for [page.mainFrame().$$(selector)](#frameselector-1).
|
|||||||
#### page.$eval(selector, pageFunction[, ...args])
|
#### page.$eval(selector, pageFunction[, ...args])
|
||||||
- `selector` <[string]> A [selector] to query page for
|
- `selector` <[string]> A [selector] to query page for
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
- `pageFunction` <[function]> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[ElementHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
This method runs `document.querySelector` within the page and passes it as the first argument to `pageFunction`. If there's no element matching `selector`, the method throws an error.
|
This method runs `document.querySelector` within the page and passes it as the first argument to `pageFunction`. If there's no element matching `selector`, the method throws an error.
|
||||||
@ -450,22 +449,16 @@ List of all available devices is available in the source code: [DeviceDescriptor
|
|||||||
|
|
||||||
#### page.evaluate(pageFunction, ...args)
|
#### page.evaluate(pageFunction, ...args)
|
||||||
- `pageFunction` <[function]|[string]> Function to be evaluated in the page context
|
- `pageFunction` <[function]|[string]> Function to be evaluated in the page context
|
||||||
- `...args` <...[Serializable]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[ElementHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
If the function, passed to the `page.evaluate`, returns a [Promise], then `page.evaluate` would wait for the promise to resolve and return it's value.
|
If the function, passed to the `page.evaluate`, returns a [Promise], then `page.evaluate` would wait for the promise to resolve and return it's value.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const puppeteer = require('puppeteer');
|
|
||||||
|
|
||||||
puppeteer.launch().then(async browser => {
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const result = await page.evaluate(() => {
|
const result = await page.evaluate(() => {
|
||||||
return Promise.resolve(8 * 7);
|
return Promise.resolve(8 * 7);
|
||||||
});
|
});
|
||||||
console.log(result); // prints "56"
|
console.log(result); // prints "56"
|
||||||
browser.close();
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
|
|
||||||
A string can also be passed in instead of a function.
|
A string can also be passed in instead of a function.
|
||||||
@ -474,6 +467,13 @@ A string can also be passed in instead of a function.
|
|||||||
console.log(await page.evaluate('1 + 2')); // prints "3"
|
console.log(await page.evaluate('1 + 2')); // prints "3"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[ElementHandle] instances could be passed as arguments to the `page.evaluate`:
|
||||||
|
```js
|
||||||
|
const bodyHandle = await page.$('body');
|
||||||
|
const html = await page.evaluate(body => body.innerHTML, bodyHandle);
|
||||||
|
await bodyHandle.dispose();
|
||||||
|
```
|
||||||
|
|
||||||
Shortcut for [page.mainFrame().evaluate(pageFunction, ...args)](#frameevaluatepagefunction-args).
|
Shortcut for [page.mainFrame().evaluate(pageFunction, ...args)](#frameevaluatepagefunction-args).
|
||||||
|
|
||||||
#### page.evaluateOnNewDocument(pageFunction, ...args)
|
#### page.evaluateOnNewDocument(pageFunction, ...args)
|
||||||
@ -1113,7 +1113,7 @@ The method runs `document.querySelectorAll` within the frame. If no elements mat
|
|||||||
#### frame.$eval(selector, pageFunction[, ...args])
|
#### frame.$eval(selector, pageFunction[, ...args])
|
||||||
- `selector` <[string]> A [selector] to query frame for
|
- `selector` <[string]> A [selector] to query frame for
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
- `pageFunction` <[function]> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[ElementHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
This method runs `document.querySelector` within the frame and passes it as the first argument to `pageFunction`. If there's no element matching `selector`, the method throws an error.
|
This method runs `document.querySelector` within the frame and passes it as the first argument to `pageFunction`. If there's no element matching `selector`, the method throws an error.
|
||||||
@ -1138,28 +1138,29 @@ Adds a `<script>` tag to the frame with the desired url. Alternatively, JavaScri
|
|||||||
|
|
||||||
#### frame.evaluate(pageFunction, ...args)
|
#### frame.evaluate(pageFunction, ...args)
|
||||||
- `pageFunction` <[function]|[string]> Function to be evaluated in browser context
|
- `pageFunction` <[function]|[string]> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[ElementHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to function return value
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to function return value
|
||||||
|
|
||||||
If the function, passed to the `page.evaluate`, returns a [Promise], then `page.evaluate` would wait for the promise to resolve and return it's value.
|
If the function, passed to the `frame.evaluate`, returns a [Promise], then `frame.evaluate` would wait for the promise to resolve and return it's value.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const puppeteer = require('puppeteer');
|
const result = await frame.evaluate(() => {
|
||||||
|
|
||||||
puppeteer.launch().then(async browser => {
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const result = await page.mainFrame().evaluate(() => {
|
|
||||||
return Promise.resolve(8 * 7);
|
return Promise.resolve(8 * 7);
|
||||||
});
|
});
|
||||||
console.log(result); // prints "56"
|
console.log(result); // prints "56"
|
||||||
browser.close();
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
|
|
||||||
A string can also be passed in instead of a function.
|
A string can also be passed in instead of a function.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
console.log(await page.mainFrame().evaluate('1 + 2')); // prints "3"
|
console.log(await frame.evaluate('1 + 2')); // prints "3"
|
||||||
|
```
|
||||||
|
|
||||||
|
[ElementHandle] instances could be passed as arguments to the `frame.evaluate`:
|
||||||
|
```js
|
||||||
|
const bodyHandle = await frame.$('body');
|
||||||
|
const html = await frame.evaluate(body => body.innerHTML, bodyHandle);
|
||||||
|
await bodyHandle.dispose();
|
||||||
```
|
```
|
||||||
|
|
||||||
#### frame.injectFile(filePath)
|
#### frame.injectFile(filePath)
|
||||||
@ -1286,14 +1287,6 @@ If the element is detached from DOM, the method throws an error.
|
|||||||
|
|
||||||
The `elementHandle.dispose` method stops referencing the element handle.
|
The `elementHandle.dispose` method stops referencing the element handle.
|
||||||
|
|
||||||
#### elementHandle.evaluate(pageFunction, ...args)
|
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
|
||||||
- `...args` <...[Serializable]> Arguments to pass to `pageFunction`
|
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to function return value
|
|
||||||
|
|
||||||
If the function, passed to the `elementHandle.evaluate`, returns a [Promise], then `elementHandle.evaluate` would wait for the promise to resolve and return it's value.
|
|
||||||
The element will be passed as the first argument to `pageFunction`, followed by any `args`.
|
|
||||||
|
|
||||||
#### elementHandle.hover()
|
#### elementHandle.hover()
|
||||||
- returns: <[Promise]> Promise which resolves when the element is successfully hovered.
|
- returns: <[Promise]> Promise which resolves when the element is successfully hovered.
|
||||||
|
|
||||||
|
@ -18,12 +18,14 @@ const {helper} = require('./helper');
|
|||||||
|
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
/**
|
/**
|
||||||
|
* @param {!Frame} frame
|
||||||
* @param {!Connection} client
|
* @param {!Connection} client
|
||||||
* @param {!Object} remoteObject
|
* @param {!Object} remoteObject
|
||||||
* @param {!Mouse} mouse
|
* @param {!Mouse} mouse
|
||||||
* @param {!Touchscreen} touchscreen;
|
* @param {!Touchscreen} touchscreen;
|
||||||
*/
|
*/
|
||||||
constructor(client, remoteObject, mouse, touchscreen) {
|
constructor(frame, client, remoteObject, mouse, touchscreen) {
|
||||||
|
this._frame = frame;
|
||||||
this._client = client;
|
this._client = client;
|
||||||
this._remoteObject = remoteObject;
|
this._remoteObject = remoteObject;
|
||||||
this._mouse = mouse;
|
this._mouse = mouse;
|
||||||
@ -31,6 +33,13 @@ class ElementHandle {
|
|||||||
this._disposed = false;
|
this._disposed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {?string}
|
||||||
|
*/
|
||||||
|
_remoteObjectId() {
|
||||||
|
return this._disposed ? null : this._remoteObject.objectId;
|
||||||
|
}
|
||||||
|
|
||||||
async dispose() {
|
async dispose() {
|
||||||
if (this._disposed)
|
if (this._disposed)
|
||||||
return;
|
return;
|
||||||
@ -38,30 +47,11 @@ class ElementHandle {
|
|||||||
await helper.releaseObject(this._client, this._remoteObject);
|
await helper.releaseObject(this._client, this._remoteObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {function()} pageFunction
|
|
||||||
* @param {!Array<*>} args
|
|
||||||
* @return {!Promise<(!Object|undefined)>}
|
|
||||||
*/
|
|
||||||
async evaluate(pageFunction, ...args) {
|
|
||||||
console.assert(!this._disposed, 'ElementHandle is disposed!');
|
|
||||||
console.assert(typeof pageFunction === 'function', 'First argument to ElementHandle.evaluate must be a function!');
|
|
||||||
|
|
||||||
const stringifiedArgs = ['this'];
|
|
||||||
stringifiedArgs.push(...args.map(x => JSON.stringify(x)));
|
|
||||||
const functionDeclaration = `function() { return (${pageFunction})(${stringifiedArgs.join(',')}) }`;
|
|
||||||
const objectId = this._remoteObject.objectId;
|
|
||||||
const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.callFunctionOn', { objectId, functionDeclaration, returnByValue: false, awaitPromise: true});
|
|
||||||
if (exceptionDetails)
|
|
||||||
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
|
|
||||||
return await helper.serializeRemoteObject(this._client, remoteObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {!Promise<{x: number, y: number}>}
|
* @return {!Promise<{x: number, y: number}>}
|
||||||
*/
|
*/
|
||||||
async _visibleCenter() {
|
async _visibleCenter() {
|
||||||
const center = await this.evaluate(element => {
|
const center = await this._frame.evaluate(element => {
|
||||||
if (!element.ownerDocument.contains(element))
|
if (!element.ownerDocument.contains(element))
|
||||||
return null;
|
return null;
|
||||||
element.scrollIntoViewIfNeeded();
|
element.scrollIntoViewIfNeeded();
|
||||||
@ -70,7 +60,7 @@ class ElementHandle {
|
|||||||
x: (Math.max(rect.left, 0) + Math.min(rect.right, window.innerWidth)) / 2,
|
x: (Math.max(rect.left, 0) + Math.min(rect.right, window.innerWidth)) / 2,
|
||||||
y: (Math.max(rect.top, 0) + Math.min(rect.bottom, window.innerHeight)) / 2
|
y: (Math.max(rect.top, 0) + Math.min(rect.bottom, window.innerHeight)) / 2
|
||||||
};
|
};
|
||||||
});
|
}, this);
|
||||||
if (!center)
|
if (!center)
|
||||||
throw new Error('No node found for selector: ' + selector);
|
throw new Error('No node found for selector: ' + selector);
|
||||||
return center;
|
return center;
|
||||||
|
@ -194,7 +194,7 @@ class Frame {
|
|||||||
async $(selector) {
|
async $(selector) {
|
||||||
const remoteObject = await this._rawEvaluate(selector => document.querySelector(selector), selector);
|
const remoteObject = await this._rawEvaluate(selector => document.querySelector(selector), selector);
|
||||||
if (remoteObject.subtype === 'node')
|
if (remoteObject.subtype === 'node')
|
||||||
return new ElementHandle(this._client, remoteObject, this._mouse, this._touchscreen);
|
return new ElementHandle(this, this._client, remoteObject, this._mouse, this._touchscreen);
|
||||||
await helper.releaseObject(this._client, remoteObject);
|
await helper.releaseObject(this._client, remoteObject);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -209,7 +209,8 @@ class Frame {
|
|||||||
const elementHandle = await this.$(selector);
|
const elementHandle = await this.$(selector);
|
||||||
if (!elementHandle)
|
if (!elementHandle)
|
||||||
throw new Error(`Error: failed to find element matching selector "${selector}"`);
|
throw new Error(`Error: failed to find element matching selector "${selector}"`);
|
||||||
const result = await elementHandle.evaluate(pageFunction, ...args);
|
args = [elementHandle].concat(args);
|
||||||
|
const result = await this.evaluate(pageFunction, ...args);
|
||||||
await elementHandle.dispose();
|
await elementHandle.dispose();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -229,7 +230,7 @@ class Frame {
|
|||||||
const releasePromises = [helper.releaseObject(this._client, remoteObject)];
|
const releasePromises = [helper.releaseObject(this._client, remoteObject)];
|
||||||
for (const property of properties) {
|
for (const property of properties) {
|
||||||
if (property.enumerable && property.value.subtype === 'node')
|
if (property.enumerable && property.value.subtype === 'node')
|
||||||
result.push(new ElementHandle(this._client, property.value, this._mouse, this._touchscreen));
|
result.push(new ElementHandle(this, this._client, property.value, this._mouse, this._touchscreen));
|
||||||
else
|
else
|
||||||
releasePromises.push(helper.releaseObject(this._client, property.value));
|
releasePromises.push(helper.releaseObject(this._client, property.value));
|
||||||
}
|
}
|
||||||
@ -243,14 +244,52 @@ class Frame {
|
|||||||
* @return {!Promise<(!Object|undefined)>}
|
* @return {!Promise<(!Object|undefined)>}
|
||||||
*/
|
*/
|
||||||
async _rawEvaluate(pageFunction, ...args) {
|
async _rawEvaluate(pageFunction, ...args) {
|
||||||
const expression = helper.evaluationString(pageFunction, ...args);
|
if (helper.isString(pageFunction)) {
|
||||||
const contextId = this._defaultContextId;
|
const contextId = this._defaultContextId;
|
||||||
|
const expression = pageFunction;
|
||||||
const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.evaluate', { expression, contextId, returnByValue: false, awaitPromise: true});
|
const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.evaluate', { expression, contextId, returnByValue: false, awaitPromise: true});
|
||||||
if (exceptionDetails)
|
if (exceptionDetails)
|
||||||
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
|
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
|
||||||
return remoteObject;
|
return remoteObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.callFunctionOn', {
|
||||||
|
functionDeclaration: pageFunction.toString(),
|
||||||
|
executionContextId: this._defaultContextId,
|
||||||
|
arguments: args.map(convertArgument.bind(this)),
|
||||||
|
returnByValue: false,
|
||||||
|
awaitPromise: true
|
||||||
|
});
|
||||||
|
if (exceptionDetails)
|
||||||
|
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
|
||||||
|
return remoteObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {*} arg
|
||||||
|
* @return {*}
|
||||||
|
* @this {Frame}
|
||||||
|
*/
|
||||||
|
function convertArgument(arg) {
|
||||||
|
if (Object.is(arg, -0))
|
||||||
|
return { unserializableValue: '-0' };
|
||||||
|
if (Object.is(arg, Infinity))
|
||||||
|
return { unserializableValue: 'Infinity' };
|
||||||
|
if (Object.is(arg, -Infinity))
|
||||||
|
return { unserializableValue: '-Infinity' };
|
||||||
|
if (Object.is(arg, NaN))
|
||||||
|
return { unserializableValue: 'NaN' };
|
||||||
|
if (arg instanceof ElementHandle) {
|
||||||
|
if (arg._frame !== this)
|
||||||
|
throw new Error('ElementHandles passed as arguments should belong to the frame that does evaluation');
|
||||||
|
const objectId = arg._remoteObjectId();
|
||||||
|
if (!objectId)
|
||||||
|
throw new Error('ElementHandle is disposed!');
|
||||||
|
return { objectId };
|
||||||
|
}
|
||||||
|
return { value: arg };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
|
@ -689,7 +689,7 @@ class Page extends EventEmitter {
|
|||||||
async focus(selector) {
|
async focus(selector) {
|
||||||
const handle = await this.$(selector);
|
const handle = await this.$(selector);
|
||||||
console.assert(handle, 'No node found for selector: ' + selector);
|
console.assert(handle, 'No node found for selector: ' + selector);
|
||||||
await handle.evaluate(element => element.focus());
|
await this.evaluate(element => element.focus(), handle);
|
||||||
await handle.dispose();
|
await handle.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
80
test/test.js
80
test/test.js
@ -266,6 +266,30 @@ describe('Page', function() {
|
|||||||
const result = await page.evaluate('2 + 5;\n// do some math!');
|
const result = await page.evaluate('2 + 5;\n// do some math!');
|
||||||
expect(result).toBe(7);
|
expect(result).toBe(7);
|
||||||
}));
|
}));
|
||||||
|
it('should accept element handle as an argument', SX(async function() {
|
||||||
|
await page.setContent('<section>42</section>');
|
||||||
|
const element = await page.$('section');
|
||||||
|
const text = await page.evaluate(e => e.textContent, element);
|
||||||
|
expect(text).toBe('42');
|
||||||
|
}));
|
||||||
|
it('should throw if underlying element was disposed', SX(async function() {
|
||||||
|
await page.setContent('<section>39</section>');
|
||||||
|
const element = await page.$('section');
|
||||||
|
expect(element).toBeTruthy();
|
||||||
|
await element.dispose();
|
||||||
|
let error = null;
|
||||||
|
await page.evaluate(e => e.textContent, element).catch(e => error = e);
|
||||||
|
expect(error.message).toContain('ElementHandle is disposed');
|
||||||
|
}));
|
||||||
|
it('should throw if elementHandles are from other frames', SX(async function() {
|
||||||
|
const FrameUtils = require('./frame-utils');
|
||||||
|
await FrameUtils.attachFrame(page, 'frame1', EMPTY_PAGE);
|
||||||
|
const bodyHandle = await page.frames()[1].$('body');
|
||||||
|
let error = null;
|
||||||
|
await page.evaluate(body => body.innerHTML, bodyHandle).catch(e => error = e);
|
||||||
|
expect(error).toBeTruthy();
|
||||||
|
expect(error.message).toContain('ElementHandles passed as arguments should belong');
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page.injectFile', function() {
|
describe('Page.injectFile', function() {
|
||||||
@ -1151,6 +1175,12 @@ describe('Page', function() {
|
|||||||
const text = await page.$eval('section', (e, suffix) => e.textContent + suffix, ' world!');
|
const text = await page.$eval('section', (e, suffix) => e.textContent + suffix, ' world!');
|
||||||
expect(text).toBe('hello world!');
|
expect(text).toBe('hello world!');
|
||||||
}));
|
}));
|
||||||
|
it('should accept ElementHandles as arguments', SX(async function() {
|
||||||
|
await page.setContent('<section>hello</section><div> world</div>');
|
||||||
|
const divHandle = await page.$('div');
|
||||||
|
const text = await page.$eval('section', (e, div) => e.textContent + div.textContent, divHandle);
|
||||||
|
expect(text).toBe('hello world');
|
||||||
|
}));
|
||||||
it('should throw error if no element is found', SX(async function() {
|
it('should throw error if no element is found', SX(async function() {
|
||||||
let error = null;
|
let error = null;
|
||||||
await page.$eval('section', e => e.id).catch(e => error = e);
|
await page.$eval('section', e => e.id).catch(e => error = e);
|
||||||
@ -1174,7 +1204,7 @@ describe('Page', function() {
|
|||||||
await page.setContent('<div>A</div><br/><div>B</div>');
|
await page.setContent('<div>A</div><br/><div>B</div>');
|
||||||
const elements = await page.$$('div');
|
const elements = await page.$$('div');
|
||||||
expect(elements.length).toBe(2);
|
expect(elements.length).toBe(2);
|
||||||
const promises = elements.map(element => element.evaluate(e => e.textContent));
|
const promises = elements.map(element => page.evaluate(e => e.textContent, element));
|
||||||
expect(await Promise.all(promises)).toEqual(['A', 'B']);
|
expect(await Promise.all(promises)).toEqual(['A', 'B']);
|
||||||
}));
|
}));
|
||||||
it('should return empty array if nothing is found', SX(async function() {
|
it('should return empty array if nothing is found', SX(async function() {
|
||||||
@ -1184,48 +1214,6 @@ describe('Page', function() {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ElementHandle.evaluate', function() {
|
|
||||||
it('should work', SX(async function() {
|
|
||||||
await page.setContent('<section>42</section>');
|
|
||||||
const element = await page.$('section');
|
|
||||||
const text = await element.evaluate(e => e.textContent);
|
|
||||||
expect(text).toBe('42');
|
|
||||||
}));
|
|
||||||
it('should await promise if any', SX(async function() {
|
|
||||||
await page.setContent('<section>39</section>');
|
|
||||||
const element = await page.$('section');
|
|
||||||
const text = await element.evaluate(e => Promise.resolve(e.textContent));
|
|
||||||
expect(text).toBe('39');
|
|
||||||
}));
|
|
||||||
it('should throw if underlying page got closed', SX(async function() {
|
|
||||||
const otherPage = await browser.newPage();
|
|
||||||
await otherPage.setContent('<section>88</section>');
|
|
||||||
const element = await otherPage.$('section');
|
|
||||||
expect(element).toBeTruthy();
|
|
||||||
await otherPage.close();
|
|
||||||
let error = null;
|
|
||||||
try {
|
|
||||||
await element.evaluate(e => e.textContent);
|
|
||||||
} catch (e) {
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
expect(error.message).toContain('Session closed');
|
|
||||||
}));
|
|
||||||
it('should throw if underlying element was disposed', SX(async function() {
|
|
||||||
await page.setContent('<section>39</section>');
|
|
||||||
const element = await page.$('section');
|
|
||||||
expect(element).toBeTruthy();
|
|
||||||
await element.dispose();
|
|
||||||
let error = null;
|
|
||||||
try {
|
|
||||||
await element.evaluate(e => e.textContent);
|
|
||||||
} catch (e) {
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
expect(error.message).toContain('ElementHandle is disposed');
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('ElementHandle.click', function() {
|
describe('ElementHandle.click', function() {
|
||||||
it('should work', SX(async function() {
|
it('should work', SX(async function() {
|
||||||
await page.goto(PREFIX + '/input/button.html');
|
await page.goto(PREFIX + '/input/button.html');
|
||||||
@ -1284,13 +1272,13 @@ describe('Page', function() {
|
|||||||
const filePath = path.relative(process.cwd(), __dirname + '/assets/file-to-upload.txt');
|
const filePath = path.relative(process.cwd(), __dirname + '/assets/file-to-upload.txt');
|
||||||
const input = await page.$('input');
|
const input = await page.$('input');
|
||||||
await input.uploadFile(filePath);
|
await input.uploadFile(filePath);
|
||||||
expect(await input.evaluate(e => e.files[0].name)).toBe('file-to-upload.txt');
|
expect(await page.evaluate(e => e.files[0].name, input)).toBe('file-to-upload.txt');
|
||||||
expect(await input.evaluate(e => {
|
expect(await page.evaluate(e => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
const promise = new Promise(fulfill => reader.onload = fulfill);
|
const promise = new Promise(fulfill => reader.onload = fulfill);
|
||||||
reader.readAsText(e.files[0]);
|
reader.readAsText(e.files[0]);
|
||||||
return promise.then(() => reader.result);
|
return promise.then(() => reader.result);
|
||||||
})).toBe('contents of the file');
|
}, input)).toBe('contents of the file');
|
||||||
}));
|
}));
|
||||||
it('should move with the arrow keys', SX(async function(){
|
it('should move with the arrow keys', SX(async function(){
|
||||||
await page.goto(PREFIX + '/input/textarea.html');
|
await page.goto(PREFIX + '/input/textarea.html');
|
||||||
|
Loading…
Reference in New Issue
Block a user