Unit testing with Jest (Part 2)

Testing Asynchronous Code

A lot of code in JavaScript run asynchronously: for example every time we want to make an API call or fetch some data. There are a few ways to test these situations with Jest.

Let’s say we want to test api.login function.

import * as api.login from '../../src/auth/api.login';

describe('API Auth', () => {

  describe('login', () => {

    it('should successfully login user', async () => {
      const user ='QWERTY';
      const password ='12345';

      const response = await api.login(user, password);
      expect(response).toEqual('You have successfully logged in!');
    });
  });
});

An actual implementation of this function would go to login server and compare user’s login and password, but we don’t want a real call being made. It would be slow, and we’d need an API instance to be available for testing. Instead, we want to trick our system into thinking that a real Response object has been returned from our call to api.login, and so long as that object looks and behaves just like a real Response object would, our code can interact with it just as if it were the real deal.

This is the process of “mocking”.

To start mocking in Jest is super easy. We just declare jest.mock('../path/to/module/to/mock/here.js'), and Jest will automatically replace the real module with a mocked equivalent.

but because we don’t want to go to the network in our test, we are going to create a manual mock for our api.login.js function in the __mocks__ folder. It could look something like this:

function api.login(user, password) {
  return new Promise(function(resolve, reject) {

    if (user === 'QWERTY' && password === '12345') {
       resolve('You have successfully logged in!');
    } else {
       reject ('Wrong username or password!');
    }
}

Now let’s write a test for our async functionality.

jest.mock('../api.login');

describe('API Auth', () => {

  describe('api.login', () => {

    it('should successfully login user', async () => {
      const user ='QWERTY';
      const password ='12345';

      const response = await api.login(user, password);
      expect(response).toEqual('You have successfully logged in!');

      // we can also get rid of response const:
      // await expect(api.login(user, password)).resolves.
      // toEqual('You have successfully logged in!');
     });

    it('should not successfully login user', async () => {
       const user ='QWERTY';
       const password ='54321'; 
       const response = await api.login(user, password); 
       expect(response).toEqual('Wrong username or password!');

       // we can also get rid of response const:
      // await expect(api.login(user, password)).rejects.
      // toEqual('Wrong username or password!');
     })
 }); 
});

Aside from allowing us to fake the response, defining api.login as a Jest mock function also gives us a bunch of additional useful features from the .mock property.

By accessing the .mock property of our api.login function after it has been used, we can ensure that – for example – the arguments passed toapi.login resulted in calls with our expected arguments. The full list of mock methods we can call you can find here.

Advertisements

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 )

Google+ photo

You are commenting using your Google+ 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