最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin4浏览0评论

I'm testing a ponent 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 ponent inside the test then it works

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

  // create a fake ponent
  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 ponents? I've spent many days looking for answers but I'm lost.

I'm testing a ponent 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 ponent inside the test then it works

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

  // create a fake ponent
  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 ponents? I've spent many days looking for answers but I'm lost.

Share Improve this question edited May 7, 2017 at 5:59 Shaoz asked May 6, 2017 at 22:22 ShaozShaoz 10.7k26 gold badges76 silver badges100 bronze badges 8
  • Aren't you supposed to pass handleSubmit as a prop? you are setting handleSubmit but not using it within your ponent! – Jose Paredes Commented May 6, 2017 at 22:47
  • @Shaoz Can you post the minimal code of your ponent? Are you passing the handleSubmit as prop or it is a ponent method? – Hardik Modha Commented May 7, 2017 at 3:08
  • @HardikModha, thanks for responding. handleSubmit is a ponent method. I have updated my question with the ponent code. – Shaoz Commented May 7, 2017 at 5:32
  • Thanks for the update. You'll need to mock the ponent method as suggested by @rauliyohmc. Have you given it a try? – Hardik Modha Commented May 7, 2017 at 5:39
  • @HardikModha, yes try his suggestion but I'm still getting the same error Expected mock function to have been called. So something isn't right with shallow or mount and jest.fn(), I think. – Shaoz Commented May 7, 2017 at 5:51
 |  Show 3 more ments

3 Answers 3

Reset to default 4

Adding to @rauliyohmc answer. The problem is that even after mocking the ponent 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 ponent 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 ponent 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 ponent 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" />

Your ponent isn't using className .submit-btn, it's using .card-submit-btn.

发布评论

评论列表(0)

  1. 暂无评论