jest.setMock does not work with jest.dontMock

Created on 26 Jan 2015  Â·  18Comments  Â·  Source: facebook/jest

Say I have a test, and in it, I have a module, ../myModuleToTest that requires someNodeLib. When I do the following, things get screwed up:

jest.setMock('someNodeLib', require('../mocks/myMockLib');
jest.dontMock('../myModuleToTest');

My expected behavior is that setMock will provide me the actual module.exports from '../mocks/myMockLib', but setMock seems to do nothing. I also tried to switch the order of the above statements, and then what ends up happening is that every require statement in the test file, no matter what module you are requiring, gets replaced with a mock of whatever setMock is defined to be.

What does work, however, is this current workaround in the test (note the order of calls):

jest.setMock('someNodeLib', require.requireActual('../mocks/myMockLib');
jest.setMock('../myModuleToTest', require.requireActual('../myModuleToTest');

All of this is a bit of a kludge, when in actuality a node_module I required, i.e. 'request', was not correctly mocked by jest. The proposed solution is to fix the automocking such that I don't have to explicitly set my own mocks, or to either document what setMock does better or make it fit to what it says on the jest website.

Most helpful comment

I think this issue can be safely closed. The issue described here should be resolved with Jest 0.9. Previous versions were always a little bit confused about node_modules. If this problem persists for anyone I'm happy to take a closer look at this issue – please provide me with a repository that has a failure case.

A few things to keep in mind: jest.setMock will likely not work when a module has already been required as a transitive dependency:

jest.unmock('Bar');
const Bar = require('Bar'); // assume this will require Foo
jest.setMock('Foo', {…})
const Foo = require('Foo'); // Foo was already required before `setMock` was called.

It therefore is required to call APIs like setMock before all other APIs.

Manual mocks for node modules can also be created by creating a __mocks__ folder and putting a node-module-name.js file in it. To mock react, for example, you'd create a __mocks__/react.js file.

The next version of Jest will introduce a new API jest.mock('Foo', () => {moduleExports}) that gets hoisted at the top of the block, when used together with babel-jest.

Please let me know if any of this doesn't make sense or if this is still an issue :)

All 18 comments

The same issue for me.

Sadly, I cannot even get your double setMock example to work in my case. Adding setMock anywhere in my test file breaks every subsequent require statement. (React 0.12.1, Jest 0.2.0).

The same for me. Here's what I have in my test:

// mocking
jest.setMock('bookshelf', '../../__mocks__/bookshelf.js');

// stuff that should not be mocked
jest.setMock('../topics', require.requireActual('../topics'));
jest.setMock('../../bookshelf-models', require.requireActual('../../bookshelf-models'));
jest.setMock('es6-promise', require.requireActual('es6-promise')); // we need the polyfill

And the output is:

TypeError: /Users/mikolajdadela/code/lb-node-api/resources/__tests__/topics-test.js: /Users/mikolajdadela/code/lb-node-api/resources/topics.js: Object ../../__mocks__/bookshelf.js has no method 'polyfill'
    at /Users/mikolajdadela/code/lb-node-api/resources/topics.js:4:24

The reported line (resources/topics.js:4:24) is:

require('es6-promise').polyfill();

So it looks like, in my case, Jest tries to use ../../__mocks__/bookshelf.js as a mock of es6-promise. :(


I also tried other approaches:

  • when I use dontMock for stuff that should not be mocked and have setMock BEFORE dontMock (so the order is like in my example above), the setMock is ignored.
  • when I use dontMock for stuff that should not be mocked and have setMock AFTER dontMock, the modules are mismatched as in my full example.

+1

+1 Even if I setMock on everything, I can't seem to get an actual module for TestUtils.

/** @jsx React.DOM */
//tests/app/headernav-test.js
jest.setMock('../../../app/modules/HeaderNav.jsx', require.requireActual('../../../app/modules/HeaderNav.jsx'));
jest.setMock('../../TestContext', require.requireActual('../../TestContext'));
jest.setMock('../../../app/modules/LoginStatus.jsx', require.requireActual('./mocks/LoginStatus.jsx'));
jest.setMock('react/addons', require.requireActual('react/addons'));

var React = require('react/addons'),
    MyComponent = require('../../../app/modules/HeaderNav.jsx'),
    TestUtils = React.addons.TestUtils,
    TestContext = require('./../../TestContext'),
    component = TestContext.getRouterComponent(MyComponent).component;

describe('HeaderNav', function() {

    it('renders the header nav', function() {
        //test doesn't even make it this far.
    });
});

Cannot read property 'TestUtils' of undefined

See also:
http://stackoverflow.com/questions/28777211/typeerror-with-jest-setmock

+1 ! When making use of jest.setMock, it seems that it mocks just about every module I then try to require instead of the requested one only (for the record, my test uses jest.autoMockOff at the top).

Any hints on this ?

I'd appreciate some clarity on this too. I am using jest.setMock('...', require.requireActual('...')) and dontMock for the component to test.

The only way I can get the test to even pass is to use dontMock inside the describe block, which gets ignored - when I log my component, I can see that is a mock :(

I'm also encountering these issues with setMock. If I set a manual mock for "superagent", every single other require seems to return that mock too. Seems like a really big problem.

I discovered a workaround for the problem where the wrong mocks are used. If you create a "wrapper" for the node module you wish to use, e.g.

// superagent.js
module.exports = require("superagent");

Reference this in your system under test, rather than the direct dependency. Then you can mock this as you wish:

jest.setMock("../superagent", {...});

Everything seems to work as expected. Jest seems to be falling over when trying to mock a node module but any local files are fine.

+1

This is madness. This bug makes Jest really unusable. It's the kind of bug that should actually never-ever happen, and if it does, it just means that the underlying code is so brittle you can't really trust it to tell you anything about your code. And if this kind of bug is reported and not fixed after almost 10 months, this tells a lot about how much its authors care about its quality.

Got to agree with the above. This has me contemplating just moving over to another testing solution. Testing anything but _truly_ basic unit tests is really annoying.

+1

+1

@kentaromuria this might be a good ask to look into to get started with Jest! Absolutely agree we should make this better soon.

+1

I think this issue can be safely closed. The issue described here should be resolved with Jest 0.9. Previous versions were always a little bit confused about node_modules. If this problem persists for anyone I'm happy to take a closer look at this issue – please provide me with a repository that has a failure case.

A few things to keep in mind: jest.setMock will likely not work when a module has already been required as a transitive dependency:

jest.unmock('Bar');
const Bar = require('Bar'); // assume this will require Foo
jest.setMock('Foo', {…})
const Foo = require('Foo'); // Foo was already required before `setMock` was called.

It therefore is required to call APIs like setMock before all other APIs.

Manual mocks for node modules can also be created by creating a __mocks__ folder and putting a node-module-name.js file in it. To mock react, for example, you'd create a __mocks__/react.js file.

The next version of Jest will introduce a new API jest.mock('Foo', () => {moduleExports}) that gets hoisted at the top of the block, when used together with babel-jest.

Please let me know if any of this doesn't make sense or if this is still an issue :)

Was this page helpful?
0 / 5 - 0 ratings