Keep calm and test with Jest

Maykol Purica
Wolox
Published in
4 min readAug 26, 2019

--

NodeJS Automated testing tips with Jest

Jest has become a popular option for unit testing in NodeJs and JavaScript in general for its robustness and its simplicity allowing us to get started without any previous configurations nor installing any other library. It has basically everything you need to make assertions mock and spy and you don’t even need to require it.

Our first tests

As we see in the example, a test is basically a call to the `test( )` function. It receives two parameters: the description of the test and a function that wraps the assertion. We can wrap several tests in a describe call for organization purposes and to write more verbose logs when running the tests.

We use the expect function which receives the test subject as a parameter and exposes the matcher functions. This allows us to check our assertions. In this case, the toEqual function tests if the result of calling foo( ) equals the object {a: ‘foo’ }. If our test subject is an async function, we can just use the async/await syntax.

Notice we don’t need to require either test nor expect. This is because jest loads its dependencies by itself when running the tests. The same applies to the jest object that we’ll see later in the mocking section.

Mocking services

Normally, our services or serverless functions will access resources from another domain using HTTP requests and since unit tests should be fast and isolated we need to mock those requests. One of the more common and popular choices for this is the use of nock, which allows us to capture and mock any HTTP request in a very straightforward way.

In the example what we’re telling nock is that when a post request is performed to that URL and endpoint it should return a 200 response and the given body. This way we can ensure our code will receive the same response each time for the same test scenario, without the need for the actual HTTP request to reach to external world.

As a good practice, requests to external APIs or databases are wrapped in what we call service functions or service modules. So if they’re not the actual test subject but called by it instead, why don’t we just mock them?

So to be more clear: let’s imagine we have a timer-triggered azure function that hourly fetches some orders from our API and then gets information from a third party API, for what we have made a service function called getInfoFromThirdPartyAPI.

Our code could be something like this:

In our test, we can include scenarios such as: when there are no orders to track, when the endpoint is not available, when the third party API responds with an error (expected or unexpected). For this we’ll make those functions injectable, meaning that they can be received by the main module as parameters. This will allow us to mock the implementation as needed in our test suit to fit the different scenarios.

Notice we’re adding a default implementation for each so we don’t need to perform the actual dependency injection in the real code.

And now we’ll do it in our tests:

As you can see, we mock the functions and inject them to our test subject using jest.fn(). We can pass the implementation we want to be executed, which is very similar to what we did with nock library. In case the mocked function doesn’t return anything or its return value is not used we can just use jest.fn() in its more basic form since it uses the identity function as a default.

Spying on mocked services

You may ask yourself why to use jest.fn() and not just use a function for example

getOrders: () => Promise.resolve(),

The point is it lets us spy on our test subject to check if it would call our mock functions (in case we need that level of detail). To do that we are using the same previous example:

We could even check the values passed as parameters to our mocked functions during the execution, like this:

This will check if the function getOrders was called and received the object { limit: 100 } as the first parameter.

Mocking objects injected by runtime or framework

Sometimes our test subject receives parameters passed automatically by the framework or runtime like express’ request and response objects or azure runtime context object. So if our test subject uses functions or attributes from those objects when we run our tests there’s going to be an exception similar to Cannot read property ‘foo’ of undefined. In this case, we need to mock the Azure context object. Let’s create a test/defaultContext.js file:

This allows us to execute defaultContext.log(), defaultContext.log.info(), defaultContext.log.error() and defaultContext.done().

Making assertions from a mocked object

Another approach is to use a mocked object injected to our test subject, in this case azure functions context object, and make the assertions from within it. This way when the mock is called the assertions are checked.

Conclusions

  • Azure functions can be unit tested just as any other NodeJs code.
  • Jest is a robust easy-to-use test framework that allows us to start testing without any configuration, and there is no need to install plugins or other libraries.
  • Jest makes mocking and spying on objects used by our test subject easy.
  • We can use jest.fn( ) as the value of the attributes in objects we want to mock.

--

--