Testing with Jasmine

This marks the seventh of GSoC 2016 and a lot of work has been merged since I started working. Looking back at it gives real feeling of accomplishment.

An important part of writing good code is that it is well tested. So that when you start working on a new feature or a fix you ensure that it doesn’t break any functionality by running the tests. Having a good test suite ensures your app has a strong backbone and it also can be extended for further development.

We have been writing rails tests for quite sometime and now we have good test suite for plots2 . But we didn’t have any test framework for testing JavaScript functionalities. So my mentor Jeffrey Warren suggested that we have tests for JavaScript too. We chose the Jasmine framework as it is the most popular JavaScript framework used and it also comes out in different packages for in browser testing and npm package as well as a rubygem as well for headless command line testing powered by phantomjs. And the best thing is it is best suited for Rubyists as the testing pattern is similar to Rspec – the popular Ruby testing framework. Here I am going to brief on how to setup Jasmine using the jasmine-rails gem. Since we were mostly using jQuery for JavaScript functionalities we also used the jasmine-jquery-rails gem to enable use of html-fixtures and some custom matchers.

Setup jasmine-rails

Follow the installation instructions to install the jasmine-rails gem to use it in your test-suite. This should also install the phantomjs gem along with it. But if the package installation fails you follow this documentation given here. A  spec/javascripts  folder will be created where all test files will reside.

You can run tests headlessly using the command

rake spec:javascript

 

How to write Tests ?

Now the most important how to actually write tests? The best place to start is with the jasmine docs. It gives a comprehensive guide to how to write tests. Jasmine tests basically describe a test and set some expectations which are tested against some matcher. All tests are written in spec files which are basically js files that reside in the spec/javascripts folder. Let us take a very simple test. As you can see it is written in a js file jasmine_spec.js


describe("A suite", function() {
it("contains spec with an expectation", function() {
expect(true).toBe(true);
});
});

view raw

jasmine_spec.js

hosted with ❤ by GitHub

Here the describe() function start a test description with a string and a function that contains a block of code. The it block also starts with a string and a function that contains a code block that contains expectations. The describe block basically tells the bigger story. And the it block tells the smaller individual stories that need to be tested. The expect() functions defines the expectation that is to be made. It can contain any instance or message. Basically any variable or method that returns something should go in it. The expect()function goes with a matcher chained with it. Each matcher implements a boolean comparison between the actual value and the expected value. It is responsible for reporting to Jasmine if the expectation is true or false. Jasmine will then pass or fail the spec. Here toBe() is a matcher.

Faking Ajax Calls

Now there are Ajax calls in applications that require server side requests. But depending on server responses makes the test suite slow and also leads to test failures when offline. So to test Ajax we need to fake Ajax calls using mock-ajax. You can simply copy paste the code in this link and put it in a helpers/mock-ajax.js file that goes inside the spec/javascripts folder. To mock ajax calls across a test suite you need to use install() and uninstall() in beforeEach()and afterEach() blocks in the beginning of the describe block as explained in the documentation. This sets up jasmine-ajax across the test suite. You can have a look at the jasmine-ajax documentation to have an idea on how to fake ajax calls.

Basically what happens in the entire process is you make or trigger a Ajax request first. Then you need to “Spy” on the Ajax call and return a fake Ajax response.  After that you need to test that with the expectation. A Spy is nothing but a function that helps faking the response. It is similar like a stunt double of an actor who fakes for the actor for a shot in a movie! You can learn more about Spies here. I was using jQuery and was using the .ajax() function for ajax calls so i preferred this stackoverflow answer to fake the ajax response.

Now you have been thinking what’s the point of testing if we actually setup the fake response  ourselves and test the same. Its definitely going to pass! Well  it’s not going to pass unless you have your Ajax call working properly. The entire point is not testing the response but whether the Ajax call is actually triggered on executing the action. The response is tested in the server framework, here, the Rails test suite.

Using HTML fixtures

When you are testing JavaScript in a web application you must have it associated with some html element may its a button or a link. What you want is to test it against some event like a hover or a button press specifically those associated with an Ajax call. What you need to do is to create a html file with that specific element like the button or link similar to what you have written in the actual page and load it in the test suite. HTML fixtures go in a separate fixtures directory inside the spec/javascripts directory. Here is a sample fixture I wrote .


<ul class="btn-group">
<li rel="tooltip" title="Helpful? Like it and get updates!" class="btn btn-default btn-sm btn-like" node-id="1" id="like-button-1"><span id="like-star-1" class="fa fa-star"></span> <span id="like-count-1">1</span></li>
</ul>
<script>
jQuery(document).ready(function() {
$('#like-button-1').on('click', clickliked);
})
</script>

view raw

unlike.html

hosted with ❤ by GitHub

As you can see I also associated the event associated with the button so that I can trigger the button press in the test.

To load the fixtures include the fixtures path at the top of the describe block

jasmine.getFixtures().fixturesPath="../../spec/javascripts/fixtures";

Also if you are using jasmine-jquey you need to preload the fixtures by including this line

preloadFixtures('unlike.html')

Finally load the fixture at the beginning of the specific test in the it block

loadFixtures('unlike.html');

Now you can use the html elements in the test. Like you can trigger the button click using

$('#like-button-1').trigger('click');

That’s how you use fixtures in test.

Whenever you have a problem in testing try debugging using a console.log() message. That helps you in figuring where you are going wrong in the test.

Here is how a spec file would look. You can find my work on this in plots2 PR #618.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s