Search code examples
javascriptnode.jsunit-testingjestjscommonjs

Trying to mock a named commonjs module in Jest


I've searched for days on how to accomplish this and nothing i've tried has worked. I have an authenticate module that I share among other modules, and I'm wanting to create a mock for it using jest, in my my unit tests. Here's what i have currently:

authenticate.js

const got = require('got');

const authenticate = async (options) => {
  let res = ...api request using got library to retrieve token...

  return { data: res.access_token };
};

exports.authenticate = authenticate;

schedule.js

const schedule = async (options) {
  // import authenticate library
  const authenticate = require('./authenticate');

  const login = await authenticate.authenticate(options);

  const result;

  ...stuff to set result...
  result = {
    data: 'success'
  };

  return result;
};

exports.schedule = schedule;

shedule.test.js

const scheduler = require('./schedule');

test('[schedule]', async () => {
  const options = {...};

  jest.mock('./authenticate', () => ({
    authenticate: jest.fn()
  }));

  const authenticate = require('./authenticate');

  authenticate.authenticate.mockReturnValue({
    data: mockOptions.access_token
  });

  const moduleUnderTest = await scheduler.schedule(options);

  expect(moduleUnderTest).toEqual({ data: 'success' });
});

Solution

  • You SHOULD NOT use jest.mock(moduleName, factory, options) in function scope, it should be used in MODULE scope. Besides, for your case, I don't see any reason to use rewire module.

    E.g.

    authenticate.js:

    const got = require('got');
    
    const authenticate = async (options) => {
      let res = 'got';
      return { data: res.access_token };
    };
    
    exports.authenticate = authenticate;
    

    schedule.js:

    const schedule = async (options) => {
      const authenticate = require('./authenticate');
      const login = await authenticate.authenticate(options);
      const result;
      result = {
        data: 'success'
      };
    
      return result;
    };
    
    exports.schedule = schedule;
    

    schedule.test.js:

    const scheduler = require('./schedule');
    
    jest.mock('./authenticate', () => ({
      authenticate: jest.fn(),
    }));
    
    describe('62074254', () => {
      test('[schedule]', async () => {
        const authenticate = require('./authenticate');
        const mockOptions = { access_token: '123' };
    
        authenticate.authenticate.mockReturnValue({
          data: mockOptions.access_token,
        });
        const options = {};
        const moduleUnderTest = await scheduler.schedule(options);
    
        expect(moduleUnderTest).toEqual({ data: 'success' });
        expect(authenticate.authenticate).toBeCalledWith({});
      });
    });
    

    Unit test results with coverage report:

     PASS  stackoverflow/62074254/schedule.test.js (10.742s)
      62074254
        ✓ [schedule] (6ms)
    
    -------------|---------|----------|---------|---------|-------------------
    File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    -------------|---------|----------|---------|---------|-------------------
    All files    |     100 |      100 |     100 |     100 |                   
     schedule.js |     100 |      100 |     100 |     100 |                   
    -------------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        12.202s