Reputation: 9163
We are using the superb WebdriverJS (with Selenium) to perform acceptance testing on our web app. Everything works fine, and our tests execute successfully when we use Firefox and Safari.
However, when we use PhantomJS, our tests fail with unhelpful errors. It's almost as if... Javascript isn't even running inside the client page! Something that would cause this would be if PhantomJS' javascript environment ran into errors. Unfortunately, I can't seem to find a way to access Javascript errors when using PhantomJS with WebdriverJS.
If we were using PhantomJS directly, we could simply do (from the PhantomJS site):
page.onError = function(msg, trace) {
console.log(msg);
trace.forEach(function(item) {
console.log(' ', item.file, ':', item.line);
});
}
Unfortunately, I don't know how to access this mysterious page
object when using PhantomJS within WebdriverJS. Any thoughts?
Upvotes: 2
Views: 1680
Reputation: 233
You can actually access JS errors in your PhantomJS stdout log at INFO level.
$ phantomjs --webdriver 4444 --webdriver-loglevel=INFO
You can even push things forward by setting the log level to DEBUG
and see what actually PhantomJS does to execute the commands you send through Webdriver / Ghostdriver.
Upvotes: 3
Reputation: 9163
I figured out a workable solution! Essentially, it involves using an onerror event handler to intercept (and store) the Javascript errors. Then, once the DOM is ready, we report the errors via hidden DOM elements. This allows Selenium to look for specific elements (e.g. ".javascript-errors"), which is something it's naturally quite good at. Thanks go to myriad other blog posts and SO questions for getting me to this point.
The code:
//For detecting and reporting Javascript errors via Selenium. Note that this should be in its own file to allow this code to reliably detect syntax errors in other files.
var errors = [];
//Handle all errors
window.onerror = function(message, url, line) {
errors.push({"message":message, "url":url, "line":line});
}
//Report errors visually via HTML once the DOM is ready
window.onload = function() {
if(errors.length==0)
return;
var div = document.createElement("div");
div.className = 'javascript-errors';
div.innerHTML = '';
var style = "position:absolute; left:-10000px; top:auto; width:1px; height:1px;"; //CSS to hide the errors; we can't use display:none, or Selenium won't be able to read the error messages. Adapted from http://webaim.org/techniques/css/invisiblecontent/
for(var i=0; i<errors.length; i++)
div.innerHTML += '<div class="javascript-error" style="' + style +'"><span class="message">' + errors[i].message.replace('<', '<').replace('>', '>') + '</span><br/><span class="url">' + errors[i].url + '</span><br/><span class="line">' + errors[i].line + '</span></div>';
document.body.appendChild(div);
}
Upvotes: 2