【问题标题】:How to shallow test a non redux connected component that uses redux hooks如何对使用 redux 钩子的非 redux 连接组件进行浅层测试
【发布时间】:2020-03-03 21:02:55
【问题描述】:

我的 ReactJS 项目中的 jest/enzyme 单元测试有问题,我将我的组件转换为 ES6 并使用钩子将我的 redux 连接到减速器存储。然而,在这个组件中添加了使用钩子的更改之后,它的单元测试已经被破坏了,我花了几天时间试图弄清楚为什么这个测试将不再浅渲染,因为完全安装可以正常工作。

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 页有关这些内容的内容后,我还没有找到最接近的解决方案我得到的是使用挂载,它工作得很好,但是我更喜欢这个测试的浅层,这是包装在带有模拟存储的提供程序中时的代码和结果

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 | });

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

【问题讨论】:

    标签: reactjs redux react-redux enzyme


    【解决方案1】:

    我在使用酶进行shallow 渲染时遇到了问题。目前,酶不完全支持浅渲染测试组件中的反应挂钩。您暂时需要使用 mount 。您可以在 issue #1938 中与他们的 github 相关的 issue 页面上跟踪进度。

    如果您想尝试使用 shallow,您目前可以使用相当多的功能。尝试将enzyme-adapter-react-16 升级到1.15.1 或更新版本,以消除一些更明显的问题。到 19 年 11 月 12 日我最后一次尝试添加它时,它肯定仍然存在问题,但随着他们解决兼容性问题,它一直在变得更好。

    【讨论】:

      【解决方案2】:

      您的测试失败正是因为shallow 只渲染了一层 DOM 树。因此,您只能获得树的&lt;Provider /&gt; 部分,永远不会到达&lt;DemoPage /&gt;。这也解释了为什么 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复制粘贴。

      【讨论】:

        猜你喜欢
        • 2019-11-11
        • 2021-06-04
        • 2016-05-09
        • 2021-05-27
        • 1970-01-01
        • 2020-03-30
        • 1970-01-01
        • 2016-12-24
        • 1970-01-01
        相关资源
        最近更新 更多