2

I'm trying to test a chrome plugin by simulating part of what it's doing on phantomjs.

What I want phantom to do seems extremely simple, and yet I'm having problems. I want it to visit a certain web page and in the context of this page run a script that will send an ajax request to my backend and print out the response. To make my life easier, I want phantom to use jQuery for sending ajax requests.

So here’s the script test1.js that I’m passing to phantom:

var page = new WebPage(), url = 'http://www.example.com', // Callback is executed each time a page is loaded... page.open(url, function (status) { if (status === 'success') { console.log('opened url'); start(); } }); function start(){ page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function() { console.log("got here"); $.get("http://my-wonderful-site.com") .done(function( data ) { console.log("here!"); console.log(data); phantom.exit(); }); }); } 

The console output of the command phantomjs test1.js --web-security=false is:

opened url got here ReferenceError: Can't find variable: $ test1.js:20 :/modules/webpage.js:337 

So it seems that even jQuery doesn’t get loaded, but I can't figure out what I am doing wrong. Tried page.injectJs to inject jQuery from my hard drive, but got the same error. Could you please help?

Edited:

Updated the function as suggested:

function start(){ page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function() { console.log("got here"); page.evaluate(function() { console.log("and here"); $.get("http://my-wonderful-site.com") .done(function( data ) { console.log("here!"); console.log(data); phantom.exit(); }); }); }); } 

Now phantom just hangs, and the console output is:

phantomjs test1.js --web-security=false opened url got here 

That is, the console.log immediately before the $.get doesn't even execute.

0

2 Answers 2

2

PhantomJS has two contexts. The inner context or page context is defined by page.evaluate(). It is sandboxed and has no access to variables defined outside. So, it doesn't know what phantom is. In the same way the outer context doesn't know what $ is, because jQuery is a DOM library and was injected into the page. You need to wrap your jQuery request in page.evaluate().

The other thing is that now, phantom.exit() doesn't mean anything. You need to tell PhantomJS to exit from inside of the page context, because the request is asynchronous. That's where the page.onCallback and window.callPhantom() pair comes in.

page.onCallback = function(data){ if (data.type === "exit") { phantom.exit(); } }; function start(){ page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function() { console.log("got here"); page.evaluate(function(){ $.get("http://my-wonderful-site.com") .done(function( data ) { console.log("here!"); console.log(data); window.callPhantom({type: "exit"}); }); }); }); } 

console.log() is defined inside of the page context, but you can't see it there, because PhantomJS doesn't pass them out by default. You have to register to the page.onConsoleMessage event.

You can also send the data to the outer context with the help of callPhantom() instead of logging it. Note that not everything can be passed between the contexts:

Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.

Closures, functions, DOM nodes, etc. will not work!

The other helpful event handlers are onError, onResourceError, onResourceTimeout in case there are still problems.

Sign up to request clarification or add additional context in comments.

2 Comments

Cool! Got it working using the page.onCallback and page.onConsoleMessage listeners. Incidentally, since I’m now listening to all console messages, I see lots of warnings like this: Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL about:blank. Domains, protocols and ports must match. Is this normal?
If you're using 1.9.8, then it is. It's simply a bug in PhantomJS that was introduced in version 1.9.8. It doesn't do anything and is only bad if you need clean output. I suggest that you update to PhantomJS 2.
0

I'm pretty sure you need to be in a page.evaluate to actually use the injected JS (see example here http://phantomjs.org/page-automation.html). Try:

function start() { page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function() { console.log("got here"); page.evaluate(function() { $.get("http://my-wonderful-site.com") .done(function( data ) { console.log("here!"); console.log(data); phantom.exit(); }); }); }); } 

9 Comments

Ah! This reminds me. I tried this before, and I tried this once again now (see update of my question). The error goes away, but now phantomjs just hangs immediately after page.evaluate. I put a logger before the $.get, but it doesn't print anything in the console.
Well now that's weird, you're definitely using the jQuery now at least. Just for the sake of debugging, add a console.log in the .get callback as well ($.get("http://my-wonderful-site.com", function(){ console.log('derp'); })). Does it at least hit that?
Nope :-( And I added a console.log on the line between page.evaluate... and $.get — and that console.log doesn't show up in the console either. So, technically, there’s even no way of saying that jQuery is being used, because the execution stops before it gets to $.get.
So basically, even if I remove the jQuery bit altogether and just write ` page.evaluate(function() { console.log("and here"); });`, this freezes phantom when it gets to that point, and the log message does not even appear in the console.
Ahh whoops, I missed the log after the page.eval, you are 100% correct it's not getting there. Looking at some of my own tests, I am instantiating the page a bit differently- var webPage = require('webpage'); var page = webPage.create(); instead of var webPage = require('webpage'); var page = new webPage(). Long shot, but worth a try?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.