首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【译】使用Enzyme和React Testing Library测试React Hooks

【译】使用Enzyme和React Testing Library测试React Hooks

作者头像
腾讯IVWEB团队
发布2020-06-28 10:12:03
发布2020-06-28 10:12:03
4.7K00
代码可运行
举报
运行总次数:0
代码可运行

原文:https://css-tricks.com/testing-react-hooks-with-enzyme-and-react-testing-library/

当你开始在应用中使用React Hooks时,你需要确保编写的代码是可靠的。确保代码没有bug的一种方法就是编写测试用例。测试React hooks与测试一般程序的方式没有太大区别。

在本教程中,我们将了解如何通过使用带有hooks的to-do应用程序来实现这一点。我们将介绍使用EnzymeReact Testing Library编写测试,这两个库都能做到这一点。如果你第一次使用Enzyme,我们之前发布过关于它的文章,《Enzyme如何在React应用中与Jest一起使用》。我们可以用他们来深入测试React Hooks。

这里有我们想要测试的

一个标准的待办事项组件是这样的:

代码语言:javascript
代码运行次数:0
运行
复制
import React, { useState, useRef } from "react";
const Todo = () => {
  const [todos, setTodos] = useState([
    { id: 1, item: "Fix bugs" },
    { id: 2, item: "Take out the trash" }
  ]);
  const todoRef = useRef();
  const removeTodo = id => {
    setTodos(todos.filter(todo => todo.id !== id));
  };
  const addTodo = data => {
    let id = todos.length + 1;
    setTodos([
      ...todos,
      {
        id,
        item: data
      }
    ]);
  };
  const handleNewTodo = e => {
    e.preventDefault();
    const item = todoRef.current;
    addTodo(item.value);
    item.value = "";
  };
  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <h2>Add Todo</h2>
        </div>
      </div>
      <form>
        <div className="row">
          <div className="col-md-6">
            <input
              type="text"
              autoFocus
              ref={todoRef}
              placeholder="Enter a task"
              className="form-control"
              data-testid="input"
            />
          </div>
        </div>
        <div className="row">
          <div className="col-md-6">
            <button
              type="submit"
              onClick={handleNewTodo}
              className="btn btn-primary"
            >
              Add Task
            </button>
          </div>
        </div>
      </form>
      <div className="row todo-list">
        <div className="col-md-6">
          <h3>Lists</h3>
          {!todos.length ? (
            <div className="no-task">No task!</div>
          ) : (
            <ul data-testid="todos">
              {todos.map(todo => {
                return (
                  <li key={todo.id}>
                    <div>
                      <span>{todo.item}</span>
                      <button
                        className="btn btn-danger"
                        data-testid="delete-button"
                        onClick={() => removeTodo(todo.id)}
                      >
                        X
                      </button>
                    </div>
                  </li>
                );
              })}
            </ul>
          )}
        </div>
      </div>
    </div>
  );
};
export default Todo;

使用Enzyme测试

在开始测试之前,我们需要安装这些包。是时候启动终端了!

代码语言:javascript
代码运行次数:0
运行
复制
npm install --save-dev enzyme enzyme-adapter-16

在src目录中,创建一个名为setupTests.js的文件。这是我们用来配置Enzymeadapter

代码语言:javascript
代码运行次数:0
运行
复制
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
Enzyme.configure({ adapter: new Adapter() });

现在我们可以开始写我们的测试代码了!我们想要测试四点:

1、组件渲染

2、渲染时初始待办事项的展示

3、我们可以创建一个新的待办事项然后返回三个待办事项

4、我们可以删除一个初始的待办事项并且只留下一个

在你的src目录中,创建一个名为 tests 的文件夹,并创建一个文件,你可以在其中编写待办事项组件的测试。我们将该文件命名为Todo.test.js

创建完文件,我们可以导入我们需要的包,并且创建一个describe模块来写我们的测试代码。

代码语言:javascript
代码运行次数:0
运行
复制
import React from "react";
import { shallow, mount } from "enzyme";
import Todo from "../Todo";

describe("Todo", () => {
  // Tests will go here using `it` blocks
});
Test 1: 组件渲染

为此,我们将使用浅渲染。浅渲染允许我们检查组件的渲染方法是否被调用——这是我们想要确认的,因为这里我们需要证明组件渲染。

代码语言:javascript
代码运行次数:0
运行
复制
it("renders", () => {
  shallow(<Todo />);
});
Test 2: 展示初始待办事项

这里我们将使用mount方法,它允许我们深入到比shallow更深的地方。这样,我们就可以检查待办事项的长度。

代码语言:javascript
代码运行次数:0
运行
复制
it("displays initial to-dos", () => {
  const wrapper = mount(<Todo />);
  expect(wrapper.find("li")).toHaveLength(2);
});

#### Test 3: 我们可以创建一个新的待办事项然后返回三个待办事项

让我们想一下创建一个新的待办事项的过程:

1、用户在input中输入一个值。

2、用户点击提交按钮。

3、我们获得一共三个待办事项,其中第三个是新创建的。

代码语言:javascript
代码运行次数:0
运行
复制
it("adds a new item", () => {
  const wrapper = mount(<Todo />);
  wrapper.find("input").instance().value = "Fix failing test";
  expect(wrapper.find("input").instance().value).toEqual("Fix failing test");
  wrapper.find('[type="submit"]').simulate("click");
  expect(wrapper.find("li")).toHaveLength(3);
  expect(
    wrapper
      .find("li div span")
      .last()
      .text()
  ).toEqual("Fix failing test");
});

我们挂载组件,然后使用find()instance()方法设置输入字段的值。我们使用断言,在进一步模拟单击事件之前,输入“修复失败测试”,该事件应该将新的项目添加到待办事项列表中。

