如何用酶Chai测试HOC

时间:2019-04-04 21:41:01

标签: reactjs unit-testing jestjs enzyme chai

我有一个HOC函数,该函数接收React组件并返回带有两个新方法属性(handleBackmoveitOnTop)的react组件,如下所示:

import React, { Component } from "react";
import classNames from "classnames";

 export default WrappedComponent => {
  return class extends Component {
      constructor(props) {
          super(props);
            this.moveitOnTop = this.moveitOnTop.bind(this);
            this.handleBack = this.handleBack.bind(this);

        this.state = {
            isSearchActive: false
        };
    }
    moveitOnTop(flag) {
        this.setState({ isSearchActive: flag });
        window.scrollTo(0, -100);
    }

    handleBack() {
        this.setState({ isSearchActive: false });
        if (document.body.classList.contains("lock-position")) {
            document.body.classList.remove("lock-position");
        }
    }

    render() {
        const props = {
            ...this.props,
            isSearchActive: this.state.isSearchActive,
            moveitOnTop: this.moveitOnTop,
            goBack: this.handleBack
        };

        const classes = classNames({ "c-ftsOnTop": this.state.isSearchActive });
        return (
            <div className={classes}>
                <WrappedComponent {...props} />
            </div>
        );
    }
  };
 };

组件:

 //import fireAnalytics
import { fireAnalytics } from "@modules/js-utils/lib";
class MyComponent extender Component{
  constructor(){
     super(props);
     this.handleClick = this.handleClick.bind(this);
  }

   handleClick(e) {
     // calling analytics function by passing vals
    fireAnalytics({
        event: "GAEvent",
        category: "",
        action: `Clicked on the ${e.target.id} input`,
        label: "Click"
    });

     // I CALL THE HOC PROPERTY
     this.props.moveitOnTop(true);

     // I CALL THE HOC PROPERTY
     this.props.handleBack();
   }

  render(){
     return(
        <div className="emailBlock">
          <input type="text" onClick={handleClick} />
          <Button className="submit">Submit</Button>
        </div>
     )
  }
}

// export HOC component
export default hoc(MyComponent);

// export just MyComponent
export {MyComponent};

我要测试HOC:

  1. 我需要检查类.c-ftsOnTop是否存在
  2. 我需要检查调用onClick和`this.props.moveitOnTop'的this.props.handleBack函数
  3. 我需要检查className emailBlock是否存在。

我尝试过但失败的测试:

 import { mount, shallow } from 'enzyme';
 import sinon from 'sinon';
 import React from 'react';
 import { expect } from 'chai';
 import hoc from '....';
 import {MyComponent} from '...';
 import MyComponent from '....';

 it('renders component', () => {

const props = {}
const HocComponent = hoc(MyComponent);
const wrapper = mount(
  <HocComponent {...props} />
);

console.log('wrapper:', wrapper);
expect(wrapper.find('.c-ftsOnTop')).to.have.lengthOf(1);
expect(wrapper.hasClass('c-fts-input-container')).toEqual(true);
 })

错误

AssertionError: expected {} to have a length of 1 but got 0

console.log:wrapper: ReactWrapper {}

有人可以帮助我呈现HOC吗?

1 个答案:

答案 0 :(得分:0)

这是一个有效的测试:

import { mount } from 'enzyme';
import React from 'react';
import WrappedMyComponent from './MyComponent';

it('renders component', () => {
  const props = {}
  const moveitOnTopSpy = jest.spyOn(WrappedMyComponent.prototype, 'moveitOnTop');
  const handleBackSpy = jest.spyOn(WrappedMyComponent.prototype, 'handleBack');
  const wrapper = mount(
    <WrappedMyComponent {...props} />
  );

  // 1. I need to check that class .c-ftsOnTop exists
  wrapper.setState({ isSearchActive: true });  // <= set isSearchActive to true so .c-ftsOnTop is added
  expect(wrapper.find('.c-ftsOnTop')).toHaveLength(1);  // Success!

  // 2. I need to check onClick function that calls this.props.handleBack & `this.props.moveitOnTop'
  window.scrollTo = jest.fn();  // mock window.scrollTo
  wrapper.find('input').props().onClick();
  expect(moveitOnTopSpy).toHaveBeenCalled();  // Success!
  expect(window.scrollTo).toHaveBeenCalledWith(0, -100);  // Success!
  expect(handleBackSpy).toHaveBeenCalled();  // Success!

  // 3. I need to check if className emailBlock exists
  expect(wrapper.find('.emailBlock')).toHaveLength(1);  // Success!
})

详细信息

.c-ftsOnTop仅在isSearchActivetrue时添加,因此只需设置组件的状态即可添加类。

如果您在moveitOnTophandleBack的原型方法上创建间谍,那么当hoc通过将其实例方法绑定到构造函数中的this来创建其实例方法时,实例方法将绑定到您的间谍。

window.scrollTo默认在jsdom中将错误记录到控制台,因此您可以模拟该错误以避免该错误消息并验证是否已使用期望的参数调用了该错误消息。


请注意,以上测试要求在MyComponent中修复以下拼写错误:

  • extender应该是extends
  • constructor应该接受一个props参数
  • onClick应该绑定到this.handleClick而不是handleClick
  • handleClick应该呼叫this.props.goBack()而不是this.props.handleBack()

(我猜MyComponent只是作为实际组件的一个例子而已)