Give Jest Another Go

Jest is a JavaScript testing framework developed by Facebook, with the tagline ‘Painless JavaScript Testing’. However, up until recently, it could be argued that it didn’t live up to this promise.

When released, one of the main selling points of Jest was its automocking feature, which automatically mocks any require calls (or ES6 imports, given they are transpiled). While their intentions were good, this is perhaps where Jest went wrong, as this hidden complexity seemed too magical for developers, and in a lot of cases, didn’t work as intended and caused confusion. Secondly, a large number of complaints were raised about the slowness of tests using Jest, which was seen as a deal breaker for a lot of development teams. Finally, documentation was lacking, general stability wasn’t great, and dependencies on older technologies were also questioned. All-in-all, Jest did not gain much adoption outside of Facebook and garnered a pretty negative view amongst developers. This is all despite the massive growth and widespread adoption of React, another Facebook offering, which seemingly should have gone hand-in-hand with the adoption of Jest.

A few months ago, in conjunction with the open-source community, Facebook decided to invest more time and effort into improving Jest, starting with their first ‘stable’ release, version 11.0.0, in April 2016. This release added the ability to turn off automocking globally, in addition to introducing some much needed performance fixes and a range of other features. Since then, Jest has gone from strength-to-strength, with 4 more major releases, resulting in the addition of new, innovative features, while addressing some of the pain-points developers experience when using it. Perhaps the most major of these changes came in version 15 — the decision to disable automocking by default, showing Facebook’s willingness to admit mistakes and work with developers to improve Jest.

Having personally not used Jest for over a year, instead working mainly with a combination of Karma, Jasmine and Webpack, I was blown away when I came back to using Jest recently due to its features and ease-of-use. Below is a list of some of the great features I’ve come across during my reacquaintance:

Ease-of-Install

Installation is as simple as running npm i -D jest babel-jest (babel-jest for if you’re using Babel and ES6) and adding a few lines to your package.json file, which depending on your setup and needs, could be as simple as adding “test”: “jest” to your scripts section. This greatly contrasts with the reams of plugins, associated libraries and configuration needed for testing with Karma.

If you’re also using Webpack and use non-standard file type imports, such as CSS files, the Jest documentation has a great section on the setup needed.

Code Coverage

A lot of work has been put into providing code coverage out-of-the-box in Jest, which is as simple as running the jest command with a coverage flag. Again, this contrasts with Karma, which can be a complete pain to set up correctly, especially when combined with ES6 and Webpack. Code coverage for untested files has also been recently added to Jest, allowing for a greater insight as to the state of a project’s code coverage.

Running Tests on Changed Files Only

This is one of the major benefits of Jest in my opinion — the ability to run tests on only files which have been changed. Jest does this via static analysis of imports, so it is smart enough to also run tests on files which have the file that has been changed as a dependency somewhere in its dependency tree. On large codebases with thousands of tests, this can provide a great productivity boost.

Speed

As mentioned, a lot of work has gone into improving the speed of Jest, both for small and large projects, with great results:

This, combined with the ability to run tests on only what’s changed, should mean that any slow test suites should no longer be the fault of Jest. While the actual test run speed was not an issue with Karma, I often found that the Webpack compile step took too long on larger projects— this is addressed by Jest with intelligent use of caching built files, and then further boosted by running tests concurrently.

Mocking

Personally, I prefer to be more explicit when mocking to gain maximum control over my tests, but Jest caters for all ranges of mocking, from the automocking functionality, to writing static mocks in a file alongside the application code, to mocking individual functions and values within your tests. It works by hijacking require statements and replacing them with your specified mocked versions, and despite there being libraries out there to do this, such as babel-rewire, I’ve found Jest to work better out-of-the-box and have a much nicer syntax.

Async Testing

Asynchronous testing also works out-of-the box, whereby you can simply return a promise to mark a test as asynchronous, or use async/await within your tests — no plugins or done callbacks needed!

Snapshot Testing

This is one of the most recent innovations around Jest and React, and a great addition to a developer’s testing arsenal. Its aim is to reduce the amount of time developers spend writing tests, whilst still providing solid coverage for components. It works by saving a snapshot of a rendered component to a file, which can then be compared to the current version within a test. It displays any differences clearly, which can then be actioned by the developer. More details can be found in this video directly from Facebook:

A walkthrough of React snapshot testing

With all of the changes made to Jest in the recent months, it is clearly now living up to the ‘Painless JavaScript Testing’ tagline. Jest is now being used in Facebook’s community-led, semi-official React bootstrapping project, create-react-app, and has in general caused a great deal of excitement and interest within the React community, with people willing to give it a second-look and liking what they see.

Not only has the library improved greatly, but Facebook are doing an excellent job of engaging with the community, for example this excellent GitHub post by Christoph Pojer, taking responsibility on behalf of Facebook for Jest’s shortcomings and clearly outlining its future direction. I’ve also seen this kind of engagement across React, and more recently Flow (Facebook’s take on static typing for JavaScript) too, which makes me more confident in buying into Facebook’s technologies.

Over time, I believe Jest can become the de-facto choice for testing with React, then possibly move on to make a greater dent in the general JavaScript testing realm, provided the negative perceptions, due to its early shortcomings, can be changed. Regardless, I believe it is going in the right direction, is in great hands, and I for one will be keeping a keen eye on how it develops in the future.