【问题标题】:How do I shallow test a react component wrapped in memo and withStyles?如何对包含在 memo 和 withStyles 中的 React 组件进行浅层测试?
【发布时间】:2019-07-27 00:16:58
【问题描述】:

我有一个组件,它同时包含在 Material-UI withStyles HOC 和 React memo HOC 中。

我无法测试此组件,因为我无法致电dive()

ShallowWrapper::dive() can only be called on components

我目前知道的唯一选择是独立export Demoexport default withStyles(styles)(Demo)。这使我可以测试未包含在withStyles 中的组件。我想避免这种方法。

如果我删除 memo(),我可以测试组件。同样,如果我删除 withStyles(),我也可以测试该组件。这些 HOC 的组合使我的组件无法测试。

有哪些可用的策略可以有效地测试这个组件?

demo.js

import React, { memo } from "react";
import MUIIconButton from "@material-ui/core/IconButton";
import { withStyles } from "@material-ui/core/styles";
import Tooltip from "@material-ui/core/Tooltip";
import Typography from "@material-ui/core/Typography";

const styles = () => ({
  root: {
    backgroundColor: "red"
    /* more styles... */
  }
});

const Demo = memo(({ label, classes }) => (
  <div className={classes.root}>
    <Tooltip disableFocusListener title={label}>
      <Typography>label</Typography>
    </Tooltip>
  </div>
));

export default withStyles(styles)(Demo);

demo.test.js

import React from "react";
import Adapter from "enzyme-adapter-react-16";
import { configure, shallow } from "enzyme";
import Demo from "./demo";
import MUIIconButton from "@material-ui/core/IconButton";
import Tooltip from "@material-ui/core/Tooltip";

configure({ adapter: new Adapter() });

describe("Demo", () => {
  it("Should have a tooltip with label", () => {
    const tooltip = "My tooltip";

    const el = shallow(<Demo label={tooltip} />).dive();

    expect(el.find(Tooltip).props().title).toEqual(tooltip);
  });
});

完整的工作沙盒

【问题讨论】:

  • 检查github.com/mui-org/material-ui/issues/9266 - createShallow 有一些解决方法。但我宁愿像你已经做的那样继续使用单独的导出。这是更可靠的方式。在某些情况下,比如 Redux 连接的组件,这就像官方的建议。那么在不同的组件中使用相同的方法不是更好吗?

标签: reactjs material-ui enzyme memo


【解决方案1】:

当我用备忘录包裹时,我得到一个看起来像这样的形状

import MemoizedFoo from './Foo'
console.log(MemoizedFoo) 

    { '$$typeof': Symbol(react.memo),
      type:
       { [Function: Foo]
         displayName: 'Foo',
         defaultProps: { theme: {} } },
      compare: null }

所以在我的玩笑测试中,我可以通过引用类型键来获取内部组件

import MemoizedFoo from './Foo'
const Foo = MemoizedFoo.type

describe() { it() { shallow(Foo) ...etc } }

这对于浅层单元测试非常有用。

如果我正在安装一个父组件并寻找存在的子组件,你可以这样做:

wrapper = mount(Layout)
wrapper.find('Memo(Foo)')

【讨论】:

    【解决方案2】:

    正如skyboyer 所建议的,您应该只使用export 记忆函数。您可以import 默认导出HOC 并使用mount,但您需要模拟classes 对象以匹配它在组件中的使用方式。

    工作示例https://codesandbox.io/s/4r492qvoz9

    components/Demo/demo.js

    import React, { memo } from "react";
    import MUIIconButton from "@material-ui/core/IconButton";
    import { withStyles } from "@material-ui/core/styles";
    import Tooltip from "@material-ui/core/Tooltip";
    import Typography from "@material-ui/core/Typography";
    
    const styles = () => ({
      root: {
        backgroundColor: "red"
        /* more styles... */
      }
    });
    
    export const Demo = memo(({ label, classes }) => {
      return (
        <div className={classes.root}>
          <Tooltip disableFocusListener title={label}>
            <Typography>label</Typography>
          </Tooltip>
        </div>
      );
    });
    
    export default withStyles(styles)(Demo);
    

    components/Demo/__tests__/demo.test.js 如果需要查看DOM 结构,则只需使用console.log(wrapper.debug());——例如console.log(mountHOComponent.debug());

    import React from "react";
    import Adapter from "enzyme-adapter-react-16";
    import { configure, shallow, mount } from "enzyme";
    import { Demo } from "../demo";
    import HOCDemo from "../demo";
    
    configure({ adapter: new Adapter() });
    
    const initialProps = {
      label: "My tooltip",
      classes: {
        root: "component-example"
      }
    };
    
    const shallowWrapper = shallow(<Demo {...initialProps} />);
    const mountWrapper = mount(<Demo {...initialProps} />);
    const mountHOComponent = mount(<HOCDemo {...initialProps} />);
    
    describe("Demo", () => {
      afterAll(() => {
        shallowWrapper.unmount();
        mountWrapper.unmount();
      });
    
      it("shallowWrap renders a tooltip with label", () => {
        expect(shallowWrapper.find("WithStyles(Tooltip)").props().title).toBe(
          initialProps.label
        );
      });
    
      it("mountWrap renders a tooltip with label", () => {
        expect(mountWrapper.find("Tooltip").props().title).toBe(initialProps.label);
      });
    
      it("mountHOComponent renders a tooltip with label", () => {
        expect(mountHOComponent.find("Tooltip").props().title).toBe(
          initialProps.label
        );
      });
    });
    

    【讨论】:

    • 谢谢,我们决定硬着头皮采用这种方法,它运行良好。但我仍然不知道为什么 shallow(el).dive().dive() (每个 HOC 规则一次潜水)没有按预期工作。
    【解决方案3】:

    enzyme-adapter-react-16 v1.13.0 开始,现在已修复此问题,增加了 memo dive() 支持。这是一个更新了依赖项的分叉沙箱,以显示两种测试方法(潜水和导出解决方法)现在都通过了。

    【讨论】:

      猜你喜欢
      • 2018-04-28
      • 2020-05-15
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      • 2020-04-20
      • 2019-09-20
      • 2015-12-01
      • 2020-07-19
      相关资源
      最近更新 更多