原文地址: codeburst.io/testing-rea…
译文地址:github.com/xiao-T/note…
本文版权归原作者所有,翻译仅用于学习。

先前,我们已经知道如何设置 Jest 和 Enzyme,并且,顺便了解了 Jest 中如何模拟 ES 和 CommonJS 模块。
在这篇文章中,我们将会看到更多的示例:如何通过 Enzyme 创建特殊的测试场景模拟组件中用户的交互。
如本系列第一篇文章所述,我们将会用 Enzyme 的 mount 的方法来实现组件的完整的渲染。来自文档的总结:
在需要组件与 DOM API 交互或者测试那些被高阶组件包含的组件时,完整的 DOM 渲染是最理想的方式
如果,你不打算在浏览器中运行测试,推荐使用
mount
,它依赖 jsdom 库,这个库本质上是一个用 JS 实现的 headless 浏览器。
这让我们可以与组件交互,就像在浏览器中一样。
以下是基本的版本配置:
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-to-json": "^3.3.3",
模拟事件
Enzyme 中模拟用户交互的语法非常简单直接,以下就是最简单的示例:
component.find(selector).simulate(event);
选择器
选择器 是下面的其中之一:
- CSS 选择器
- Prop 属性选择器
- Prop 对象选择器
- React 组件构造函数
- React 组件
displayName
在这篇文章中,我们只会查看 CSS 选择器的几种不同方式。如果,CSS 选择器不能满足你的需求,可以继续查阅文档,Enzyme 的文档写的非常好,也有很好的演示。
通过文档我们知道 CSS 选择器支持以下几种:
- 类选择器(
.foo
.foo-bar
等) - 元素选择器(
input
div
span
等) - ID 选择器(
#foo
#foo-bar
等) - 属性选择器(
[href="foo"]
[type="text"]
等)
以上语法也可以组合使用(button#id-foo
)。
如果,父组件中存在多个需要交互的子组件时,一个常见的错误:Method "simulate" is only meant to be run on a single node. 3 found instead
。
这也很容易修复,你可以给需要交互的 node 指定索引:
// the initial
component.find([className="checkbox__input"]).simulate(event);
// becomes
component.find([className="checkbox__input"]).at(1).simulate(event);
事件
Enzyme 的方法 simulate 可以用来模拟 DOM 事件,常用的有:click
、change
、keydown
。选定 node 后,可以直接链式调用 simulate 来完成模拟交互:
component.find(selector).simulate('click');
component.find(selector).simulate('change');
component.find(selector).simulate('keydown', { keyCode: 32 });
编写测试用例
测试重新渲染
如果,DOM 事件引起组件重新渲染,卸载子组件,这时,Jest 快照测试就可以来验证组件是否正确的重新渲染。
it('should be possible to open menu with Spacebar', done => {
const component = mount(<MyComponent />);
component.find('#link-id').simulate('keydown', { keyCode: 32 });
expect(component).toMatchSnapshot();
component.unmount();
});
测试函数调用
如果,一个函数传递了子组件,你希望在父组件挂载的时候,验证它是否被正确的调用。首先,需要模拟这个函数,然后,以 prop 的形式传递下去。
const mockFunction = jest.fn();
it('should call mockFunction on button click', () => {
const component = mount(
<MyComponent onClickFunction={mockFunction} />
);
component.find('button#ok-btn').simulate('click');
expect(mockFunction).toHaveBeenCalled();
component.unmount();
});
测试 state 或者 prop 的更新
it('sets loading state to true on save press', () => {
const component = mount(<MyComponent />);
component.find('[className="save-button"]').simulate('click');
expect(component.state('isLoading')).toEqual(true);
component.unmount();
});
与 document 的其他交互
因为,mount
可以渲染完整的 DOM,因此,可以包含其他很多方面的测试。
这也包括与当前 document 关联的 cookies。它可以通过 document.cookie
访问。为了防止测试之间相互影响,你或许需要用到以下方式
beforeEach(() => {
document.cookie = '';
});
去重置它的值。
如果,组件在挂载时想同步 cookie 的值到 state 中,可以考虑以下的测试:
it('syncs state with user cookie on mount', () => {
document.cookie = 'cookieOne=valueOne:::false&valueTwo:::true';
const component = mount(<MyComponent />);
expect(component.state('valueOne')).toEqual(false);
expect(component.state('valueTwo')).toEqual(true);
component.unmount();
});
最后的思考
希望这能说明在一起使用 Jest 和 Enzyme 是存在可能,这里的示例也具可读性,足以用到你自己的项目中。
另外一个提示:如果,用户交互没有产生预期的结果,Enzyme 中的 debug 可以帮到你
console.log(component.debug())
这时,需要去看看组件挂载后的快照。
多谢你们喜欢,如果,你有更多的见解,可以在评论中提出!😁
我还写了其他的文章: