如何有条件地测试样式组件和子元素?

IT技术 reactjs unit-testing enzyme styled-components
2021-05-10 01:21:43

我是单元测试的新手,我在文档、文章和 YT 视频上花了大约 20-30 个小时,但仍然无法理解如何实现这一点。基本上我想在这里测试三件事:

  1. 确保这个组件渲染了 3 个组件
  2. 测试条件样式
  3. 测试点击事件

到目前为止,对于第一件事,如果我尝试这样做:

import { shallow } from "enzyme";
import React from "react";
import ButtonsComponent, { SchedButton } from "./ButtonsComponent";

it("renders three <MyButton /> components", () => {
  const wrapper = shallow(<ButtonsComponent />);
  expect(wrapper.find(MyButton)).to.have.lengthOf(3);
});

我收到以下错误:TypeError:Enzyme::Selector 需要字符串、对象或组件构造函数

我不知道如何测试其他两件事,我看过一些例子,但我不明白如何使它们适应我的特定情况,因为它们似乎并没有完全测试我我正在尝试做。

这是我的组件的简化版本:

import React from "react";
import styled from "styled-components";

const MyButton = styled.button`
  background: ${props =>
    props.color ? theme.palette.secondary.dark : "#e6e6e6"};
  color: ${props => (props.color ? "white" : "#737373")};
`;

const ButtonsComponent = ({ currentState, updateState }) => {
  const handleClick = event => {
    updateState(event.target.value);
  };

  return (
    <div>
      <MyButton
        value="Button 1"
        onClick={handleClick}
        color={currentState === "Button 1" ? "#1fbd45" : ""}
      >
        Button 1
      </MyButton>
      <MyButton
        value="Button 2"
        onClick={handleClick}
        color={currentState === "Button 2" ? "#1fbd45" : ""}
      >
        Button 2
      </MyButton>

      <MyButton
        value="Button 3"
        onClick={handleClick}
        color={!currentState || currentState === "Button 3" ? "#1fbd45" : ""}
      >
        Button 3
      </MyButton>
    </div>
  );
};

export default ButtonsComponent;

非常感谢任何帮助,ELI5 解释会更多!

1个回答

我会尽量详细地回答你的问题。

所以你有3个问题:

1.确保这个组件渲染了3个组件

你的测试几乎是正确的。错误是你在做: wrapper.find(MyButton)而不是wrapper.find('MyButton'). 为此,wrapper.find(MyButton)您需要先导入 MyButton 组件,因此应该可以执行以下操作:

import { shallow } from "enzyme";
import React from "react";
import ButtonsComponent, { MyButton } from "./ButtonsComponent";

it("renders three <MyButton /> components", () => {
  const wrapper = shallow(<ButtonsComponent />);
  expect(wrapper.find(MyButton)).to.have.lengthOf(3);
});

但是您不能在代码中执行此操作,因为您没有导出 MyButton 组件。我对这个问题的建议是为 MyButton 组件创建一个文件,为 ButtonsComponent 组件创建另一个文件。一般来说,每个文件有一个组件会更清晰,单元测试也变得更清晰。然后你将能够做这样的事情:

import { shallow } from "enzyme";
import React from "react";
import ButtonsComponent from "./ButtonsComponent";
import MyButton from "./MyButton"

it("renders three <MyButton /> components", () => {
  const wrapper = shallow(<ButtonsComponent />);
  expect(wrapper.find(MyButton)).to.have.lengthOf(3);
});

2. 测试条件样式

我不知道你使用的是什么测试引擎(mocha、jest 等),但如果我必须选择一个来测试 React 应用程序,我会选择 Jest(不过这只是一个品味问题)。我建议 jest,因为它有你需要的一切,比如间谍、匹配器等,还有一些额外的包可以让你的生活更轻松,就像在这种情况下一样。

因此,要使用 jest 测试您的样式化组件,您将需要两个额外的包react-test-renderer(基本上将 React 组件转换为 js 对象)和jest-styled-components(这将为您提供一个名为 toHaveStyleRule 的额外匹配器,这将对您的目标有很大帮助)。

安装这两个软件包后,您要做的是,首先导入它们:

import renderer from "react-test-renderer";
import "jest-styled-components";

然后你将你的组件转换为一个 js 对象:

const tree =
  renderer
  .create(<MyButton color="red">Test</MyButton>)
  .toJSON();

最后,您将要求使用您为组件指定的属性应用的样式:

expect(tree).toHaveStyleRule("background-color", "red");

3.测试点击事件

要测试单击事件,您将需要一个间谍。如果您使用的是 jest,则您已经拥有此功能,如果您使用的是 mocha,我想您可能需要一个额外的包,例如 sinon 或类似的包。

间谍会让你跟踪你的updateState函数发生了什么,所以当你测试点击事件时,你会传递一个间谍函数作为 updateState props的值。通过这种方式,当您模拟按钮上的点击时,您的间谍将被调用,然后您将能够向它提出问题,例如“您是否被呼叫过?”,因此您将能够在点击事件时检查您使用预期的参数调用 updateState 函数。

此链接中,您会发现您的示例(有一些小的修改)正在运行并测试您想要检查的所有内容(不要注意依赖项出现在 package.json 文件中的位置,其中许多应该出现作为开发依赖项,但出于某种原因,如果我这样做它不起作用,则可能是我在该工具中做错了)。

我希望这个答案对你有帮助。