Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking and testing require.resolve calls in jest

I want to mock a node's built-in function require.resolve in jest test suite. Here a working example of a problem on repl.it and the code itself:

Test subject (as an example):

const requirer = () => {
  try {
    return require.resolve('./add')
  } catch (error) {
    console.error('failed to find a module')
  }
}

module.exports = requirer

Test suite:

const requirer = require('./requirer')

describe('attempt to mock require.resolve', () => {
   it('does not work', () => {
     require.resolve = jest.fn(arg => `./${arg}`)
     console.log(
       'is require.resolve mocked',
       jest.isMockFunction(require.resolve)) // will say true

     requirer()

     expect(require.resolve).toHaveBeenCalledTimes(1)
     expect(require.resolve).toBeCalledWith('')
  })
})

Inside of a test suite declaration everything is OK (see an output of a jest.isMockFunction(require.resolve)) and mock works. But for a test subject require.resolve remains with original functionality.

Due to this issue, this isn't pure unit test.

If I, for example, mock process.exit everything works as expected.

like image 872
Ruslan Zaytsev Avatar asked Dec 20 '17 13:12

Ruslan Zaytsev


People also ask

How do you call a mock function in Jest?

You can create a namespace that you export as the default object and call b using the namespace. This way, when you call jest. mock it will replace the b function on the namespace object. const f = require('./f'); jest.

What is mock call Jest?

Mock functions allow you to test the links between code by erasing the actual implementation of a function, capturing calls to the function (and the parameters passed in those calls), capturing instances of constructor functions when instantiated with new , and allowing test-time configuration of return values.

Does Jest mock get hoisted?

Using with ES module imports​ But often you need to instruct Jest to use a mock before modules use it. For this reason, Jest will automatically hoist jest. mock calls to the top of the module (before any imports).

What does mocking mean in Jest?

Mocking is a technique to isolate test subjects by replacing dependencies with objects that you can control and inspect. A dependency can be anything your subject depends on, but it is typically a module that the subject imports.


1 Answers

So, not a perfect solution, but it is simpler to inject (DI) require.resolve into

const requirer = (resolver) => {
  try {
    return resolver('./add')
  } catch (error) {
    console.error('failed to find a module')
  }
}

module.exports = requirer

now in a test suite passing down mocked version of a require.resolve works as expected

const requirer = require('./requirer')

describe('attempt to mock require.resolve', () => {
   it('works', () => {
     require.resolve = jest.fn(arg => `./${arg}`)
     console.log(
       'is require.resolve mocked',
       jest.isMockFunction(require.resolve)) // will say true

     requirer(require.resolve)

     expect(require.resolve).toHaveBeenCalledTimes(1)
     // expect(require.resolve).toBeCalledWith('')
  })
})
like image 80
Ruslan Zaytsev Avatar answered Oct 11 '22 23:10

Ruslan Zaytsev