diff --git a/examples/pagecallback.js b/examples/pagecallback.js index 2ffdb06a..15daa316 100644 --- a/examples/pagecallback.js +++ b/examples/pagecallback.js @@ -19,14 +19,26 @@ var browser = new Browser(); browser.newPage().then(async page => { page.on('consolemessage', console.log); + + await page.setInPageCallback('callPhantom', msg => { - console.log("Received by the 'phantom' main context: "+msg); - return "Hello there, I'm coming to you from the 'phantom' context instead"; + console.log("Page is saying: '" + msg + "'"); + return "Hello, page"; }); - await page.evaluate(function() { + + + + + await page.evaluate(async function() { + + + // Return-value of the "onCallback" handler arrive here - var callbackResponse = window.callPhantom("Hello, I'm coming to you from the 'page' context"); - console.log("Received by the 'page' context: "+callbackResponse); + var callbackResponse = await window.callPhantom("Hello, driver"); + console.log("Driver is saying: '" + callbackResponse + "'"); + + + }); browser.close(); }); diff --git a/lib/Browser.js b/lib/Browser.js index 3acff7f9..7ed79781 100644 --- a/lib/Browser.js +++ b/lib/Browser.js @@ -38,7 +38,7 @@ class Browser { options = options || {}; ++browserId; this._userDataDir = CHROME_PROFILE_PATH + browserId; - this._remoteDebuggingPort = 9229; + this._remoteDebuggingPort = 9227; if (typeof options.remoteDebuggingPort === 'number') this._remoteDebuggingPort = options.remoteDebuggingPort; this._chromeArguments = DEFAULT_ARGS.concat([ diff --git a/lib/Page.js b/lib/Page.js index 0b1233e9..40abe375 100644 --- a/lib/Page.js +++ b/lib/Page.js @@ -50,17 +50,13 @@ class Page extends EventEmitter { this._client = client; this._screenDPI = screenDPI; this._extraHeaders = {}; - /** @type {!Map} */ - this._sourceURLToPageCallback = new Map(); - /** @type {!Map} */ - this._scriptIdToPageCallback = new Map(); + /** @type {!Map} */ + this._inPageCallbacks = new Map(); /** @type {?function(!Request)} */ this._requestInterceptor = null; this._screenshotTaskChain = Promise.resolve(); - client.on('Debugger.paused', event => this._onDebuggerPaused(event)); - client.on('Debugger.scriptParsed', event => this._onScriptParsed(event)); client.on('Network.responseReceived', event => this.emit(Page.Events.ResponseReceived, event.response)); client.on('Network.loadingFailed', event => this.emit(Page.Events.ResourceLoadingFailed, event)); client.on('Network.requestIntercepted', event => this._onRequestIntercepted(event)); @@ -118,69 +114,31 @@ class Page extends EventEmitter { * @param {function(?)} callback */ async setInPageCallback(name, callback) { - var hasCallback = await this.evaluate(function(name) { - return !!window[name]; - }, name); - if (hasCallback) + if (this._inPageCallbacks[name]) throw new Error(`Failed to set in-page callback with name ${name}: window['${name}'] already exists!`); + this._inPageCallbacks[name] = callback; - var sourceURL = '__in_page_callback__' + name; - this._sourceURLToPageCallback.set(sourceURL, new InPageCallback(name, callback)); - var expression = helpers.evaluationString(inPageCallback, [name], false /* wrapInPromise */, sourceURL); - await Promise.all([ - this._client.send('Debugger.enable', {}), - this._client.send('Page.addScriptToEvaluateOnLoad', { scriptSource: expression }), - this._client.send('Runtime.evaluate', { expression, returnByValue: true }) - ]); + var expression = helpers.evaluationString(inPageCallback, [name]); + await this._client.send('Page.addScriptToEvaluateOnLoad', { scriptSource: expression }); + await this._client.send('Runtime.evaluate', { expression, returnByValue: true }); function inPageCallback(callbackName) { - window[callbackName] = (...args) => { - window[callbackName].__args = args; - debugger; - var result = window[callbackName].__result; - delete window[callbackName].__result; - delete window[callbackName].__args; - return result; + window[callbackName] = async (...args) => { + const me = window[callbackName]; + let callbacks = me['callbacks']; + if (!callbacks) { + callbacks = new Map(); + me['callbacks'] = callbacks; + } + const seq = (me['lastSeq'] || 0) + 1; + me['lastSeq'] = seq; + const promise = new Promise(fulfill => callbacks.set(seq, fulfill)); + console.debug('driver:InPageCallback', JSON.stringify({name: callbackName, seq, args})); + return promise; }; } } - /** - * @param {!InPageCallback} inPageCallback - */ - async _handleInPageCallback(inPageCallback) { - var name = inPageCallback.name; - var callback = inPageCallback.callback; - var args = await this.evaluate(callbackName => window[callbackName].__args, name); - var result = await Promise.resolve(callback.apply(null, args)); - await this.evaluate(assignResult, name, result); - this._client.send('Debugger.resume'); - - /** - * @param {string} callbackName - * @param {string} callbackResult - */ - function assignResult(callbackName, callbackResult) { - window[callbackName].__result = callbackResult; - } - } - - _onDebuggerPaused(event) { - var location = event.callFrames[0] ? event.callFrames[0].location : null; - var inPageCallback = location ? this._scriptIdToPageCallback.get(location.scriptId) : null; - if (inPageCallback) { - this._handleInPageCallback(inPageCallback); - return; - } - this._client.send('Debugger.resume'); - } - - _onScriptParsed(event) { - var inPageCallback = this._sourceURLToPageCallback.get(event.url); - if (inPageCallback) - this._scriptIdToPageCallback.set(event.scriptId, inPageCallback); - } - /** * @param {!Object} headers * @return {!Promise} @@ -224,7 +182,19 @@ class Page extends EventEmitter { this.emit(Page.Events.Error, new Error(message)); } - _onConsoleAPI(event) { + async _onConsoleAPI(event) { + if (event.type === 'debug' && event.args.length && event.args[0].value === 'driver:InPageCallback') { + var {name, seq, args} = JSON.parse(event.args[1].value); + var result = await this._inPageCallbacks[name](...args); + var expression = helpers.evaluationString(deliverResult, [name, seq, result]); + this._client.send('Runtime.evaluate', { expression }); + + function deliverResult(name, seq, result) { + window[name]['callbacks'].get(seq)(result); + window[name]['callbacks'].delete(seq); + } + return; + } var values = event.args.map(arg => arg.value || arg.description || ''); this.emit(Page.Events.ConsoleMessage, values.join(' ')); } diff --git a/phantom_shim/WebPage.js b/phantom_shim/WebPage.js index 5f98da0e..6d07a5a5 100644 --- a/phantom_shim/WebPage.js +++ b/phantom_shim/WebPage.js @@ -39,10 +39,7 @@ class WebPage { if (options.viewportSize) await(this._page.setViewportSize(options.viewportSize)); - await(this._page.setInPageCallback('callPhantom', (...args) => this.onCallback.apply(null, args))); - this.clipRect = options.clipRect || {left: 0, top: 0, width: 0, height: 0}; - this.onCallback = null; this.onConsoleMessage = null; this.onLoadFinished = null; this.onResourceError = null; diff --git a/test/test.js b/test/test.js index 9dd0582a..76063c26 100644 --- a/test/test.js +++ b/test/test.js @@ -70,8 +70,8 @@ describe('Puppeteer', function() { await page.setInPageCallback('callController', async function(a, b) { return await page.evaluate((a, b) => a * b, a, b); }); - var result = await page.evaluate(function() { - return callController(9, 3); + var result = await page.evaluate(async function() { + return await callController(9, 3); }); expect(result).toBe(27); })); @@ -110,9 +110,8 @@ describe('Puppeteer', function() { await page.setInPageCallback('callController', function(a, b) { return a * b; }); - - var result = await page.evaluate(function() { - return callController(9, 4); + var result = await page.evaluate(async function() { + return await callController(9, 4); }); expect(result).toBe(36); })); @@ -122,8 +121,8 @@ describe('Puppeteer', function() { }); await page.navigate(EMPTY_PAGE); - var result = await page.evaluate(function() { - return callController(9, 4); + var result = await page.evaluate(async function() { + return await callController(9, 4); }); expect(result).toBe(36); })); @@ -132,8 +131,8 @@ describe('Puppeteer', function() { return Promise.resolve(a * b); }); - var result = await page.evaluate(function() { - return callController(3, 5); + var result = await page.evaluate(async function() { + return await callController(3, 5); }); expect(result).toBe(15); })); diff --git a/third_party/phantomjs/test/module/webpage/callback.js b/third_party/phantomjs/test/module/webpage/callback.js index 0c14c441..c8edb1b4 100644 --- a/third_party/phantomjs/test/module/webpage/callback.js +++ b/third_party/phantomjs/test/module/webpage/callback.js @@ -13,4 +13,4 @@ test(function () { }, msgA, msgB); assert_equals(result, expected); -}, "page.onCallback"); +}, "page.onCallback", { expected_fail : true });