Agile Zone is brought to you in partnership with:

Julian writes by night as The Build Doctor, a poorly disguised non de plume. By day he is a freelance build engineer, systems administrator and all round useful guy. Julian lives near London with his fiance and children. He enjoys balancing a love of real ale and Indian food with cycling. Julian has posted 16 posts at DZone. View Full User Profile

JavaScript BDD, with Jasmine, without a browser

12.13.2010
| 10853 views |
  • submit to reddit

I’ve been test driving the domain of my build radiator, XFD with the lovely Jasmine BDD framework for JavaScript. Jasmine is lovely. Browsers aren’t. Spawning a new browser to run your tests has issues for me:

  • Spawning a browser takes time and ruins my flow,
  • I’m trying to drive out logic – having a browser present will lead my design to un-natural couplings, and
  • It makes Continuous Integration that much harder


So I started investigating what I could do with Rhino and Envjs to make testing with Jasmine more awesome. Ingvald Skaug had been there before. It took me some time to really understand how the pieces fit together works, so I thought I’d expand on it.

Step 1: Check that Jasmine is working

I would have saved so much time if I’d started with this bit. What you need to do is download the core of Jasmine and stick it in your project. I started with the Jasmine RubyGem that spawns a browser and does the plumbing, but for this it’s back to basics. In my project it’s checked in at lib/jasmine-1.0.1. You need an HTML file to reference all the scripts and kick off the tests. Here’s an example derived from the Jasmine docs:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Test Runner</title>
<link rel="stylesheet" type="text/css" href="lib/jasmine-1.0.1/jasmine.css"></link>
<script type="text/javascript" src="lib/jasmine-1.0.1/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-1.0.1/jasmine-html.js"></script>

<!-- include source files here... -->
<script type="text/javascript" src="src/Player.js"></script>
<script type="text/javascript" src="src/Song.js"></script>

<!-- include spec files here... -->
<script type="text/javascript" src="spec/SpecHelper.js"></script>
<script type="text/javascript" src="spec/PlayerSpec.js"></script>

</head>
<body>

<script type="text/javascript">
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
jasmine.getEnv().execute();
</script>

</body>
</html>

In my real project I generate this file at build time from an ERB template, to make sure I get all the source files and tests. However you do it, make sure it works in a browser first. Yes. Really.

Step 2: Get the bits that you need

In my lib directory I have:

  • js.jar – which is the Rhino implementation of JavaScript. I already used this to run JsLint as part of my build
  • env.rhino.1.2.js – which is Envjs – a DOM implementation written in JavaScript.
  • jasmine.console_reporter.js, jasmine.junit_reporter.js and envjs.bootstrap.js – all from Larry Myers’ excellent Jasmine Reporters project. Jasmine Reporters is really what glues everything together.


Step 3: Wire up Jasmine Reporters

You can have many Jasmine reporters wired up in the SpecRunner.html. In this example I’m leaving two in – the TrivialReporter that gives HTML/CSS reports, and the ConsoleReporter, which we’ll use later. Here’s the edit to the SpecRunner file now:

<script type="text/javascript">
jasmine.getEnv().addReporter(new jasmine.ConsoleReporter());
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
jasmine.getEnv().execute();
</script>

Step 4: Put it all together

Here’s where it all happens. In my example I use a shell script but in real life the Rakefile that generates the SpecRunner file also fires up the JVM and checks STDOUT for error messages.

#!/bin/bash
java -jar lib/js.jar -opt -1 lib/envjs.bootstrap.js SpecRunner.html

envjs.bootstrap.js is worth examining, too:

load('lib/env.rhino.1.2.js');

Envjs.scriptTypes['text/javascript'] = true;

var specFile;

for (i = 0; i < arguments.length; i++) {
specFile = arguments[i];

console.log("Loading: " + specFile);

window.location = specFile
}

This file takes the list of HTML files that you give it and tells the fake browser inside the JVM to load each one. Jasmine then fires and runs your tests:

jsimpson@curie:~/Documents/workspace/jasmine-rhino-envjs$ ./jasmine
[ Envjs/1.6 (Rhino; U; Linux i386 2.6.32-26-generic; en-US; rv:1.7.0.rc2) Resig/20070309 PilotFish/1.2.13 ]
Loading: SpecRunner.html
Runner Started.
Player : should be able to play a Song ...
>> Jasmine Running Player should be able to play a Song...
Passed.
when song has been paused : should indicate that the song is currently paused ...
>> Jasmine Running when song has been paused should indicate that the song is currently paused...
Passed.
when song has been paused : should be possible to resume ...
>> Jasmine Running when song has been paused should be possible to resume...
Passed.
when song has been paused: 4 of 4 passed.
Player : tells the current song if the user has made it a favorite ...
>> Jasmine Running Player tells the current song if the user has made it a favorite...
Passed.
#resume : should throw an exception if song is already playing ...
>> Jasmine Running #resume should throw an exception if song is already playing...
Passed.
#resume: 1 of 1 passed.
Player: 8 of 8 passed.
Runner Finished.

There’s also a JUnit compatible XML reporter, courtesy of Larry. This lets you make the Continuous Integration server report test results as usual.

Summary
I’m very impressed. All of my tests that used to run in the browser run headless, with some fiddling of paths. I’m using the Jasmine JQuery plugin, which probably saved my bacon on the test that is too tightly coupled to views. I’ve collected the example on GitHub.

Props to Ingvald, Larry, and the Jasmine, Rhino and Envjs teams. You guys rock.



References
Published at DZone with permission of its author, Julian Simpson. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Emma Watson replied on Fri, 2012/03/30 - 3:12am

Julian, thanks for the post. I was able to get my setup working and I love it! One suggestion for some of the readers who are not as savvy with Java development is to add more details about the installation and configuration of Rhino (js.jar) and EnvJS. Also for people who are planning on using a Windows machine it is
necessary to apply a patch for EnvJS as the bootstrap code does not currently handle Windows UNC path.

java program

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.