在 Enzyme 中使用 Lab 与 Code:Hapi 测试框架下的 React 组件测试指南
【免费下载链接】enzymeJavaScript Testing utilities for React项目地址: https://gitcode.com/gh_mirrors/en/enzyme
本指南围绕 docs/guides/lab.md 展开,讲解如何将 Enzyme 与 Hapi 生态中的测试工具 Lab 及其断言库 Code 组合使用,为 React 组件编写结构清晰、断言可读的测试。读完本文,你将掌握 Lab 的 suite/test 组织方式、Code 的链式断言风格,以及如何让 Enzyme 的shallow/mount/render三种渲染 API 在 Lab 测试中正确工作。
Lab 与 Code 是什么
Lab 是 Node.js 生态中一款简洁的测试工具,属于 Hapi.js 框架生态的组成部分。它最初大量借鉴了 Mocha 的设计理念,因此如果你熟悉 Mocha 的describe/it结构,Lab 的suite/test会非常容易上手。Code 则是 Lab 配套的标准断言库,其定位是 Chai 的直接重写,继承了 Chai 广受欢迎的链式断言风格(如expect(...).to.equal(...))。
两者配合使用时,Enzyme 负责渲染 React 组件并暴露可查询的 wrapper,Lab 负责组织测试用例与报告结果,Code 负责对组件渲染结果进行断言。
安装与初始化
安装依赖
在你的项目中安装 Enzyme、适配器以及 Lab 和 Code:
npm install --save-dev enzyme enzyme-adapter-react-16 lab code需要说明的是:enzyme 适配器需要与你项目中的 React 版本对应(React 16 使用enzyme-adapter-react-16,其余版本可参考仓库中的 安装文档 与 packages 目录下对应的适配器包)。
配置 Enzyme 适配器
Enzyme v3 及以后版本要求显式配置 React 适配器。参考仓库内示例项目 enzyme-example-mocha/src/Foo.spec.jsx 的写法,在测试入口(或每个测试文件)中执行:
import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({ adapter: new Adapter() });从源码看,configure由 configuration.js 的merge导出(见 index.js),用于将适配器等全局配置合入 Enzyme 内部配置。
准备 DOM 环境
如果测试中使用了mount(完整渲染到真实 DOM)或render(静态渲染 HTML),需要先提供一个浏览器环境。最常用的方式是 jsdom,具体配置方法可参考仓库中的 jsdom 指南。
示例测试:enzyme + Lab + Code
以下是原文档提供的完整示例,展示了三者协作的基本形态:
import { shallow, mount, render } from 'enzyme'; import React from 'react'; const Code = require('code'); const Lab = require('lab'); const lab = Lab.script(); export { lab }; lab.suite('A suite', () => { lab.test('calls componentDidMount', (done) => { const wrapper = mount(<Foo />); Code.expect(Foo.prototype.componentDidMount.callCount).to.equal(1); done(); }); });逐行拆解这段代码:
- 导入 Enzyme 三种渲染 API:
shallow、mount、render分别对应浅渲染、完整 DOM 渲染和静态 HTML 渲染。它们在 index.js 中统一对外导出,实现分别位于 shallow.js(返回ShallowWrapper)与 mount.js(返回ReactWrapper)。 Lab.script():创建一个独立的 Lab 测试脚本实例。通过export { lab }将脚本导出,Lab 运行器才能发现并执行其中的用例;也可以不导出而直接用require('lab').script()在文件内组织用例。lab.suite/lab.test:suite定义一组测试,test定义单个用例。这里在用例中mount(<Foo />)完整渲染组件,触发componentDidMount生命周期,随后用Code.expect(...).to.equal(1)断言其被调用过一次。- 回调风格
done:示例使用异步回调风格,断言完成后必须调用done(),Lab 才会认为用例结束。这是 Lab 兼容老式 Node 测试习惯的体现,也方便测试异步生命周期。
生命周期断言为什么可行
Foo.prototype.componentDidMount.callCount之所以能拿到调用次数,是因为mount会真实地把组件挂载进文档并触发完整生命周期。从 mount.js 可以看到mount(node, options)直接返回new ReactWrapper(node, null, options),其挂载过程中会走适配器并执行组件的挂载钩子。这也是mount与shallow的关键区别:shallow只渲染组件本身、不渲染子组件,主要用于"单元级"断言;需要验证生命周期副作用、DOM 事件或子组件协作时,应使用mount。
运行测试
在终端执行:
labLab 默认会扫描项目中的测试文件并运行全部用例,输出通过/失败统计。与 Mocha 的describe/it相比,Lab 通过Lab.script()显式声明脚本边界,且断言必须依赖 Code(或其他兼容断言库),这是 Hapi 生态强约定风格的体现。
把示例扩展为更完整的测试
在真实项目中,你通常会在一个文件内组合多种断言风格。结合原文档示例与仓库中 enzyme-example-mocha 的写法,可以扩展出如下形态:
import React from 'react'; import { shallow, mount } from 'enzyme'; import { expect } from 'code'; import { lab } from './setup'; lab.suite('Foo 组件', () => { lab.test('shallow 渲染出期望的 DOM 结构', () => { const wrapper = shallow(<Foo />); expect(wrapper.contains(<div className="foo" />)).to.equal(true); expect(wrapper.is('.foo')).to.equal(true); }); lab.test('mount 后能通过 find 查询到节点', () => { const wrapper = mount(<Foo />); expect(wrapper.find('.foo').length).to.equal(1); }); });shallow(...).contains(...)、is(...)、find(...)这些查询方法分别对应 ShallowWrapper 与 ReactWrapper 上的公开 API,其完整签名与行为可参考 ReactWrapper 文档 与 ShallowWrapper 文档。
常见注意事项
- 适配器必须配置:忘记调用
Enzyme.configure({ adapter })时,Enzyme 会报错或回退到默认适配器,务必在测试入口统一配置。 mount依赖 DOM:没有 jsdom 等环境时mount无法工作;纯shallow测试对 DOM 的依赖较低。- 回调风格记得调用
done():使用(done) => {...}的用例若遗漏done(),测试会一直挂起直至超时。 - 适配器版本与 React 匹配:不同 React 版本需要不同适配器包,仓库中 packages 目录按 React 13/14/15/16 系列分别提供了对应适配器实现,选用时需与项目 React 版本严格对应。
相关资源
- 原文档: docs/guides/lab.md
- 其他测试框架集成指南: docs/guides(含 Mocha、Jest、Karma、jsdom 等)
- 示例项目:仓库内的 enzyme-example-mocha 提供了 Mocha + Chai 的完整可运行范例,其测试文件写法可平移至 Lab + Code
- API 文档: ReactWrapper 与 ShallowWrapper 下的各方法说明
【免费下载链接】enzymeJavaScript Testing utilities for React项目地址: https://gitcode.com/gh_mirrors/en/enzyme
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考