简体   繁体   中英

Jest.fn() not working in React unit-test

I'm testing a component method called handleSubmit (the name doesn't matter...).

Test

// ...imported all modules at the top, including enzyme

it('should submit form data', () => {
  let form = shallow(<Form />);
  let handleSubmit = jest.fn(); // <= this doesn't work!!

  form.find('.submit-btn').simulate('click');

  expect(form.find('.submit-btn').length).toEqual(1);
  expect(handleSubmit).toHaveBeenCalled();
});

Component

import React, { Component } from 'react';
import axios from 'axios';

class CarnetSidebarForm extends Component {
  constructor(props) {
    super(props);

    this.state = {
      title: ''
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(e) {
    const target = e.target;
    const value = target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  handleSubmit(e) {
    e.preventDefault();

    let payload = {
      title: this.state.title
    };

    this.postCard(payload);

    console.log('Payload: ', payload);
  }

  postCard(data) {
    return axios.post('http://localhost:4000/api/cards', data)
      .then(response => {
        console.log('Response: ', response.message);
      });
  }

  render() {
    return (
      <div className="card-form-panel">
        <form className="card-form" onSubmit={this.handleSubmit}>
          <div className="form-group">
            <label htmlFor="card-title-field">Title</label>
            <input className="form-control"
               type="text"
               placeholder="Title..."
               id="card-title-field"
               name="title"
               value={this.state.title}
               onChange={this.handleChange} />
          </div>

          <input className="card-submit-btn btn btn-primary" type="submit" value="Save" />
        </form>
      </div>
    );
  }
}

export default CarnetSidebarForm;

I keep getting this error message, which is annoying now:

expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called.

But if I create a fake component inside the test then it works

it('should submit form data', () => {
  let handleSubmit = jest.fn();

  // create a fake component
  let form = mount(
    <form onSubmit={handleSubmit}>
      <input className="submit-btn" type="submit" value="Save" />
    </form>
  );

  form.find('.submit-btn').simulate('submit');

  expect(form.find('.submit-btn').length).toEqual(1);
  expect(handleSubmit).toHaveBeenCalled();
});

Is it something to do with shallow() or mount from enzyme with imported components? I've spent many days looking for answers but I'm lost.

Adding to @rauliyohmc answer. The problem is that even after mocking the component method it is not getting called and instead, the actual method is called. So, after spending some time on it, I found out a solution. You'll need to forceUpdate your component after mocking its method.

it('should submit form data', () => {
  let form = mount(<Form />); // need to use mount to make it work.
  form.instance().handleSubmit = jest.fn();
  form.update(); // equivalent to calling form.instance().forceUpdate();

  form.find('.submit-btn').simulate('submit'); // simulated event must be submit

  expect(form.find('.submit-btn').length).toEqual(1);
  expect(form.instance().handleSubmit).toHaveBeenCalled();
}); 

Minimal example: gist

The problem is that you are not mocking the component method itself, but rather creating a new mock function and assign it to a random variable.

Try to mock the method through the object prototype before rendering as follows:

jest.mock('../Form'); // mock the component before importing it using the right path
import Form from '../Form';
...
it('should submit form data', () => {
  Form.prototype.handleSubmit = jest.fn();
  let form = shallow(<Form />);

  form.find('.submit-btn').simulate('submit');

  expect(form.find('.submit-btn').length).toEqual(1);
  expect(Form.prototype.handleSubmit).toHaveBeenCalled();
}); 

Note : not sure which jest version are you using but since Jest v15, automocking is disabled by default, so you need to explicitly mock your module before importing it in the file.

<input className="card-submit-btn btn btn-primary" type="submit" value="Save" />

你的组件没有使用className .submit-btn ,它使用的是.card-submit-btn

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM