nz_21
nz_21

Reputation: 7383

Javscript Jest test framework: when is a mock unmocked?

I want to mock a module and a function for a specific test. I have the following:

test("my test", () => {
   jest.mock("some_module")
   some_module.some_function = jest.fn();
   ...

})

test("another test", () => {
    ...
});


My question is, when the test is finished, will both mocks be "unset" so that I can use the real implementation for my next test? Or do I have to explicitly remove all mocks myself?

Upvotes: 2

Views: 187

Answers (1)

Robin Balmforth
Robin Balmforth

Reputation: 231

when the test is finished will all of the mocks be "unset"?

Jest tests are sandboxed on a test-file basis, so ordinarily after all tests in that file have been run, all the mocks would be restored.

However, what you are doing there: some_module.some_function = jest.fn(); is not mocking via Jest's mocking mechanism, it is monkey-patching an imported function. This will not be removed by Jest.

You should be doing something like this instead:

import { some_function } from 'some-module-path';

jest.mock('some-module-path');

test('my test', () => {
  ...
  expect(some_function).toHaveBeenCalled(); // e.g.
}

UPDATE:

After the discussion in comments, here is an example of doing a simple monkey-patch safely in Jest, so that it is restored for subsequent tests in the same file:

// foo.js -----------------------------------
export const foo = () => 'real foo';


// bar.js -----------------------------------
import { foo } from './foo';

export const bar = () => foo();


// bar.test.js ------------------------------
import { bar } from './bar';
import * as fooModule from './foo';

describe('with mocked foo', () => {
  let originalFoo;

  beforeAll(() => {
    // patch it!
    originalFoo = fooModule.foo;
    fooModule.foo = () => 'mocked foo';
  });

  afterAll(() => {
    // put it back again!
    fooModule.foo = originalFoo;
  });

  test('mocked return value from foo()', () => {
    expect(bar()).toEqual('mocked foo');
  });
});

describe('with real foo', () => {
  test('expect real return value from foo()', () => {
    expect(bar()).toEqual('real foo');
  });
});

UPDATE 2:

Another alternative, you can mock the dependency and use the original implementation temporarily with jest.requireActual:

import { bar } from './bar';
import { foo } from './foo';

jest.mock('./foo');
foo.mockReturnValue('mocked foo');
const fooModule = jest.requireActual('./foo')

test('mocked return value from foo()', () => {
  expect(bar()).toEqual('mocked foo');
});

test('real return value from foo()', () => {
  foo.mockImplementation(fooModule.foo);
  expect(bar()).toEqual('real foo');
});

Upvotes: 4

Related Questions