diff --git a/docs/api.md b/docs/api.md
index 4aa0c70af01..a6ced9cf3e1 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -354,14 +354,34 @@ Adds a `` tag to the page with the desired url. Alternatively,
- returns: <[Promise]> Returns promise which resolves when page gets closed.
#### page.evaluate(pageFunction, ...args)
-- `pageFunction` <[function]> Function to be evaluated in browser context
+- `pageFunction` <[function]|[string]> Function to be evaluated in browser context
- `...args` <...[string]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Object]>> 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.
+
+```js
+const {Browser} = require('puppeteer');
+const browser = new Browser();
+browser.newPage().then(async page =>
+ const result = await page.evaluate(() => {
+ return Promise.resolve().then(() => 8 * 7);
+ });
+ console.log(result); // prints "56"
+ browser.close();
+});
+```
+
+A string can also be passed in instead of a function.
+
+```js
+console.log(await page.evaluate('1 + 2')); // prints "3"
+```
+
This is a shortcut for [page.mainFrame().evaluate()](#frameevaluatefun-args) method.
#### page.evaluateOnNewDocument(pageFunction, ...args)
-- `pageFunction` <[function]> Function to be evaluated in browser context
+- `pageFunction` <[function]|[string]> Function to be evaluated in browser context
- `...args` <...[string]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Object]>> Promise which resolves to function
@@ -825,23 +845,11 @@ Adds a `` tag to the frame with the desired url. Alternatively,
- returns: <[Promise]> Promise which resolves when the element matching `selector` is successfully clicked. Promise gets rejected if there's no element matching `selector`.
#### frame.evaluate(pageFunction, ...args)
-- `pageFunction` <[function]> Function to be evaluated in browser context
+- `pageFunction` <[function]|[string]> Function to be evaluated in browser context
- `...args` <...[string]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Object]>> 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.
-
-```js
-const {Browser} = require('puppeteer');
-const browser = new Browser();
-browser.newPage().then(async page =>
- const result = await page.evaluate(() => {
- return Promise.resolve().then(() => 8 * 7);
- });
- console.log(result); // prints "56"
- browser.close();
-});
-```
+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.
#### frame.focus(selector)
- `selector` <[string]> A query selector of element to focus. If there are multiple elements satisfying the selector, the first will be focused.
diff --git a/lib/FrameManager.js b/lib/FrameManager.js
index 9873aa79e25..13f7b017ed2 100644
--- a/lib/FrameManager.js
+++ b/lib/FrameManager.js
@@ -187,24 +187,14 @@ class Frame {
}
/**
- * @param {function()} pageFunction
+ * @param {function()|string} pageFunction
* @param {!Array<*>} args
* @return {!Promise<(!Object|undefined)>}
*/
async evaluate(pageFunction, ...args) {
- return this._evaluateExpression(helper.evaluationString(pageFunction, ...args), true);
- }
-
- /**
- * @param {string} expression
- * @param {boolean} awaitPromise
- * @return {!Promise<(!Object|undefined)>}
- */
- async _evaluateExpression(expression, awaitPromise) {
+ let expression = helper.evaluationString(pageFunction, ...args);
const contextId = this._defaultContextId;
- if (awaitPromise)
- expression = `Promise.resolve(${expression})`;
- let { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.evaluate', { expression, contextId, returnByValue: false, awaitPromise});
+ let { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.evaluate', { expression, contextId, returnByValue: false});
if (exceptionDetails)
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
return await helper.serializeRemoteObject(this._client, remoteObject);
@@ -257,7 +247,7 @@ class Frame {
});
});
contents += `//# sourceURL=` + filePath.replace(/\n/g,'');
- return this._evaluateExpression(contents, false);
+ return this.evaluate(contents);
}
/**
@@ -319,7 +309,7 @@ class Frame {
return null;
return (${pageFunction})(${argsString});
})()`;
- return this._evaluateExpression(expression, true);
+ return this.evaluate(expression);
}
/**
@@ -335,7 +325,7 @@ class Frame {
let nodes = document.querySelectorAll(${JSON.stringify(selector)});
return Array.prototype.map.call(nodes, (node, index) => (${pageFunction})(${argsString}));
})()`;
- return this._evaluateExpression(expression, true);
+ return this.evaluate(expression);
}
/**
@@ -457,7 +447,7 @@ class WaitTask {
let success = false;
let error = null;
try {
- success = await this._frame._evaluateExpression(this._pageScript, true);
+ success = await this._frame.evaluate(this._pageScript);
} catch (e) {
error = e;
}
diff --git a/lib/Page.js b/lib/Page.js
index 6a4895efba5..8a172640618 100644
--- a/lib/Page.js
+++ b/lib/Page.js
@@ -345,7 +345,7 @@ class Page extends EventEmitter {
}
/**
- * @param {function()} pageFunction
+ * @param {function()|string} pageFunction
* @param {!Array<*>} args
* @return {!Promise}
*/
diff --git a/lib/helper.js b/lib/helper.js
index d077dcece3e..248ec465c55 100644
--- a/lib/helper.js
+++ b/lib/helper.js
@@ -16,11 +16,15 @@
class Helper {
/**
- * @param {function()} fun
+ * @param {function()|string} fun
* @param {!Array<*>} args
* @return {string}
*/
static evaluationString(fun, ...args) {
+ if (typeof fun === 'string') {
+ console.assert(args.length === 0, 'Cannot evaluate a string with arguments');
+ return fun;
+ }
return `(${fun})(${args.map(x => JSON.stringify(x)).join(',')})`;
}
@@ -48,6 +52,16 @@ class Helper {
* @return {!Promise}
*/
static async serializeRemoteObject(client, remoteObject) {
+ if (remoteObject.subtype === 'promise') {
+ let response = (await client.send('Runtime.awaitPromise', {
+ promiseObjectId: remoteObject.objectId,
+ returnByValue: false
+ }));
+ Helper.releaseObject(client, remoteObject);
+ if (response.exceptionDetails)
+ throw new Error('Evaluation failed: ' + Helper.getExceptionMessage(response.exceptionDetails));
+ remoteObject = response.result;
+ }
if (remoteObject.unserializableValue) {
switch (remoteObject.unserializableValue) {
case '-0':
diff --git a/phantom_shim/WebPage.js b/phantom_shim/WebPage.js
index 84583b49f94..076611edca9 100644
--- a/phantom_shim/WebPage.js
+++ b/phantom_shim/WebPage.js
@@ -533,10 +533,12 @@ class WebPage {
}
/**
- * @param {function()} fun
+ * @param {function()|string} fun
* @param {!Array} args
*/
evaluate(fun, ...args) {
+ if (typeof fun === 'string')
+ fun = `(${fun})()`;
if (this._deferEvaluate)
return await(this._page.evaluateOnNewDocument(fun, ...args));
return await(this._currentFrame.evaluate(fun, ...args));
diff --git a/test/test.js b/test/test.js
index 372d5150e0b..f8414c4f779 100644
--- a/test/test.js
+++ b/test/test.js
@@ -144,6 +144,18 @@ describe('Puppeteer', function() {
let result = await page.evaluate(() => window);
expect(result).toBe('Window');
}));
+ it('should accept a string', SX(async function() {
+ let result = await page.evaluate('1 + 2');
+ expect(result).toBe(3);
+ }));
+ it('should accept a string with semi colons', SX(async function() {
+ let result = await page.evaluate('1 + 5;');
+ expect(result).toBe(6);
+ }));
+ it('should accept a string with comments', SX(async function() {
+ let result = await page.evaluate('2 + 5;\n// do some math!');
+ expect(result).toBe(7);
+ }));
});
describe('Page.injectFile', function() {