how properly mock/test constructor with Jest

I'd like to test Module2 constructor as well as other its functions. What is the proper way to mock Module2 constructor without breaking testFunc1, testFunc2 to test with Jest.

// ****************************************
// Module 1 component
class Module1 {
  init() {
    // ........
  }
}

module.exports = new Module1()


// ****************************************
// Module 2 component
const module1 = require('./module1')

class Module2 {
  constructor() {
    try {
      module1.init()
    } catch (err) {
      console.log('error')
      process.exit(1)
    }
  }

  testfunc1 = () => {
    // ........
  }

  testfunc2 = () => {
    // ........
  }
}

module.exports = new Module2()

1 answer

  • answered 2021-04-15 02:04 slideshowp2

    You are testing module2, so you need to mock module1 rather than module2.

    You can use jest.doMock(moduleName, factory, options) to mock module1 module. After mocking, require the module2. Besides, you should use jest.resetModules() to reset the module cache from require.cache object before mocking with different implementations.

    E.g.

    module1.js:

    class Module1 {
      init() {}
    }
    
    module.exports = new Module1();
    

    module2.js:

    const module1 = require('./module1');
    
    class Module2 {
      constructor() {
        try {
          module1.init();
        } catch (err) {
          console.log('error');
          process.exit(1);
        }
      }
    
      testfunc1 = () => {};
    
      testfunc2 = () => {};
    }
    
    module.exports = new Module2();
    

    module2.test.js:

    describe('67099526', () => {
      beforeEach(() => {
        jest.resetModules();
      });
      it('should initialize module1 correctly', () => {
        const module1instance = { init: jest.fn() };
        jest.doMock('./module1', () => {
          return module1instance;
        });
        require('./module2');
        expect(module1instance.init).toBeCalledTimes(1);
      });
    
      it('should handle error', () => {
        const exitSpy = jest.spyOn(process, 'exit').mockImplementation();
        const module1instance = {
          init: jest.fn().mockImplementationOnce(() => {
            throw new Error('initialize module1');
          }),
        };
        jest.doMock('./module1', () => {
          return module1instance;
        });
        require('./module2');
        expect(module1instance.init).toBeCalledTimes(1);
        expect(exitSpy).toBeCalledWith(1);
      });
    });
    

    unit test result:

     PASS  examples/67099526/module2.test.js (11.508 s)
      67099526
        ✓ should initialize module1 correctly (8819 ms)
        ✓ should handle error (18 ms)
    
      console.log
        error
    
          at new Module2 (examples/67099526/module2.js:8:15)
    
    ------------|---------|----------|---------|---------|-------------------
    File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ------------|---------|----------|---------|---------|-------------------
    All files   |     100 |      100 |   33.33 |     100 |                   
     module2.js |     100 |      100 |   33.33 |     100 |                   
    ------------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       2 passed, 2 total
    Snapshots:   0 total
    Time:        13.743 s