Saturday, December 17, 2011

Phantom.js and Backbone.js (and require.js)

‹prev | My Chain | next›

Yesterday I was able to make use of my mad ruby hacker skills to get the jasmine server to run the jasmine specs for my backbone.js and require.js application. Today, I hope to use my lovely specs:


The hope is to get them running under PhantomJS—a headless webkit and Javascript engine. First I need to install the thing. For that, I follow the build instructions for Ubuntu. I already have the QT dependencies installed, so I download the source code and compile:
➜  Downloads  wget http://phantomjs.googlecode.com/files/phantomjs-1.3.0-source.tar.gz
...
2011-12-17 23:00:29 (144 KB/s) - `phantomjs-1.3.0-source.tar.gz' saved [409428/409428]

➜  Downloads  sha1sum phantomjs-1.3.0-source.tar.gz 
76902ad0956cf212cc9bb845f290690f53eca576  phantomjs-1.3.0-source.tar.gz


➜  src  tar zxf ../Downloads/phantomjs-1.3.0-source.tar.gz
➜  src  cd phantomjs-1.3.0

➜  phantomjs-1.3.0  qmake-qt4 && make
cd src/ && /usr/bin/qmake-qt4 /home/cstrom/src/phantomjs-1.3.0/src/phantomjs.pro -o Makefile.phantomjs
cd src/ && make -f Makefile.phantomjs
make[1]: Entering directory `/home/cstrom/src/phantomjs-1.3.0/src'
...
make[1]: Leaving directory `/home/cstrom/src/phantomjs-1.3.0/src'

➜  phantomjs-1.3.0  ls -l bin
total 324
-rwxrwxr-x 1 cstrom cstrom 330534 2011-12-17 23:05 phantomjs
I copy that phantomjs executable into my bin directory (which is in my $PATH):
➜  phantomjs-1.3.0  cp bin/phantomjs ~/bin/
I am not quite ready just yet. In the same source code, PhantomJS includes a script for running jasmine tests. That sounds like exactly what I want, I copy it into my applications source directory:
➜  phantomjs-1.3.0  cp examples/run-jasmine.js ~/repos/calendar
With that, I am ready to give PhantomJS and the jasmine server a try. First, I spin up the jasmine server:
➜  calendar git:(master) ✗ rake jasmine
your tests are here:
  http://localhost:8888/
In a separate terminal, I then point PhantomJS at the run-jasmine.js script and my running gem server:
➜  calendar git:(requirejs-jasmine-gem) ✗ phantomjs run-jasmine.js http://localhost:8888
[setDefault]
[setMonth] %s
Error: Backbone.history has already been started
[setMonth] %s
...
[setDefault]
[setMonth] %s
editClick
Error: Backbone.history has already been started
[setMonth] %s
[fetch] Dang
[object Arguments]
'waitFor()' finished in 1253ms.
Hrm... I guess that worked OK. The exit status was cool:
➜  calendar git:(requirejs-jasmine-gem) ✗ echo $?                                       
0
All of the output was just my various calls to console.log(). Really, I should remove them because they will break older browsers like IE. It is interesting that PhantomJS does not seem to honor the sprintf format of console.log:
define(function(require) {
  var Backbone = require('backbone')
    , to_iso8601 = require('Calendar/Helpers.to_iso8601');

  return Backbone.Router.extend({
    // ....
    setMonth: function(date) {
      console.log("[setMonth] %s", date);
      this.application.setDate(date);
    }
  });
});
The "[fetch] Dang" error seems legit. It is not causing anything to fail, but I seem to have missed a sinon.js stub somewhere in my tests.

All of the Backbone.history messages are a minor headache incurred when testing Backbone.js applications with jasmine.

So it all seems to be working. To be sure, I intentionally break a test:
    describe("the page title", function() {
      it("contains the current month", function() {
        expect($('h1')).toHaveText("Remember, Remember the Fifth of Novemeber");
      });
    });
In the browser, this failure looks like:


In PhantomJS, it looks like:
➜  calendar git:(requirejs-jasmine-gem) ✗ phantomjs run-jasmine.js http://localhost:8888
...
'waitFor()' finished in 1044ms.


Calendar
routing
defaults to the current month
sets the date of the appointment collection
the initial view
the page title
contains the current month
a collection of appointments
populates the calendar with appointments
adding an appointment
sends clicks on day to an add dialog
displays the date clicked in the add dialog
adds a new appointment to the UI when saved
deleting an appointment
clicking the "X" removes records from the data store and UI
updating an appointment
binds click events on the appointment to an edit dialog
displays model updates
can edit appointments through an edit dialog
navigated view
I guess that failed. The output was different. Even so that exist code remained the same:
➜  calendar git:(requirejs-jasmine-gem) ✗ echo $?
0
Hrm... that output is nothing more than the entire text of the test suite. Hopefully fixing that is just a simple matter of futzing with the run-jasmine.js script. I think I will leave that for tomorrow.

For now, I am happy with the progress I made tonight. I can run my Jasmine test suite under the Jasmine server (standalone still works as well) and under PhantomJS. The output from PhantomJS leaves a little to be desired, but it is still workable in a continuous integration environment. Hopefully, by tomorrow, I can make it even better.


Day #237

No comments:

Post a Comment