How to setup a Unit Test environment for an AngularJS application
Exploring Unit Testing(Spec) Capabilities
AngularJS has been designed with testing in mind meaning that it’s easier to unit test.
“With Angular we try to make it easy for you to do the right thing, and so we provide dependency injection for your XHR (which you can mock out) and we created abstractions which allow you to sort your model without having to resort to manipulating the DOM. So that in the end, it is easy to write a sort function which sorts some data, so that your test can create a data set, apply the function, and assert that the resulting model is in the correct order. The test does not have to wait for the XHR response to arrive, create the right kind of test DOM, nor assert that your function has mutated the DOM in the right way.” https://docs.angularjs.org/guide/unit-testing
When we did our initial research we found there are a range of Unit Testing options. The ones we came across were:
We decided to choose Jasmine as it’s recommended in the Angular docs and there is well documented help across the web. Having spoken to people within the Tech Community it also had some glowing reviews from them.
In order to confirm that Jasmine was the right choice in our context we built a simple proof of concept showing how it could be used to write Unit Tests(or specs as they are called within Jasmine). This was actually a task i took up so that i could get first hand exposure to how the developers would be writing tests. It was surprisingly easy to write the tests even for a tester like myself. The syntax is easy to read and the assertions, or matchers as they are called in Jasmine world, were easy to use. There were also lots of flexibility including the option of creating your own Custom matchers and using mocking such as Spies.
Getting the tests to run locally
Once we had decided on Jasmine it was time to investigate how to run them locally so that the team could start writing unit tests. When we first started looking into how to do this, there was limited cohesive information across the web on the best approach. The basic examples for Jasmine show how you can run the tests through the SpecRunner which is provided as default when you obtain Jasmine.
This uses all the required .js files and runs the tests when the page loads; very simple but not really suitable within an CI environment. So we did some more research and were initially focusing our research around the SpecRunner and how we could expand it to meet our needs, but then we found Karma.
Karma is a Node Package which runs through NodeJS. Let me just clarify the tools in this line before we go any further:
If you haven’t heard of NodeJS you can check it out on the official site. They describe it as:
This is where we get Karma from and its role is to act as our Test Runner aswell as a few other cool things. Karma was actually built by the AngularJS team because in their own words:
“On the AngularJS team, we rely on testing and we always seek better tools to make our life easier. That’s why we created Karma – a test runner that fits all our needs.” Karma
So we started to look into Karma but we hit a roadblock. Karma and other node packages are downloaded from the internet by NodeJS but this meant that our corporate network was blocking us from doing this. Luckily through NodeJS you can specify a proxy and once we’d done this we were in business.
Now alongside Karma there were several other node packages we have used to support us, these are:
Once we had everything installed on our local development machines we had to configure karma so that it knew where the application and test(specs) files were, what browsers we wanted to run against and our reporting options. The Karma site has some good advice on how to setup your configuration.
Now it’s time to run the tests locally. All we do is send the command – ‘karma start’
Boom! We are in business, our sample Jasmine Tests are running.
Once you have NodeJS installed with all the relevant packages it is super easy to run the tests. What I really liked was the file watcher capability. Karma watches your application and test files and when you make any changes the tests automatically run giving instant feedback, nice! You can have your Karma window open on a second(or third) screen running all the time. This is super amazing when developing.
Running through Jenkins
Once we were happy everything was running locally it was time to get setup on our CI tool Jenkins. One thing we noticed is there seems to be a vast amount of people using AngularJS on Linux systems meaning some of the techniques and approaches are not relevant for Windows based times like ours. One specific example is the NodeJS plugin for Jenkins. We couldn’t get it to work on our Windows box, there’s also a few threads from around the web with people who have faced the same problem. According to the official page it’s just the auto installer that doesn’t work but we couldn’t get the other feature of the plugin to work either. To be honest, this was no big deal. We installed NodeJS directly onto our Jenkins box and got all the packages mentioned earlier installed.
There is one additional Node Package which is really important when it comes to setting up your CI process. When running Jasmine Tests through Karam by default there isn’t any kind of output that Jenkins can easily read to determine a pass or fail. There is an easy solution though, the Karma jUnit node package. This generates an xml file of your test results which can then be read easily by Jenkins.
The final task was to setup our Karma.conf.js on the build server. This was slightly different to our local development environment in three ways:
1. The location of the files
2. We switched off the file watcher
3. We told karma to close after each run
Now all the node packages were installed and our configuration complete on our Jenkins server it was an easy task to configure a new job. We just added some Windows Batch Command build tasks to start NodeJS and run Karma. These commands would run the tests and generate the test-results.xml file which we told Jenkins to read. Now this meant that our tests would run through Jenkins on each commit providing us with fast regular feedback. It should be noted that we’ve found these tests to be extremely fast.
Unit Test Coverage
The final thing we did was to get some Test Coverage reports generating. We installed a node package called Istanbul. We added some additional tasks to our Jenkins build to publish the HTML reports generated by Istanbul. One problem we needed to overcome was that Istanbul produces HTML files in more then one place so when it comes to publishing them on Jenkins the links to sub pages are all messed up. We created a simple PowerShell script to move all the HTML files to a single folder and automatically amend the links so they go to the right location.
So in summary we have:
Karma acting as our test runner
Jasmine to write the tests(specs)
Jenkins as our CI Server
Istanbul as our Code Coverage tool
This means we now have an environment to create Unit Tests to provide quick and regular feedback to the team all the way through the development process.
If you need any help getting any of this setup in your team give me a shout and i’d be more than happy to help.