25

coming from rspec, i am having trouble understanding mocking with jest. the approach i am trying for, is to automock a class's constructor and all of it's functions, and then unmock them one by one to test only that one function. the only documentation i can find on it, is with using 2 classes, mocking 1 class, and then testing that those functions are called from the other unmocked class.

below is a basic, contrived idea of what i am trying to do. can someone direct me to the jest-way of doing this?

foo.js

class Foo
  constructor: ->
    this.bar()
    this.baz()
  bar: ->
    return 'bar'
  baz: ->
    return 'baz'

foo_test.js

// require the class
Foo = require('foo')

// mock entire Foo class methods
jest.mock('foo')

// unmock just the bar method
jest.unmock(Foo::bar)

// or by
Foo::bar.mockRestore()

// and should now be able to call
foo = new Foo
foo.bar() // 'bar'
foo.baz() // undefined (still mocked)

// i even tried unmocking the instance
foo = new Foo
jest.unmock(foo.bar)
foo.bar.mockRestore()
skyboyer
  • 22,209
  • 7
  • 57
  • 64
brewster
  • 4,342
  • 6
  • 45
  • 67

5 Answers5

16

mockFn.mockRestore() worked for me with jest@24.9.0:

// Create a spy with a mock
const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(() => {})

// Run test or whatever code which uses console.info
console.info('This bypasses the real console.info')

// Restore original console.info
consoleInfoSpy.mockRestore()
johannchopin
  • 13,720
  • 10
  • 55
  • 101
Nick Ribal
  • 1,959
  • 19
  • 26
11

This does not strictly apply to the OP, but answer-seekers may end up here. You can mock a module except certain parts for all tests like so.

mocks/saladMaker.js

// Let Jest create the mock.
const saladMaker = jest.genMockFromModule('../saladMaker');

// Get the unmocked chop method.
const {chop} = jest.requireActual('../saladMaker');

// Patch it in.
saladMaker.chop = chop;

module.exports = saladMaker;

The key part is to use requireActual to get at the unmocked module.

bypassing module mocks

Liam
  • 27,717
  • 28
  • 128
  • 190
reergymerej
  • 2,371
  • 2
  • 26
  • 32
4

It is not possible to get the original module after mocking it in Jest. What jest.mock does is to replace the module with your mock.

So even you write:

Foo = require('foo')
jest.mock('foo')

Jest will hoist the jest.mock('foo') call on top of the call stack, so it's the first thing that happens when the test starts. This will also affect all other modules you import and that import foo.js.

You could try to use spyOn to spy on functions of an object, should work with classes as well, but I'm not quite sure.

Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
  • yea i have been playing with that too, but having the same issue. i was also looking at try to just mock the constructor, but can't seem to figure that out either. somehow jest is doing it, but looking through their source code may take longer than just figuring it out myself – brewster Jan 09 '19 at 20:36
1

I have tried a lot of things, but what eventually worked for me is (using Create React App):

setupTests.ts

jest.mock("./services/translations/translationsService", () => ({
  __esModule: true,
  default: {
    initDict: (): void => undefined,
    translate: (key: Phrases): string => key,
  },
  t: (key: Phrases): string => key,
}));

Which mocks the module for all tests. In order to unmock for a single test suite, I did:

jest.mock("../../../services/translations/translationsService", () =>
  jest.requireActual("../../../services/translations/translationsService")
);

describe(() => { /* test suite goes here and uses real implementation */ });
Daniel Stoyanoff
  • 1,443
  • 1
  • 9
  • 25
0

For Jest@27.4.7

const mockChildComponent = jest.mock('../../../src/components/common/childComponent', () => ({
  __esModule: true,
  default: (props: Prop) => (
    <div data-test-id="stub-chart-panel">
      {props.label}
    </div>
  ),
}));

test('mock child', async () => {
  const wrapper = mount(
      <ParentComponent />
  );
  expect(....);
});

mockChildComponent.restoreAllMocks();

test('default child component ', async () => {
  const wrapper = mount(
      <ParentComponent />
  );
  expect(....);
});
Viraj Singh
  • 1,951
  • 1
  • 17
  • 27