RoboKozo
RoboKozo

Reputation: 5062

Mocking require statements with Jest

sum.js

module.exports = function sum(a, b){
    return a + b;
};

Thing.js

var sum = require("./sum");

module.exports = class Thing {
    add(a, b){
        return sum(a, b);
    }
}

Thing.test.js

test('1 + 2 = 3', () => {
    //Arrange
    var Thing = require('./Thing');
    var thing = new Thing();

    //Act
    var result = thing.add(1, 2);

    //Assert
    expect(result).toBe(3);
});

test('sum mocked', () => {
    //Arrange
    jest.mock('./sum', () => {
        return jest.fn(() => 42);
    });

    var Thing = require('./Thing');
    var thing = new Thing();

    //Act
    var result = thing.add(1, 2);

    //Assert
    expect(result).toBe(42);
});

How can I mock the sum 'require' dependency when testing? I get the following error.

sum mocked

    expect(received).toBe(expected)

    Expected value to be (using ===):
      42
    Received:
      3

What's interesting if I run each test individually with .only, they both work just fine on their own.

In the past I've used proxyquire to do things like this but I'd like to avoid it if possible.

Upvotes: 24

Views: 39738

Answers (3)

Ryan Vice
Ryan Vice

Reputation: 2181

Taken from the Jest Docs.

beforeEach(() => {
  jest.resetModules();
});

test('moduleName 1', () => {
  jest.doMock('../moduleName', () => {
    return jest.fn(() => 1);
  });
  const moduleName = require('../moduleName');
  expect(moduleName()).toEqual(1);
});

test('moduleName 2', () => {
  jest.doMock('../moduleName', () => {
    return jest.fn(() => 2);
  });
  const moduleName = require('../moduleName');
  expect(moduleName()).toEqual(2);
});

https://facebook.github.io/jest/docs/en/jest-object.html#jestdomockmodulename-factory-options

Upvotes: 10

Leonardo Moreno
Leonardo Moreno

Reputation: 172

I have the feeling that mocking works per test file. Don't ask me why ¯\_(ツ)_/¯

The approach that worked the best for me was to set the tests like this:

// sum.test.js
//Arrange
const sum = require('./sum');

test('1 + 2 = 3', () => {
    //Act
    const result = sum(1, 2);

    //Assert
    expect(result).toBe(3);
});

And:

// Thing.test.js
//Arrange
const Thing = require('./Thing');

// jest.mock are hoisted so you can keep imports/require on top
const sumSpy = jest.fn(() => 42);
jest.mock('./sum', () => sumSpy);

test('Thing', () => {
    const thing = new Thing();

    //Act
    const result = thing.add(1, 2);

    //Assert
    expect(sumSpy).toHaveBeenCalledTimes(1);
    expect(result).toBe(42);
});

You can even provide different mock implementations per test with something like:

sumSpy.mockImplementation(() => NaN);

Upvotes: 6

RoboKozo
RoboKozo

Reputation: 5062

In the test, I added

beforeEach(() =>  {
    jest.resetModules();
});

and the tests passed as expected.

Upvotes: 21

Related Questions