Monday, December 19, 2011

Exit Codes from PhantomJS Jasmine Runs

‹prev | My Chain | next›

Last night, I was able to get some pretty OK output from my jasmine test suite when run with PhantomJS. I had to use the jasmine server provided by the jasmine ruby gem to get my require.js structured Backbone.js application running under test, but it was worth it if it makes testing easy on a continuous integration server.

The thing about continuous integration servers is that they like proper exit codes from builds. A non-zero exit code indicates a failure on Unix systems, but the run-jasmine.js script that is supplied in the PhantomJS examples always returns 0:
        waitFor(
          function(){
            return page.evaluate(function(){
              // Run the Jasmine suite on the page
            });
          }, 
          function(){
            page.evaluate(function(){ 
              // Inspect the results
            });
            phantom.exit();
          }
        );
The problem is that, inside the page.evaluate the anonymous function has no access to PhantomJS variables. So something like this will not work:
        var passed;
        waitFor(
          function(){ // Run the Jasmine suite on the page }, 
          function(){
            page.evaluate(function(){ 
              // Inspect the results

              passed = jasmineEnv.currentRunner().results().passed();
            });
            phantom.exit(passed);
          }
        );
The value of passed at the very end will always be undefined.

I could return a value from page.evaluate, but the enclosing waitFor() does not return a value.

Without any better solution, I try to write to the file system:
page.evaluate(function(){
  var fs = require('fs');
  // ...
})
But even that does not work for me:
Error: Module name 'fs' has not been loaded yet for context: _
http://requirejs.org/docs/errors.html#notloaded
Unfortunately, I seem to be stuck here.

Update: Figured it out. The indentation in my Javascript was confusing me. It turns out that I can use the return value from page.evaluate():
        waitFor(
          function(){ // Run the Jasmine suite on the page }, 
          function(){
            var passed = page.evaluate(function(){ 
              // Inspect the results

              return jasmineEnv.currentRunner().results().passed();
            });
            phantom.exit(passed ? 0 : 1);
          }
        );
Now, if I run the test suite with an and-and echo, I do not see the and-and echo when the suite is failing:
➜  calendar git:(requirejs-jasmine-gem) ✗ phantomjs run-jasmine.js http://localhost:8888 && echo "\n\n    PASSED\!\!\!\!\n\n"
...
'waitFor()' finished in 980ms.

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'.
But, when I fix that spec and re-run the suite, I do see the and-and echo output:
➜  calendar git:(requirejs-jasmine-gem) ✗ phantomjs run-jasmine.js http://localhost:8888 && echo "\n\n    PASSED\!\!\!\!\n\n"
...
'waitFor()' finished in 1138ms.

Succeeded.




    PASSED!!!!

Yay!


Day #239

3 comments:

  1. Thanks man! this helped me out a ton. Now I've got my project set up using Travis CI with jasmine and phantomjs running my unit tests.

    However, I was unable to access the jasmineEnv variable like you did. I solved it by returning
    errors.length == 0 instead (should be the same thing, right?)

    ReplyDelete
    Replies
    1. Nice! That's a better solution than mine. I had made jasmineEnv global the night before this: http://japhr.blogspot.com/2011/12/somewhat-pretty-printing-with-phantomjs.html, which explains why I was able to get access to it.

      Thanks for sharing :)

      Delete
  2. Oh, and you can check out the project at github of course. It's just getting started.

    https://github.com/ansjob/rtorrentcontrol

    ReplyDelete