[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:
Andrey Lushnikov
2017-09-11 19:20:02 -07:00
committed by GitHub
parent 69e707a2b7
commit 9292a56eaf
5 changed files with 118 additions and 108 deletions

View File

@@ -194,7 +194,7 @@ class Frame {
async $(selector) {
const remoteObject = await this._rawEvaluate(selector => document.querySelector(selector), selector);
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);
return null;
}
@@ -209,7 +209,8 @@ class Frame {
const elementHandle = await this.$(selector);
if (!elementHandle)
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();
return result;
}
@@ -229,7 +230,7 @@ class Frame {
const releasePromises = [helper.releaseObject(this._client, remoteObject)];
for (const property of properties) {
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
releasePromises.push(helper.releaseObject(this._client, property.value));
}
@@ -243,12 +244,50 @@ class Frame {
* @return {!Promise<(!Object|undefined)>}
*/
async _rawEvaluate(pageFunction, ...args) {
const expression = helper.evaluationString(pageFunction, ...args);
const contextId = this._defaultContextId;
const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.evaluate', { expression, contextId, returnByValue: false, awaitPromise: true});
if (helper.isString(pageFunction)) {
const contextId = this._defaultContextId;
const expression = pageFunction;
const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.evaluate', { expression, contextId, returnByValue: false, awaitPromise: true});
if (exceptionDetails)
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
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 };
}
}
/**