14
votes

I have a functional component and I wanted to test it with mock function (simplified demonstration)

const remove = () => {
  ... do something
}

const removeButton = (props) => (
  <Button onClick={() => remove()}>
    Remove
  </Button>
);

I tried with this test case

it('test remove button', () => {
  const test = shallow(<removeButton/>)
  const mockFunction = jest.fn()
  test.instance().remove = mockFunction
  test.find('Button').simulate('click')
  expect(mockFunction).toHaveBeenCalled()
})

.instance().remove could not mock the function because it is out of scope. How would I mock the function remove ?

2

2 Answers

4
votes

Here is a working example:

// ---- comp.js ----
import * as React from 'react';
import * as comp from './comp';

export const remove = () => {
  // ...do something
}

export const RemoveButton = (props) => (
  <div onClick={() => comp.remove()}>
    Remove
  </div>
);


// ---- comp.test.js ----
import * as React from 'react';
import { shallow } from 'enzyme';

import * as comp from './comp';

describe('removeButton', () => {
  it('should call remove on click', () => {
    const mock = jest.spyOn(comp, 'remove');
    mock.mockImplementation(() => {});
    const component = shallow(<comp.RemoveButton />);
    component.find('div').simulate('click');
    expect(mock).toHaveBeenCalled();
    mock.mockRestore();
  });
});

Note that to mock remove you need to export it and you need to import the module back into itself and use the import within your component.

Having said that, I agree that passing remove in as a prop is a better approach. It is much easier to test and makes your components more reusable.

0
votes

You should pass the remove function as a prop, rather than just defining an adjacent variable that is private to a module.

const removeButton = (props) => (
  <Button onClick={() => props.remove()}>
    Remove
  </Button>
)

// test file
it('test remove button', () => {
  const mockFunction = jest.fn()
  const test = shallow(<RemoveButton remove={mockFunction} />)
  test.find('Button').simulate('click')
  expect(mockFunction).toHaveBeenCalled()
})