如何对使用Redux挂钩的非Redux连接的组件进行浅化测试

时间:2019-11-07 09:52:48

标签: reactjs redux react-redux enzyme redux-react-hook

我的ReactJS项目中的jest / enzyme中的单元测试有问题,我将组件转换为ES6,并使用钩子将Redux连接到reducer存储。但是,在此组件中添加了使用挂钩的更改后,该组件的单元测试已被破坏,我花了几天的时间来弄清楚为什么该测试将不再进行浅渲染,因为完全安装可以正常工作。

DemoPage.js

import React  from 'react';
import { useSelector, useDispatch} from 'react-redux';
import * as actions from '../../actions/demoPageActions';
import DemoPageForm from '../demoApp/DemoPageForm';
import {compose} from "recompose";
import {withStyles} from "@material-ui/core";

const styles = theme => ({});

export const DemoPage = () => {
  const demoState = useSelector(state => state.demoPage);
  const dispatch = useDispatch();

  const saveSomething = () => {
    dispatch(actions.saveSomething(demoState));
  };

  const calculateSomething = e => {
    dispatch(actions.calculateSomething(demoState, e.target.name, e.target.value));
  };

  return (
    <DemoPageForm
      onSaveClick={saveSomething}
      onChange={calculateSomething}
      demoState={demoState}
    />
  );
};

export default compose(withStyles(styles))(DemoPage);

DemoPage.spec.js

import React from "react";
import { shallow } from "enzyme";
import {DemoPage} from "./DemoPage";
import DemoPageForm from "../demoApp/DemoPageForm";

describe("<DemoPage />", () => {
  it("should contain <DemoPageForm />", () => {
    const wrapper = shallow(
      <DemoPage/>
    );
    expect(wrapper.find(DemoPageForm).length).toEqual(1);
  });
});

哪个会产生以下错误

 <DemoPage /> › should contain <DemoPageForm />

    Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a <Provider>

       9 | 
      10 | export const DemoPage = () => {
    > 11 |   const demoState = useSelector(state => state.demoPage);
         |                     ^
      12 |   const dispatch = useDispatch();
      13 | 
      14 |   const saveSomething = () => {

这非常令人困惑,因为它仍然应该测试未连接的组件,但是我相信useSelector的钩子会导致此问题,因此在阅读了大约30至40页有关这些内容的内容后,我还没有找到解决方法和最接近的方法我已经使用了可以正常工作的mount,但是我更喜欢进行浅层测试,这是包装在带有模拟存储区的提供程序中的代码和结果

describe("<DemoPage />", () => {
  const mockStore = configureMockStore()
  const store = mockStore(returnInitialState());

  it("should contain <DemoPageForm />", () => {
    const wrapper = shallow(
      <Provider store={store}>
        <DemoPage
          store={store}
        />
      </Provider>
    );

    console.log(wrapper.dive().debug())

    expect(wrapper.find(DemoPageForm).length).toEqual(1);
  });
});
   console.log src/components/containers/DemoPage.spec.js:23
      <DemoPage store={{...}} />

  ● <DemoPage /> › should contain <DemoPageForm />

    expect(received).toEqual(expected) // deep equality

    Expected: 1
    Received: 0

      23 |     console.log(wrapper.dive().debug())
      24 | 
    > 25 |     expect(wrapper.find(DemoPageForm).length).toEqual(1);
         |                                               ^
      26 |   });
      27 | });

如果有人知道如何解决这个问题,那将非常有帮助。干杯

2 个答案:

答案 0 :(得分:1)

我在用酶进行shallow渲染时遇到问题。当前,酶不能完全支持浅色测试组件中的反应钩。您暂时需要使用mount。您可以在与问题#1938

的github绑定的问题页面上跟踪进度

如果您想尝试使用浅表,那么您确实可以使用很多功能。尝试将enzyme-adapter-react-16升级到版本1.15.1或更高版本,以消除一些更明显的问题。截止到19/11/19,当我上次尝试添加它时,它肯定仍然存在问题,但是随着它们解决兼容性问题,它一直在变得越来越好。

答案 1 :(得分:0)

您的测试失败的原因恰恰是shallow仅呈现DOM树的一级。因此,您仅获得树的<Provider />部分,而从未到达<DemoPage />。这也解释了为什么mount可以正常工作。

在使用Google狂潮模式之前,您可能应该更谨慎地read the doc™️。请注意,shallow(node, options)函数接受第二个参数。并提供了两种与React Context交互的方式:

  1. 您可以将Context对象直接传递给options.context
  2. 或者您可以将携带该上下文的提供程序组件传递给options.wrappingComponent

options.wrappingComponent用法的示例代码:

import { Provider } from 'react-redux';
import { Router } from 'react-router';
import store from './my/app/store';
import mockStore from './my/app/mockStore';

function MyProvider(props) {
  const { children, customStore } = props;

  return (
    <Provider store={customStore || store}>
      <Router>
        {children}
      </Router>
    </Provider>
  );
}
MyProvider.propTypes = {
  children: PropTypes.node,
  customStore: PropTypes.shape({}),
};
MyProvider.defaultProps = {
  children: null,
  customStore: null,
};

const wrapper = shallow(<MyComponent />, {
  wrappingComponent: MyProvider,
});
const provider = wrapper.getWrappingComponent();
provider.setProps({ customStore: mockStore });

免责声明:上面的代码是直接从酶文档link here中无害粘贴的。