3

I'm having trouble checking if my mock action was called from an onSubmit on a form:

Login Form:

class Login extends Component {
  constructor(props) {
    super(props);
    this.state = {
      email: "",
      password: "",
    };
  }

  handleSubmit = e => {
    e.preventDefault();
    this.props.loginUser(this.state.email, this.state.password);
  };

  handleChange = event => {
    const { value } = event.target;
    const { name } = event.target;
    this.setState({
      [name]: value,
    });
  };

  render() {
    const { t } = this.props;

    return (
      <div className="login-container>
        <form data-test-id="login-form" onSubmit={this.handleSubmit}>
            <TextComponent
              label="Email"
              testId="login-email"
              value={this.state.email}
              handleChange={this.handleChange}
            />
            <div className="my-3" />
            <TextComponent
              label="Password"
              testId="login-password"
              value={this.state.password}
              handleChange={this.handleChange}
            />
            <button action="submit" data-test-id="login-button">
              {t("en.login")}
            </button>
        </form>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    authenticated: state.login.authenticated,
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ loginUser }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Login));

Test:

import { mount, shallow, render } from "enzyme";
import React from "react";
import { Provider } from "react-redux";
import { I18nextProvider } from "react-i18next";
import { Router } from "react-router-dom";
import { findByTestAtrr, testStore } from "../../test/utils/utils";
import Login from "../../src/Login/index";
import i18n from "../../src/i18n";
import history from "../../src/history";


const setUp = loginUser => {
  const initialState = {
    login: {
      authenticated: true,
    },
  };

  const store = testStore(initialState);
  const wrapper = mount(
    <I18nextProvider i18n={i18n}>
      <Provider store={store}>
        <Router history={history}>
          <Login onSubmit={loginUser} />
        </Router>
      </Provider>
    </I18nextProvider>
  );
  return wrapper;
};

  describe("submit button", () => {
    let emailInput;
    let passwordInput;
    let submitButton;
    let newWrapper;
    let loginAction;
    beforeEach(() => {
      loginAction = jest.fn();
      newWrapper = setUp(loginAction);

      emailInput = findByTestAtrr(newWrapper, "login-email");
      emailInput.instance().value = "email.com";
      emailInput.simulate("change");

      passwordInput = findByTestAtrr(newWrapper, "login-password");
      passwordInput.instance().value = "password";
      passwordInput.simulate("change");

      submitButton = findByTestAtrr(newWrapper, "login-button");
    });

    it("login action is called", () => {
      console.log(submitButton.debug());
      submitButton.simulate("submit");
      expect(loginAction).toHaveBeenCalledTimes(1);
    });
  });
});

I'm able to simulate adding values to the email and password but I can't simulate the onClick to work. Am I testing the submit function incorrectly?

This is my submit button when I console.log

console.log __tests__/integration_tests/login.test.js:97
  <button action="submit" data-test-id="login-button">
    Log in
  </button>

error:

expect(jest.fn()).toHaveBeenCalledTimes(expected)

Expected number of calls: 1
Received number of calls: 0
lost9123193
  • 10,460
  • 26
  • 73
  • 113
  • I think you are looking for `submitButton.simulate('click')` – topched Dec 31 '19 at 19:21
  • doesn't work either :/ – lost9123193 Dec 31 '19 at 19:23
  • It may be that you are using enzyme to mount instead of the render method from react testing library? (just guessing since we cant see your imports) – topched Dec 31 '19 at 19:39
  • @topched i updated the file. Yeah I'm using currently using mount – lost9123193 Dec 31 '19 at 19:42
  • Shouldn't the button attribute be type instead of action? ` – Drew Reese Dec 31 '19 at 23:16
  • @DrewReese that was a good point. I changed the code but it didn;t do anything :/ – lost9123193 Dec 31 '19 at 23:49
  • @lost9123193 is the test attribute correct? All the other components you target with `findByTestAtrr` use an attribute called `testId`, but on the button you use the data attribute `data-test-id` – Drew Reese Dec 31 '19 at 23:59
  • @DrewReese yep I console.logged the button as seen above – lost9123193 Jan 01 '20 at 00:02
  • @lost9123193 Did you ever check that you where using the correct attribute, i.e. `testId="login-button"` vs `data-test-id="login-button"`, on your button for testing? – Drew Reese Jan 06 '20 at 15:16

3 Answers3

3

As raised from 2016 on github: Simulated click on submit button in form does not submit form #308, this issue still persists on my project, using Jest + Enzyme (2020).

There are some workarounds such as using tape or sino.

The other solution is to get the DOM element and trigger the click without using simulate (go to given link, scroll down the thread to learn more).

If anyone ever found a solution to simulate form submit, kindly tag me here. Thank you.

nambk
  • 445
  • 3
  • 13
  • Just found out [Can't check if form submit works #1722](https://github.com/enzymejs/enzyme/issues/1722#issuecomment-407322577) on enzyme github. Try to set props in form as suggested to see if it solves this issue. – nambk Dec 25 '20 at 18:39
1

As explained in the below mentioned link, you can use done and setTimeout.

https://github.com/ant-design/ant-design/issues/21272#issuecomment-628607141

it('login action is called', (done) => {
  submitButton.simulate("submit");
  setTimeout(() => {
    expect(loginAction).toHaveBeenCalledTimes(1);
    done();
  }, 0);
});
1
it('should call onSubmit method', ()=>{

    const spy = jest.spyOn(wrapper.instance(), "onSubmit");
    wrapper.find('button[type="submit"]').simulate('click');
   
    expect(spy).toHaveBeenCalledTimes(1);

});

Check the name of method to be called on simulate click. In my case it was onSubmit. No need to import sinon or spy from sinon jest does everything.

SherylHohman
  • 16,580
  • 17
  • 88
  • 94