JavaScript 测试系列实战(二):深层渲染和快照测试
共 4569字,需浏览 10分钟
·
2020-08-31 09:17
在上一篇教程中,我们已经介绍了使用 Enzyme 测试 React 组件的基本知识。今天,我们将更深入地挖掘并学习如何测试组件的 Props,如何(以及为什么)使用 mount 函数,以及什么是 Jest 快照测试。
测试组件的 Props
在前一篇文章中,我们已经测试了传递 Props 给组件的情况。但实际上,我们可以直接测试 Props。让我们回到之前写的 ToDoList 组件,但是这次我们使用一个 Task 组件。
Task 组件的代码如下:
// src/Task.js
import React from 'react';
const Task = (props) => (
<li id={props.id}>{props.name}li>
);
export default Task;
修改后的 TodoList 组件代码如下:
// src/TodoList.js
import React from 'react';
import Task from "../Task/Task";
const ToDoList = (props) => {
return (
<ul>
{
props.tasks.map(task =>
<Task key={task.id} id={task.id} name={task.taskName}/>
)
}
ul>
)
};
export default ToDoList;
然后我们来测试 ToDoList 组件是否能够渲染 Task 组件并传递正确的 Props:
// src/TodoList.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ToDoList from './ToDoList';
describe('ToDoList component', () => {
describe('when provided with an array of tasks', () => {
it('passes them to the Task components', () => {
const tasks = [
{
id: 0,
name: 'Wash the dishes'
},
{
id: 1,
name: 'Make the bed'
}
];
const toDoListInstance = shallow(
<ToDoList tasks={tasks}/>
);
toDoListInstance.find('Task').forEach(taskInstance => {
const taskProps = taskInstance.props();
const matchingTask = tasks.find(task => task.id === taskProps.id);
expect(taskProps.name).toBe(matchingTask.name);
})
})
});
});
通过上面的测试代码,我们可以确定 Task 组件从 ToDoList 收到了正确的 Props。由于 toDoListInstance
和 taskInstance
都是继承自 Enzyme 浅包装器 ShallowWrapper
,因此可以调用 props
方法来获取一个组件传入的 Props。不仅如此,我们还可以检查组件状态,甚至更改状态。想要查看可用函数的完整列表,可以浏览 Enzyme 文档 https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md。
mount 完全渲染
但是,如果我们想测试 Task 组件中 li
标签的实际内容呢?也许我们可以像下面这样写:
toDoListInstance.find('Task').forEach(taskInstance => {
const taskProps = taskInstance.props();
const matchingTask = tasks.find(task => task.id === taskProps.id);
const listItem = taskInstance.first('li');
expect(listItem.text()).toBe(matchingTask.name);
}
如果运行测试,我们会遇到一个错误:
FAIL app/components/ToDoList/ToDoList.test.js
● ToDoList component › when provided with array of tasks › passes them to the Task components
expect(received).toBe(expected) // Object.is equality
Expected: "Wash the dishes"
Received: " "
23 | const matchingTask = tasks.find(task => task.id === taskProps.id);
24 | const listItem = taskInstance.first('li');
\> 25 | expect(listItem.text()).toBe(matchingTask.name);
| ^
26 | })
27 | })
28 | });
这里之所以失败,是因为浅层渲染 shallow 的局限性:子组件 Task 将根本不会渲染,因此就无法判断是否渲染出正确的内容。
针对浅层渲染的局限性,Enzyme 提供了完全渲染函数 mount
:
const toDoListInstance = mount(
<ToDoList tasks={tasks}/>
);
上面的代码会将完整的 ToDoList 和它所有子组件一起渲染。因此,之前失败的测试现在就会通过。
由于 mount
函数会模拟实际的 DOM,渲染成本更高,因此运行测试会花费更多的时间。通常我们会在集成测试中使用 mount
函数,测试组件之间如何协同工作,而不仅仅是作为独立的单元。
如果你不了解单元测试和集成测试这两个术语,可以看下本系列第一篇教程。
在测试与 DOM 的交互或者在处理高阶组件时,mount 函数也可以派上用场。_Mount 使用 DOM 实现的模拟,Jest 默认使用的是 jsdom。我们可以通过调整 testEnvironment
属性更改。
快照测试
快照测试是 Jest 的一大招牌功能。所谓快照,可以简单地理解成是我们应用的一个**“代码截图”**。当我们运行快照测试时,Jest 将会渲染组件并创建其快照文件。这个快照文件包含渲染后组件的整个结构,并且应该与测试文件本身一起提交到代码库。当我们再次运行快照测试时,Jest 会将新的快照与旧的快照进行比较,如果两者不一致,测试就会失败,从而帮助我们确保用户界面不会发生意外改变。
在 TodoList 的测试代码中添加快照测试:
// src/TodoList.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ToDoList from './ToDoList';
describe('ToDoList component', () => {
describe('when provided with an array of tasks', () => {
it('should render correctly', () => {
const tasks = [
{
id: 0,
name: 'Wash the dishes'
},
{
id: 1,
name: 'Make the bed'
}
];
const toDoListInstance = shallow(
<ToDoList tasks={tasks}/>
);
expect(toDoListInstance).toMatchSnapshot();
});
});
});
运行上面的代码后,就会产生 ToDoList.test.js.snap 文件,它的内容如下:
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ToDoList component when provided with array of tasks should render correctly 1`] = `
id={0}
key="0"
name="Wash the dishes"
/>
id={1}
key="1"
name="Make the bed"
/>
`;
_
如果我们要对 ToDoList 组件进行任何更改,快照测试就会失败,并且显示当前渲染结果与快照之间的精确差异。如果我们要更新所有失败的快照,可以使用 -u
标志(别名为 --updateSnapshot
) 来运行 Jest。输入以下命令,一键更新所有快照:
npm test -- -u
实际上,目前 CRA 默认会在监听模式下运行 Jest,我们可以一个个更新冲突的快照。首先运行 npm test
,然后输入 i
以交互方式更新失败的快照。官方的 Jest 文档提供了一个动画来展示这个过程:
如果你的 CRA 版本比较老,可以通过
npm test -- --watchAll
来进入 Jest 监听模式。
小结
在本文中,我们介绍了如何直接去测试组件的 Props,并学习了 mount 函数和浅层渲染之间的区别。除此之外,我们还介绍了 Jest 快照测试,这是一个非常强大的工具,可以追踪组件渲染方式的变化。在接下来的文章中,我们还将介绍测试中常见的 Mock 技巧——与组件的模拟交互,不见不散!
扫码关注公众号,订阅更多精彩内容。
给个[在看],是对达达最大的支持!