4
votes

I want to test my react login component, but the mock function have not been called:

Login:

export default class LoginPage extends PureComponent {
    static propTypes = {

        login: PropTypes.func.isRequired,
        history: PropTypes.shape({
            replace: PropTypes.func.isRequired,
        }).isRequired,
    };

    onSubmit = (e) => {
        this.props.login(this.state.username, this.state.password)
            .then(() => {

                this.props.history.replace('/');
            });
    };

    render() {
        return (
            <form onSubmit={this.onSubmit}>
                ...
            </form>
        );
    }
}

I use jest + enzyme to test this:

const props = {
    login: jest.fn(() => Promise.resolve('success')),
    history: {
        replace: jest.fn()
    },
};

const wrapper = mount(<LoginPage {...props}/>);

const form = wrapper.find(Form);
const inputs = form.find('input');
const username = inputs.at(0);
const password = inputs.at(1);
username.simulate('change', {target: {value: 'Changed'}});
password.simulate('change', {target: {value: 'Changed'}});

form.simulate('submit');

expect(props.login).toBeDefined();
expect(props.history.replace).toBeDefined();

// this is success
expect(props.login).toBeCalled();

// this is failure
expect(props.history.replace).toBeCalled();

I mock two function, and the history.replace should be called by login, the login mocked as Promise function.

expect(props.login).toBeCalled() test success.

but expect(props.history.replace).toBeCalled() test failure.

I log props.history.replace.mock, it output { calls: [], instances: [] }.

1

1 Answers

15
votes

You need to inform Jest about the promise you are using otherwise it will not wait for so the test is over before the promise resolves. Here are the docs for testing async stuff. Your test needs to become an async function. The promise needs to be stored in a variable that can be used with await after the form submit was fired:

it('does something', async () => {
  const promise = Promise.resolve('success')

  const props = {
      login: jest.fn(() => promise),
      history: {
          replace: jest.fn()
      },
  };

  const wrapper = mount(<LoginPage {...props}/>);

  const form = wrapper.find(Form);
  const inputs = form.find('input');
  const username = inputs.at(0);
  const password = inputs.at(1);
  username.simulate('change', {target: {value: 'Changed'}});
  password.simulate('change', {target: {value: 'Changed'}});

  form.simulate('submit');
  await promise;
  expect(props.login).toBeDefined();
  expect(props.history.replace).toBeDefined();

  // this is success
  expect(props.login).toBeCalled();

  // this is failure
  expect(props.history.replace).toBeCalled();
})