Mock a TypeScript constant different in every Jest test

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.

1 answer

  • answered 2021-01-14 05:08 slideshowp2

    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