Testing an AngularJS app with Jest

swiip

Matthieu Lux

Posted on August 23, 2019

Testing an AngularJS app with Jest

I will not try to write the ultimate guide to test an AngularJS app with Jest, this article is only my feedback after trying Jest on my project.

TL;DR It works pretty well :)

First, let me add some context. I was a huge AngularJS fan and slowly drifted to React. That’s probably why I was aware of Jest and wanted to try it. Still, my biggest ongoing project uses AngularJS, it’s the member part of the new data exchange plateforme: Dawex (https://www.dawex.com/)

Also, I’m one of the developers of the Yeoman Fountain generator (fountainjs.io) and as such, pretty familiar with the use and configuration of new Web tooling.

The app is, I think, a pretty modern AngularJS app. It’s fully component oriented with AngularJS 1.5.x and uses NPM, Webpack and Babel for tooling. We even added some new stuff like RxJS and Redux.

The test environment is based on Karma and Jasmine. We use the karma-webpack plugin and tests are running in Chrome since we encountered some problems with PhantomJS.

Tests work with watching mode and coverage but there are some pain points remaining. The test bootstrap is very slow as Webpack has to build the whole bundle. Then, it starts a real Chrome (which need the xvfb trick on CI) and we didn’t find a way to have proper source-mapping (through Babel / Webpack / Karma) for proper error stacktraces. Finally but perhaps the most important, the global runtimes seems to be slow (real figures comes next).

Here’s an extract of the Karma config.

Trying Jest

In this context, I read about jsdom and thought that it could be huge to remove the real browser part since pure JavaScript implementations differences are not an every day problem anymore. jsdom is a Node library which is able to simulate the context of a Browser with its API in a pure Node execution.

I was considering trying AVA with jsdom but also looked at the testing framework used by the React team at Facebook: Jest. I was bothered at first because it looked as a nice integration of jsdom for frontend tests but I couldn’t find a blog post about using it outside the React world. As I noticed that there was no reference of React on the Jest front page, I concluded that the solution means to be framework agnostic. So, I decided to give it a try.

The PoC process was incredibly simple. I was sure I would have to deal with some AngularJS dependency injection edge cases or with the Jest mocking system. For a reason or another, I was quite sure I would have to refactor, even for a simple thing, every single test.

In reality, I only had to point my source folder and write a tiny script which imported my tests common lib and my tests were passing.

The biggest part of this script was to mock localStorage API as it’s not yet supported in jsdom.

Figures and facts

Even if I am pretty convinced by full plugin architectures like the Karma one, the drawback on the Karma configuration is obvious: 35 lines of code, not trivial for the Karma configuration against 4 lines in package.json for Jest. (I’m not counting the jest init script as Karma / Webpack needed one too).

According to coverage reports, the project counts 5917 JavaScript lines and 43.91% (2598) is covered (56000 actual source LoC). It could be better, for sure, but at least, it’s a real world example. There is also 103 tests suites and 363 tests.

Let us speak about execution times. For the execution of all tests once without coverage, Karma takes 47s in total. The bootstrap / bundling part is the most important as Chrome only takes 10s to execute tests once everything is ready. Jest, after a bit of learning (5 executions) only takes a total of 18s.

Yep! 47s for Karma against 18s for Jest! Same code, same tests.

With coverage, the bootstrap time of Karma is less problematic. Karma takes 100s against 80s for Jest.

The watch mode is harder to compare. Karma / Webpack has a strange delay on the change detection and triggers a new execution which is not measured. I manually counted 7s followed by a full pass at 10s. Using Jasmine fdescribe or fit, the run can fall at 1s. Jest works very differently, it only runs the modified test and takes approximatively 1s to detect the change and another one to execute it.

A final but important point is that with the stack Karma / Webpack / Babel we have never figured out a good solution to have a robust source-mapping in JavaScript stack traces. To be honest, sometimes, we had references, other times not. Jest is far more straightforward, The error reports are just perfect with only references to our Babel source code et good line numbers.

Conclusion

Jest popularity is shamefully restricted to the React world and really deserves to cross that frontier since it’s a very good agnostic solution for frontend testing.

I didn’t find any reference of Jest outside React before writing this article, I hope this will be the first.

I think, but some could disagree, that modern frontend unit testing doesn’t really need anymore real browser testing as most Web API are quite stable nowadays.

Configuration, performances and features are really good in Jest and the “Developer eXperience” is better than with Karma. And yet, I only used it as a test environment and didn’t played with the mocking features!

The only problem I see is that jsdom is not working right now with Zone.js and then not working with Angular 2. I really hope that it shall be fixed even if I don’t see motivation on any side (jsdom or Angular).


💖 💪 🙅 🚩
swiip
Matthieu Lux

Posted on August 23, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Testing an AngularJS app with Jest
angular Testing an AngularJS app with Jest

August 23, 2019