Configuring Jasmine to work with Maven and JQuery Fixtures

For me unit testing Javascript has been an issue for quite a while. Our backend server usually have a lot of tests at various levels but the Javascript service and view layers have been more or less neglected in terms of automated tests. Using Selenium is one option but if your UI is subject to frequent changes Selenium tests can be quite cumbersome and time consuming to use and maintain. So without any automated tests for the Javascript code you can probably guess where we end up having the most bugs? Using Java, Maven is the defacto build tool and you want your Javascript tests to integrate with Maven as smooth as possible. A requirement is also that the tests must run headless on our continous integration server and while in development mode we want to avoid restarting the container when updating our Jasmine specifications and Javascript production code.

Introducing the Jasmine Maven Plugin

At first glance the Jasmine Maven plugin seem to be perfect for the job. It supports running our tests headlessly from Maven using HtmlUnit as well as from a Jetty container. It’s simple to get started and you’re up and running in no time:

This goal starts an embedded Jetty server that assumes that the production code is in the src/main/javascript folder and the Jasmine specs are in the src/test/javascript folder. Connect to http://localhost:8234 and all your Jasmine specs are executed and the outcome is presented on an HTML page. This gives you a rapid turn-around time, you can simply change the Javascript code and hit refresh in the browser and the specification suite is re-executed. Nice! In my current project this almost worked out of the box. All we had to do was to change the jsSrcDir property in our Jasmine Maven plugin configuration in the pom.xml to ${project.basedir}/src/main/webapp/javascript and we were able to run our specifications.

How about headless?

I was very impressed by how simple it was to get everything working using the jasmine:bdd goal. But when running the jasmine:test to exectue the specs in headless mode things did not work as smoothly:

The reason is that a function called “service” couldn’t be found in some.js which is the Javascript file we’re testing. It’s actually not that surprising when you think about it. When using the jasmine:bdd goal Jetty loads the index page of our web application automatically and thus all scripts are loaded. When running outside the container, HtmlUnit doesn’t know that some functions in some.js depends on functions defined in other Javascript files. We need to tell Jasmine to load them before it executes these specifications. This is done by adding preloadSources to the Jasmine Maven plugin configuration. Let’s say that the “service” function is defined in x.js which in turn depends on y.js then this is how you would configure it:

After this change we were able to run the specs both headlessly using jasmine:test and inside the browser using the jasmine:bdd goal. Keep in mind that the order of includes in preloadSources are important. Also if you have cyclic dependencies between your Javascript files you will need to refactor them.

Using JQuery Fixtures

When testing a function that interacts with the DOM it’s good to be able to provide some fixture data that can be loaded during the test. One way to do this is to use the Jasmine JQuery plugin. It allows you do load HTML fixtures from your test, for example:

myfixture.html

Usage:

In Jasmie JQuery you can configure the path to where it should look for the fixtures, e.g.

This will intruct the plugin to look for fixtures in the target/spec/fixtures folder on the file system. But now we run into a problem. The reason is that the jasmine:bdd and jasmine:test goals look for resources in a different ways. When using jasmine:bdd the path to the folder where the fixtures are located cannot be configured to a folder on the file system. Rather it has to be a resource on Jetty server that serves out the static HTML fixture files. The jasmine:test on the other hand require the fixtures to be in the target folder of your Maven build. This has actually been reported as a bug on the Jasmine Maven plugin web site.

The work-around

So how can we fix this? Unfortunatly there’s no 100% clean solution unless you want to fork the Jasmine Maven project but as a work-around we can make use of Maven profiles. The trick is to set a different fixture path when running the jasmine:test and jasmine:bdd goal. This can be achieved by pre-loading a different script for configuring the fixture directory for each goal. Assume that we have our HTML fixtures in the src/test/javascript/fixtures folder on the file system then these are the two different scripts needed:

file_system_fixtures.js

web_resource_fixtures.js

In our project we run mvn clean install (and thus run the jasmine:test implicitly during test execution phase) much more often than jasmine:bdd and for this reason it’s probably better to configure the latter in a special profile. The first thing to do is to create a Maven build property that points to the file_system_fixtures.js file:

Secondly we alter the preloadSources configuration under Jasmine Maven plugin to load the Jasmine JQuery script and configure the correct fixture folder by running our file_system_fixtures.js script configured by the build property:

Now when running jasmine:test the fixtures will be found on the file system but we still need to make things work for the jasmine:bdd goal. To solve this we create the following Maven profile:

What we do here is to override the jasmine.fixture.setup property to point to our web_resource_fixtures.js script which configures the Jasmine JQuery fixture folder to work in Jetty. Thus whenever you need to use jasmine:bdd you also need to use the bdd profile:

Conclusion

If you’ve read this far you’ve probably seen that it’s not trivial to get Jasmine tests running in Maven, at least not if you want it to work in both headless mode and non-headless mode at the same time. To me this is a big obsticle when trying to convince people to start writing unit tests for Javascript code. These things simply have to work, we need the feedback from our continous integration server and it needs to be simple and fast to use during development. The work-around suggested here is not perfect but at least it’s acceptable once you’ve configured everything. Hopefully the issue will be resolved in Jasmine Maven in the future and I also hope that this blog can lower the barrier to get started with the testing Javascript from Maven somewhat. I know that this is something that’s lacking in many projects.

This Post Has 8 Comments

  1. Johan,
    In our case, we chose to just bail on jasmine:test for the time being. Instead, we created a custom jasmine runner that Selenium then executes, and using the Jasmine api, we report failures into Selenium, which is run as part of our build server. This solution is not ideal, but it works for us. If I wasn’t so stubborn, I would have given up long ago on making that work. ;-).

    Maybe using your solution above, I can get jasmine:test back into our workflow. Or submit a patch to Justin SOMEDAY SOON. Here’s hoping for a break in the schedule!

    Cheers!
    Dehru

  2. Thanks for a nice article.
    I didn’t know about the fixture plugin – everyday you learn something new :-)

  3. Excellent piece of work. I’ve been going around the houses now for quite a while looking at various solutions to exactly this problem. I was trying to avoif the profiles solution but, you have made it as elegant as it can be. Thanks.

    Also confirmed I was not just going mad and doing something wrong.

  4. Wow!!!

    Your trick is amazing, I try to did this on win7, but don’t work as I expected.

    Tks a lot brow!!!

  5. the solution have used that does not require build profiles

    is to create a javascript file called “configureHtmlFixtures.js” and place it the directory that contains your fixtures.

    then contents of the file is below

    (function (name) {
    var scripts = document.getElementsByTagName(‘script’);

    for (var i = scripts.length – 1; i >= 0; –i) {
    var src = scripts[i].src;
    var l = src.length;
    var length = name.length;
    if (src.substr(l – length) == name) {
    // set a global propery here
    jasmine.getFixtures().fixturesPath = src.substr(0, l – length);

    }
    }
    })(‘configureHtmlFixtures.js’);

    then include this script in your preloadSources

    similar files can be created for you css fixtures and json fixtures.

    I hope this is of use to someone

  6. This is great, I have it set-up and running nicely. However, I want to run tests that access assets in sibling modules. Is it possible to start Jetty using the parent folder as the web-root?

  7. Briefly and useful. Thank you a lot!

  8. This is a great article, but could you please share how you configured your spec runner file to include the jasmine-jquery js file and the directory structure you created for your fixtures?

    Thanks!
    David

Leave a Reply

Close Menu