I now have the jasmine specs covering my Backbone.js application running under PhantomJS. Running, but the failure leaves something to be desired. The exit code is a success and the failure message simply parrots the entire suite with no indication of which specs failed.
I know that there are terminal reporters, a la the node-jasmine. They do not seem to be a quick drop-in replacement in my little PhantomJS setup. Besides, I hope that I can hack together a little something that will be good enough™.
I still have my intentionally failing spec in place:
Back in the
run.html.erb
page runner for the jasmine gem, I make the jasmineEnv
variable global so that I might access it from within PhantomJS:require(['Calendar', 'backbone'], function(Calendar, Backbone){ window.Cal = Calendar; window.Backbone = Backbone; window.jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var reporter = new jasmine.TrivialReporter(); jasmineEnv.addReporter(reporter); jasmineEnv.specFilter = function(spec) { return reporter.specFilter(spec); }; jasmineEnv.execute(); });Then, in the PhantomJS contributed
run-jasmine.js
, I log the number of failed specs found in the current spec runner: waitFor(
function(){ /* finished at to display */ },
function(){
page.evaluate(function(){
console.log('Failed: ' + jasmineEnv.currentRunner().results().failedCount);
// ...
});
});
(I uncover that chain by fiddling with things in Chrome's Javascript console)With that logger in place, when I run my intentionally failing specs, I see:
# lots of normal application console.log output ... [object Arguments] 'waitFor()' finished in 1164ms. Failed: 1 # The text for all specs in the suite...Looking more closely at the PhantomJS
run-jasmine.js
script, I notice that it is quite shallow: waitFor(
function(){ /* finished at to display */ },
function(){
page.evaluate(function(){
console.log('Failed: ' + jasmineEnv.currentRunner().results().failedCount);
list = document.body.querySelectorAll('div.jasmine_reporter > div.suite.failed');
for (i = 0; i < list.length; ++i) { /* ... */ }
});
});
By "shallow", I mean that the script is simply grabbing the top-level failed spec and then logging the inner text of each immediate-child: list = document.body.querySelectorAll('div.jasmine_reporter > div.suite.failed');
for (i = 0; i < list.length; ++i) {
el = list[i];
desc = el.querySelectorAll('.description');
console.log('');
for (j = 0; j < desc.length; ++j) {
console.log(desc[j].innerText);
}
}
As can be seen from the screen shot of my failing spec, I am nest things quite a bit. What this translates into is a bunch of nested spec groups, each of which have some failing and some passing specs:To paraphrase the immortal philospher of movies, I know this... it's recursion! So I create a log_failure recursive function to log the specs properly:
waitFor(
function(){ /* finished at to display */ },
function(){
page.evaluate(function(){
console.log('Failed: ' + jasmineEnv.currentRunner().results().failedCount);
function has_message(el) { /* children className == spec failed */ }
function failed_children(el) { /* all children w/ className == 'suite failed' */ }
function log_failure(failure_el, indent) {
if (typeof(indent) == 'undefined') indent = '';
console.log(indent + failure_el.querySelector('.description').innerText);
if (has_message(failure_el)) {
console.log(indent + ' ' + failure_el.querySelector('.messages > .fail').innerText);
}
else {
failed_children(failure_el).forEach(function (failed_child) {
log_failure(failed_child, indent + ' ');
});
}
log_failure(document.body.querySelectorAll('div.jasmine_reporter > div.suite.failed')[0]);
}
})
});
That is kinda ugly because I had to work with HTML Collections instead of arrays. Still, it seems to work because the output produces:'waitFor()' finished in 1117ms. Failed: 1 Calendar the initial view the page title Expected '<h1>Funky Calendar<span> (2011-12) </span></h1>' to have text 'Remember, Remember the Fifth of Novemeber'.I think I can live with that.
Day #238
No comments:
Post a Comment