3

I have a react component (CreateForm). The React component depends on a module (Store). The CreateForm has a Cancel button. On clicking the cancel button, the handleCancel function of the Store module should be called.

I wrote a test unsuccessfully using Jest:

test.only('should handle cancel button click', () => {
    jest.mock('../../src/store');
    const store = require('../../src/store');
    const wrapper = shallow(<CreateForm />);
    const cancelButton = wrapper.find('button').at(1);
    cancelButton.simulate('click');
    expect(store.default.handleCancel).toBeCalled();
});

The test failed. The mock function did not get called and the test failed. Does the react component not get this version of the mock? If so, how do I fix the test? Thanks.

My CreateForm component looks something like the below:

import Store from './store';

render() {
   return (
     <Panel>
       <FormControls />
       <button onClick={Store.create}>Create</button>
       <button onClick={Store.handleCancel}>Cancel</button>
    </Panel>
  );
}

A second improvised test that works for me is shown below.

test.only('should handle cancel button click', () => {
  const store = require('../../src/store').default;
  const cancel = store.handleCancel;
  store.handleCancel = jest.fn();

  const wrapper = shallow(<CreateForm />);
  const cancelButton = wrapper.find('button').at(1);
  cancelButton.simulate('click');
  expect(store.handleCancel).toBeCalled();

  store.handleCancel = cancel;
});

The above test works. I am manually mocking the function, doing the test and restoring the function back to its original after the test. Is there a better way or Jest way of writing the above test? Thanks.

0

2 Answers 2

4

This is how I have managed to spy on imported functions using Jest.

Import everything that is imported in the file you're testing.

Mock it in the beforeEach, you can use more complex mocking if you need to return values or whatever.

In the afterEach call jest.clearAllMocks() to reset all the functions to normal to stop any mocking falling through to other tests.

Putting it all together it looks something like this.

import shallow from 'enzyme'
import * as Store from './Store' // This should be the actual path from the test file to the import

describe('mocking', () => {
  beforeEach(() => {
    jest.spyOn(Store, 'handleCancel')
    jest.spyOn(Store, 'create')
  })

  afterEach(() => {
    jest.clearAllMocks();
  })

  test.only('should handle cancel button click', () => {
    const wrapper = shallow(<CreateForm />);
    const cancelButton = wrapper.find('button').at(1);
    cancelButton.simulate('click');
    expect(Store.handleCancel).toBeCalled();
  })
})

Also, in case you need to mock a default import you can do so like this. jest.spyOn(Store, 'default')

Sign up to request clarification or add additional context in comments.

Comments

0

You forgot to tell jest how to mock the store module, in your case it is just undefined.

const store = require('../../src/store');
jest.mock('../../src/store', () =>({
 handleCancel: jest.fn()
}));

test.only('should handle cancel button click', () => {
    const wrapper = shallow(<CreateForm />);
    const cancelButton = wrapper.find('button').at(1);
    cancelButton.simulate('click');
    expect(store.default.handleCancel).toBeCalled();//I'm not sure about the default here
});

With this solution you tell jest to mock the store with an object that has the handleCancel function which is a jest spy. On this spy you can then test that it was called.

1 Comment

This does not work for me. CreateForm uses the Store module. The Store module still seems to work with the original object and not the mock. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.