开玩笑地模拟“点击”效果很奇怪,测试失败

时间:2019-11-03 19:03:02

标签: javascript reactjs jestjs enzyme

我正在尝试测试一个看起来像这样的简单组件

import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import styles from './styles.css'

export class App extends PureComponent {
  handleClick = (event) => {

    const { loadGreetings } = this.props
    loadGreetings()
  }

  render () {
    const { hi } = this.props
    return (
      <section>
        <h1 className={styles.earlyDawn}>{hi}</h1>
        <button onClick={this.handleClick}>Handshake</button>
      </section>
    )
  }
}

App.propTypes = {
  hi: PropTypes.string,
  loadGreetings: PropTypes.func
}

export default App

这是我的测试文件

import React from 'react'
import {App} from './index'
import {shallow} from 'Enzyme'

describe('Testing App container...', () => {
  let props

  beforeEach(() => {
    props = {
      loadGreetings: jest.fn().mockName('loadGreetings'),
      hi: 'Hi from test'
    }
  })

  test('should handle click on the button', () => {
    const wrapper = shallow(<App {...props}/>)
    const buttonHi = wrapper.find('button')
    const instance = wrapper.instance()

    expect(buttonHi.length).toBe(1)

    jest.spyOn(instance, 'handleClick')
    buttonHi.simulate('click')

    expect(props.loadGreetings).toHaveBeenCalled()
    expect(instance.handleClick).toHaveBeenCalled()
  })

})

所以问题出在第二个toHaveBeenCalled断言始终失败。但是,首先toHaveBeenCalled似乎在工作,这使我感到困扰,因为props.loadGreetings在instance.handleClick内部被调用。您能帮我找出问题所在吗?

依赖项:“反应”:“ 16.9.0”,“反应dom”:“ 16.9.0”,“巴比尔开玩笑”:“ ^ 24.8.0”,“酶”:“ ^ 3.10.0” ,“笑话”:“ ^ 24.8.0”,

1 个答案:

答案 0 :(得分:0)

一种更简单的方法是传入一些初始道具,并基于这些初始道具测试您的组件-您还将操纵这些道具以添加更多的断言。

这是一个可行的示例(单击Tests标签以运行测试):

Edit Testing Button Click


components / App / index.js

import React, { PureComponent } from "react";
import PropTypes from "prop-types";

class App extends PureComponent {
  handleClick = () => {
    this.props.loadGreetings();
  };

  render() {
    const { message } = this.props;
    return (
      <section className="app">
        <h1>{message}</h1>
        <button onClick={this.handleClick}>Handshake</button>
      </section>
    );
  }
}

App.propTypes = {
  message: PropTypes.string,
  loadGreetings: PropTypes.func
};

export default App;

components / App / App.test.js

import React from "react";
import { shallow } from "enzyme";
import App from "./index";

// define the passed in function here for easier testing below
const loadGreetings = jest.fn();

// initial props to pass into 'App'
const initProps = {
  message: "hi",
  loadGreetings
};

describe("Testing App container...", () => {
  let wrapper;
  beforeEach(() => {
    // this resets the wrapper with initial props defined above
    wrapper = shallow(<App {...initProps} />);
  });

  afterEach(() => {
    // this clears any calls to the mocked function 
    // and thereby resets it 
    loadGreetings.mockClear();
  });

  it("renders without errors", () => {
    expect(wrapper.find(".app").exists()).toBeTruthy();
    expect(loadGreetings).toHaveBeenCalledTimes(0);
  });

  it("initially renders a 'hi' message and then a 'goodbye' message", () => {
    expect(wrapper.find("h1").text()).toEqual("hi");

    // manipulating the initial 'message' prop
    wrapper.setProps({ message: "goodbye" });

    expect(wrapper.find("h1").text()).toEqual("goodbye");
  });

  it("should call 'loadGreetings' when the 'Handshake' button is clicked", () => {    
    // since we passed in 'loadGreetings' as a jest function
    // we expect it to be called when the 'Handshake' button is
    // clicked
    wrapper.find("button").simulate("click");
    expect(loadGreetings).toHaveBeenCalledTimes(1);
  });
});

不推荐(请参见下文),但是您可以监视类方法-您必须使用实例,强制更新实例,然后手动wrapper.instance().handleClick()或通过间接调用handleClick方法某些元素的事件处理程序:wrapper.find("button").simulate("click")wrapper.find("button").props().onClick()

我不推荐这种测试策略的原因是您正在测试React实现(测试元素的事件处理程序是否调用了您的回调函数)。相反,可以通过断言是否调用了prop函数和/或发生prop / state更改来避免这种情况。这是测试组件的更标准,更直接的方法,因为这就是我们所关心的。我们关心道具和/或状态会根据用户的某些操作而变化。换句话说,通过对所谓的“ loadGreetings”道具进行断言,我们已经在测试onClick事件处理程序的工作原理。

工作示例:

Edit Testing Button Click - Example 2

App.test.js (与上述测试相同,但该测试除外):

  it("should call 'loadGreetings' when the 'Handshake' button is clicked", () => {
    const spy = jest.spyOn(wrapper.instance(), "handleClick"); // spying on the method class
    wrapper.instance().forceUpdate(); // required to ensure the spy is placed on the method
    wrapper.find("button").simulate("click");

    expect(spy).toHaveBeenCalledTimes(1);

    const mockedFn = jest.fn(); // setting the method as a mocked fn()
    wrapper.instance().handleClick = mockedFn;
    wrapper.instance().forceUpdate(); // required to update the method instance with a mocked fn
    wrapper.find("button").simulate("click");

    expect(mockedFn).toHaveBeenCalledTimes(1);
  });