Jest: Unlike what documentation says, the mocks are activated by default

Created on 18 Dec 2016  路  8Comments  路  Source: facebook/jest

Documentation/code improvement

What is the current behavior?

The [documentation says]:

When a manual mock exists for a given module, Jest's module system will use that module when explicitly calling jest.mock('moduleName').

Even the example in the docs use jest.mock('fs'); to demonstrate that mocks are opt-in rather than active by default. But this example repo branch (default-mock-behaviour) shows that mocks are enabled by default.

// __tests__/actual-redis.test.js
const mockedRedis = require('../__mocks__/redis.js');
// jest.mock('redis');
const redis = require('redis');

describe('redis', () => {
  it('not to be mocked', () => {
    expect(redis).not.toEqual(mockedRedis); // this fails even though jest.mock() is not called
  });
});

What is the expected behavior?

So either the documentation can be updated to mention that jest.mock() isn't necessary by default (then #2355 is gonna be even more outstanding) or jest needs to have the opt-in behaviour just as described in the current documentation.
The expected behaviour at least according to the docs is to let the test files opt-in to using a manual mock by explicitly calling jest.mock() instead of having the mocks active by default and then expect an opt-out using jest.umock().
This is related to #2349 and #2353.

versions

Jest 18.0.0, Yarn 0.17.10, npm 4.0.5

Documentation good first issue

Most helpful comment

In regard to the issue, it seems inline with the documentation:

When a manual mock exists for a given module, Jest's module system will use that module when explicitly calling jest.mock('moduleName'). However, manual mocks will take precedence over node modules even if jest.mock('moduleName') is not called. To opt out of this behavior you will need to explicitly call jest.unmock('moduleName') in tests that should use the actual module implementation.

However I have the same problem as @dijimsta in that calling unmock does not seem to work.

All 8 comments

I'm also observing this behaviour. Also for axios, jest.unmock() does not prevent the mocked modules from loading.

In regard to the issue, it seems inline with the documentation:

When a manual mock exists for a given module, Jest's module system will use that module when explicitly calling jest.mock('moduleName'). However, manual mocks will take precedence over node modules even if jest.mock('moduleName') is not called. To opt out of this behavior you will need to explicitly call jest.unmock('moduleName') in tests that should use the actual module implementation.

However I have the same problem as @dijimsta in that calling unmock does not seem to work.

I seem to be having the same issues where calling unmock for a given test does not unmock the module, and loads the manual mock instead, unless jest.unmock is called for the entire file (as described here https://github.com/facebook/jest/issues/2349#issuecomment-267819337).

Is this the desired behaviour?

From the documentation:

However, manual mocks will take precedence over node modules even if jest.mock('moduleName') is not called.

I'm questioning why this is only the case for node modules. I'd love to have this behaviour for relative modules too. Adding jest.mock('./path/to/relative/module') after I've already created a manual mock seems unnecessary. Would much prefer to call jest.unmock(....) if I'm really testing that relative module.

I also think that it should work for relative modules, as part of my tests I call methods that might send emails, obviously from tests this is a bad idea, being able to use the mock per default would be a sensible improvement.

Still no movement on this? I mocked lodash/debounce by making a __mocks__/lodash/debounce.js. Calling jest.unmock('lodash/debounce') OR jest.unmock('lodash') has no effect on unmocking the file I made.

In general manual mocks of node modules are automatically mocked when required in your tests, no need to explicitly add jest.mock('some-module'). However, there is an exception to that, which is Node's core modules, like fs, path, etc. They need to be explicitly mocked by calling jest.mock('fs') or jest.mock('path') in this case.

You also need to explicitly mock your own files, e.g. jest.mock('../some-fn') is required if you have __mocks__/some-fn.js.

The fs example is kinda unfortunate, because it's a special case. Looks like we'll need to adjust the documentation to include that.

@brenthosie we're currently not supporting mocking absolute paths, this is something totally different. PR welcome however!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kentor picture kentor  路  3Comments

samzhang111 picture samzhang111  路  3Comments

StephanBijzitter picture StephanBijzitter  路  3Comments

withinboredom picture withinboredom  路  3Comments

ianp picture ianp  路  3Comments