2

I'm struggling to mock a constant with Jest on a per test basis. I have it working with the code below, but the mock is "static" - I can't mock it differently for each test.

Code:

// allowList.ts
export const ALLOW_LIST = {
  '1234': true
};
// listUtil.ts
import { ALLOW_LIST } from './allowList.ts';

export const checkList = (id: string) => {
  if (ALLOW_LIST[id]) return true;
  return false;
};

Test (working):

// listUtil.test.ts
import { checkList } from './listUtil';

jest.mock('./listUtil', () => {
  return {
    '5678': true
  };
});

test('in list', () => {
  expect(checkList('5678')).toBe(true);
});
test('not in list', () => {
  expect(checkList('1234')).toBe(false);
});

What I would like (not working):

// listUtil.test.ts
import { checkList } from './listUtil';

test('in list', () => {
  jest.mock('./listUtil', () => {
    return {
      '5678': true
    };
  });
  expect(checkList('5678')).toBe(true);
});
test('not in list', () => {
  jest.mock('./listUtil', () => {
    return {
      '9123': true
    };
  });
  expect(checkList('1234')).toBe(false);
});

Is what I'm trying to do possible? This post is very similar and appears to work when mocking functions, but I'm having the same issue as the commenters of the accepted answer. I think I'm just not understanding how Jest performs mocking under the hood. I believe the working version works because the mock is hoisted and basically overwrites the real implementation, but I'm not sure how or if I can achieve that in each test.

I think one option would be to expose the ALLOW_LIST via a function:

// allowList.ts
const ALLOW_LIST = {
  '1234': true
};
export const getAllowList = () => ALLOW_LIST;

and mock that, but am wondering if that's necessary.

Lin Du
  • 88,126
  • 95
  • 281
  • 483
Tim S
  • 5,023
  • 1
  • 34
  • 34

1 Answers1

2

You can use jest.doMock(moduleName, factory, options) to mock a module differently for each test.

E.g.

allowList.ts:

export const ALLOW_LIST = {
  '1234': true,
};

listUtil.ts:

import { ALLOW_LIST } from './allowList';
console.log('ALLOW_LIST: ', ALLOW_LIST);

export const checkList = (id: string) => {
  if (ALLOW_LIST[id]) return true;
  return false;
};

listUtil.test.ts:

describe('65712158', () => {
  beforeEach(() => {
    jest.resetModules();
  });
  it('should in list', () => {
    jest.doMock('./allowList', () => ({ ALLOW_LIST: { 5678: true } }));
    const { checkList } = require('./listUtil');
    expect(checkList('5678')).toBeTruthy();
  });

  it('should not in list', () => {
    jest.doMock('./allowList', () => ({ ALLOW_LIST: { 9123: true } }));
    const { checkList } = require('./listUtil');
    expect(checkList('1234')).toBeFalsy();
  });
});

unit test result:

 PASS  examples/65712158/listUtil.test.ts
  65712158
    ✓ should in list (2517 ms)
    ✓ should not in list (2 ms)

  console.log
    ALLOW_LIST:  { '5678': true }

      at Object.<anonymous> (examples/65712158/listUtil.ts:2:9)

  console.log
    ALLOW_LIST:  { '9123': true }

      at Object.<anonymous> (examples/65712158/listUtil.ts:2:9)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |     100 |      100 |     100 |     100 |                   
 listUtil.ts |     100 |      100 |     100 |     100 |                   
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        5.03 s
Lin Du
  • 88,126
  • 95
  • 281
  • 483
  • Awesome - thank you! I actually did try this, but was missing the `const { checkList } = require('./listUtil');` statements – Tim S Jan 14 '21 at 19:34