Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest mock module multiple times with different values

I have a function that I want to test and this function uses an imported module:

var a = require('./a');

function add(b) {
  return a + b;
}

module.exports = add;

That a module returns a number in this sample, but in my real project I use that as a config object that is changed from time to time manually.

var a = 1;
module.exports = a;

The test for the add function looks like this:

describe('add', () => {

  it('should add the mock number 1 to 2', () => {
    jest.setMock('./a', 1);
    const add = require('./add');
    expect(add(2)).toBe(3);
  });

  it('should add the mock number 2 to 2', () => {
    jest.setMock('./a', 2);
    const add = require('./add');
    expect(add(2)).toBe(4);
  });
});

First test passes, The second test fails because it inherits from the first mock. Is there any way to mock the a module multiple times?

I would like a solution that doesn't imply refactoring the add function and instead focus on mocking that module multiple times. (in my real project that is a config file)

You can play around with the code here: https://repl.it/@adyz/NocturnalBadComma

like image 345
Adrian Florescu Avatar asked Apr 04 '18 11:04

Adrian Florescu


People also ask

How do you mock the same method with different parameters Jest?

You can use jest. mock (line 4) to mock the lang dependency. In the example above, the mock module has a current field which is set to a mock function. You want to test both branches of hello, so you use mockReturnValueOnce to make the mock function return "GL" in the first invocation, and "EN" in the second one.

How do I change the Jest mock function return value in each test?

To mock a function's return value in Jest, you first need to import all named exports from a module, then use mockReturnValue on the imported function. You can use the * as <alias> inside an import statement to import all named exports. Then, you need to chain mockReturnValue off of jest. fn .

What does Jest fn () do?

The Jest library provides the jest. fn() function for creating a “mock” function. An optional implementation function may be passed to jest. fn() to define the mock function's behavior and return value.


2 Answers

Add

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

Final tests

describe('add', () => {

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

    it('should add the mock number 5 to 2', () => {
        jest.setMock('./a', 5);
        const add = require('./add');
        expect(add(2)).toBe(7);
    });

    it('should add the mock number 2 to 2', () => {
        jest.setMock('./a', 2);
        const add = require('./add');
        expect(add(2)).toBe(4);
    });
});

Demo: https://repl.it/repls/TrustingBelatedProprietarysoftware

like image 111
Gigi Avatar answered Sep 18 '22 16:09

Gigi


To add to @Gigi's solution, I created another example, using jest.mock:

In the file multiplier.ts, multiplier is the exported function we want to test:

  // file: multiplier.ts

  import {getNumber} from './get-number'
  const multiplier = (num:number) => num * getNumber()
  export {multiplier}

In the file get-number.ts, getNumber is the module we want to mock:

  // file: get-number.ts

  const getNumber = () => 2
  export {getNumber}

Here is the test:

  // file: multiplier.test.ts

  // import { multiplier } from "./multiplier"  // <-- this will not work
  
  describe("[multiplier]", () => {
    beforeEach(() => {
      jest.resetModules()
    })
  
    it('should mock getNumber so that getNumber return 3', () => {
      const mockReturn = 3
  
      jest.mock( './get-number', () => (
        { getNumber: jest.fn(()=>mockReturn) }
      ))
  
      const { multiplier } = require('./multiplier')
      expect(multiplier(2)).toBe(6)
    })
  
    it('should mock getNumber so that getNumber return 4', () => {
      const mockReturn = 4
  
      jest.mock( './get-number', () => (
        { getNumber: jest.fn(()=>mockReturn) }
      ))
  
      const { multiplier } = require('./multiplier')
      expect(multiplier(2)).toBe(8)
    })
  
    it('should mock getNumber so that getNumber return 5', () => {
      const mockReturn = 5
  
      jest.mock( './get-number', () => (
        { getNumber: jest.fn(()=>mockReturn) }
      ))
  
      const { multiplier } = require('./multiplier')
      expect(multiplier(2)).toBe(10)
    })
  })

Note: for this to work, we need to use require to import multiplier.ts

like image 33
apollo Avatar answered Sep 21 '22 16:09

apollo