Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jest: Mock function have not been called in mock promise function

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: [] }.

like image 651
someok Avatar asked Dec 05 '22 13:12

someok


1 Answers

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();
})
like image 129
Andreas Köberle Avatar answered Dec 08 '22 03:12

Andreas Köberle