最后,断言列表中有三个项,并且第三个项与我们创建的项相等。

Test 4: 我们可以删除一个初始待办事项并且仅剩一个待办事项
代码语言:javascript
代码运行次数:0
运行
复制
it("removes an item", () => {
  const wrapper = mount(<Todo />);
  wrapper
    .find("li button")
    .first()
    .simulate("click");
  expect(wrapper.find("li")).toHaveLength(1);
  expect(wrapper.find("li span").map(item => item.text())).toEqual([
    "Take out the trash"
  ]);
});

在这个场景中,我们使用第一个项目上的模拟单击事件返回待办事项。这将调用removeTodo()方法,该方法将删除被单击的item。然后检查我们拥有的item的数量,并且返回的的值。

这四个测试的源代码可以在GitHub上找到。

使用react-testing-library测试

我们将为此写三个测试:

1、初始待办事项的渲染

2、我们可以加一个新的待办事项

3、我们可以删除一个待办事项

首先,我们安装需要的安装包:

代码语言:javascript
代码运行次数:0
运行
复制
npm install --save-dev @testing-library/jest-dom @testing-library/react

接下来,我们可以导入安装包和文件:

代码语言:javascript
代码运行次数:0
运行
复制
import React from "react";
import { render, fireEvent } from "@testing-library/react";
import Todo from "../Todo";
import "@testing-library/jest-dom/extend-expect";

test("Todo", () => {
  // Tests go here
}
Test 1: 初始待办事项的渲染

我们将在test模块里写我们的测试代码。第一个测试是这样的:

代码语言:javascript
代码运行次数:0
运行
复制
it("displays initial to-dos", () => {
  const { getByTestId } = render(<Todo />);
  const todos = getByTestId("todos");
  expect(todos.children.length).toBe(2);
});

这里发生了什么?我们使用getTestId来返回元素的与data-testid匹配的节点。在这个例子里是<ul>元素。然后,我们检查它总共有两个子元素(每个子元素是无序列表中的<li>元素)。如果初始待办事项数量等于2则通过。

Test 2:我们可以添加一个新的待办事项

我们还可以使用getTestById返回与我们传入参数匹配的节点。

代码语言:javascript
代码运行次数:0
运行
复制
it("adds a new to-do", () => {
  const { getByTestId, getByText } = render(<Todo />);
  const input = getByTestId("input");
  const todos = getByTestId("todos");
  input.value = "Fix failing tests";
  fireEvent.click(getByText("Add Task"));
  expect(todos.children.length).toBe(3);
});

我们像之前那样使用getbyTestId来返回input和ul元素。为了模拟添加新待办项的单击事件,我们使用fireEvent.click()方法并传入getByText()方法,该方法返回的是文本与我们传的参数匹配的节点。然后,我们可以通过检查子数组的长度来检查待办事项的长度。

Test 3: 我们可以删除一个待办事项

这个看起来有点像我们之前写的:

代码语言:javascript
代码运行次数:0
运行
复制
it("deletes a to-do", () => {
  const { getAllByTestId, getByTestId } = render(<Todo />);
  const todos = getByTestId("todos");
  const deleteButton = getAllByTestId("delete-button");
  const first = deleteButton[0];
  fireEvent.click(first);
  expect(todos.children.length).toBe(1);
});

我们使用getallbyTestId返回删除按钮的节点。因为我们只想删除一个项目,所以我们对集合中的第一个项目触发一个click事件,它应该删除第一个待办事项。这应该使待办事项子节点的长度等于1。

这些测试也可以在GitHub上找到。

语法检查

当使用hooks时,有两个语法检查规则要遵守:

规则1:在顶层调用钩子

...循环或嵌套函数,而不是内部条件。

代码语言:javascript
代码运行次数:0
运行
复制
// Don't do this!
if (Math.random() > 0.5) {
  const [invalid, updateInvalid] = useState(false);
}

这违反了第一条规则。根据官方文档,React取决于钩子调用的关联状态和相应的useState调用的顺序。这段代码打乱了顺序,因为钩子只有在条件为true时才会被调用。

这也适用于useEffect和其他钩子。查看文档了解更多细节。

规则2:从React功能组件调用钩子

钩子用于React的功能组件,而不是React的类组件或JavaScript函数。

当谈到语法检查,我们基本上涵盖了所有不应该做的情况。我们可以通过一个专门实施这些规则的npm包来避免这些错误。

代码语言:javascript
代码运行次数:0
运行
复制
npm install eslint-plugin-react-hooks --save-dev

下面是配置文件写法:

代码语言:javascript
代码运行次数:0
运行
复制
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

如果你正在使用Create React App,那么你应该知道,从3.0.0版本开始,该包就支持开箱即用的lint插件。

加油写面向对象的React代码!

React钩子和应用中的其他钩子一样容易出错,你要确保你能很好地使用它们。正如我们刚才看到的,有几种方法可以做到这一点。无论你是使用Enzyme或是enzyme与React Testing Library其中之一来写测试完全取决于你。不管怎样,试着使用linting,毫无疑问,你会很高兴你这样做了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 这里有我们想要测试的
  • 使用Enzyme测试
    • Test 1: 组件渲染
    • Test 2: 展示初始待办事项
    • Test 4: 我们可以删除一个初始待办事项并且仅剩一个待办事项
  • 使用react-testing-library测试
    • Test 1: 初始待办事项的渲染
    • Test 2:我们可以添加一个新的待办事项
    • Test 3: 我们可以删除一个待办事项
  • 语法检查
    • 规则1:在顶层调用钩子
    • 规则2:从React功能组件调用钩子
  • 加油写面向对象的React代码!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档