最近在继续开发之前的 Kindle UI 库,想到该写一下测试,于是决定使用 Mocha 的测试方案(尝试一些新东西)。
(此段由GPT生成👉)在开发过程中,保证代码质量和正确性是非常重要的。测试是达到这个目的的有效方法之一,特别是在 JavaScript 开发中。在 React 应用开发中,Mocha 和 Chai 是两个非常流行的测试框架。本文将介绍如何使用 Mocha 和 Chai 测试 React 应用。
为什么不用 react 官方推荐的 Jest 测试?
jest 最初是为测试 react app 设计的。相比 Jest, Mocha 具有更高的灵活性(后者可以且必须进行额外的配置,而前者开箱即用),可以在浏览器和 node 环境下运行,并且支持一些复杂的语句例如:
1expect(person.age).to.be.lte(35).and.to.be.gte(18);Q 2
由于我的项目并非单个 react app 而是 monorepo,所以在 workspace 根目录使用 mocha 无疑是更好的选择。
安装依赖
Mocha 本身是不支持 JSX 的,所以我们要安装一些依赖:
1yarn add mocha -D 2 3# Babel 配套插件 4yarn add -W -D @babel/preset-env @babel/preset-react @babel/preset-typescript @babel/register 5 6# 此依赖用于渲染 react, 请根据 react 版本选择依赖版本! 7yarn add react-test-renderer@17.0.2 -D -W
注意:如果你在 workspace 根目录安装测试依赖(推荐的做法),记得添加 -W 参数。
配置 Mocha
在项目根目录创建一个 .mocharc.js 文件,内容如下:
1module.exports = { 2 extension: ["js", "mjs", "ts", "tsx"], 3 ignore: ["**/build/**", "**/node_modules/**"], 4 recursive: true, 5 timeout: (process.env.CIRCLECI === "true" ? 5 : 2) * 1000, // Circle CI has low-performance CPUs. 6 reporter: "dot", 7 require: [require.resolve("./test/utils/setupBabel")], 8 "watch-ignore": [ 9 ".git", 10 "**/node_modules/**", 11 "**/build/**", 12 "docs/.next/**", 13 ], 14}; 15
在 /test/utils/setupBabel 目录创建一个 setupBabel.js 文件
1require("@babel/register")({ 2 extensions: [".js", ".ts", ".tsx"], 3});
配置 Babel
有了 babel, 我们可以使用 cjs 格式的测试文件而无需进行 "type": "module" 这种令人讨厌的设置。
1// babel.config.js 2module.exports = function getBabelConfig(api) { 3 const useESModules = api.env(["legacy", "modern", "stable", "rollup"]); 4 5 const presets = [ 6 [ 7 "@babel/preset-env", 8 { 9 browserslistEnv: process.env.BABEL_ENV || process.env.NODE_ENV, 10 modules: useESModules ? false : "commonjs", 11 }, 12 ], 13 [ 14 "@babel/preset-react", 15 { 16 runtime: "automatic", 17 }, 18 ], 19 "@babel/preset-typescript", 20 ]; 21 22 const plugins = []; 23 24 return { 25 assumptions: { 26 noDocumentAll: true, 27 }, 28 presets, 29 plugins, 30 ignore: [/@babel[\\\\|/]runtime/], // Fix a Windows issue. 31 overrides: [ 32 { 33 exclude: /\\.test\\.(js|ts|tsx)$/, 34 plugins: ["@babel/plugin-transform-react-constant-elements"], 35 }, 36 ], 37 }; 38}; 39
测试
在 package.json 添加快捷脚本,此处请根据实际项目配置:
1"test:unit": "cross-env NODE_ENV=test mocha --config .mocharc.js 'packages/kindle-ui/**/*.test.{mjs,js,ts,tsx}' 'test/utils/**/*.test.{js,ts,tsx}'" 2
之后我们可以愉快地编写测试了。
关于 react-test-renderer 的更多用法,可以参考官方文档。
此处列举一些常见测试场景供参考:
检查组件类型
1import * as React from "react"; 2import { expect } from "chai"; 3import renderer from "react-test-renderer"; 4// 建议使用 link 后的包,以确保贴近实际场景。 5import { ListItem } from "@kindle-ui/core"; 6 7describe("<ListItem />", () => { 8 describe("prop: component", () => { 9 it("renders a div", () => { 10 const component = renderer.create(<ListItem />); 11 expect(component.toTree().rendered).to.have.property("type", "div"); 12 }); 13 14 it("renders a link", () => { 15 const component = renderer.create( 16 <ListItem component="a" href="#" /> 17 ); 18 expect(component.toTree().rendered).to.have.property("type", "a"); 19 }); 20 }); 21}); 22
检查渲染结果
1it("render in Container", () => { 2 expect(() => 3 renderer.create( 4 <Container> 5 <ListItem>test</ListItem> 6 </Container> 7 ) 8 ).not.to.throw(); 9}); 10
改进
react 官方提供的测试库功能比较局限,例如,我们无法测试一个元素是否可见,也无法模拟用户操作页面。
所以,我们可以使用@testing-library/react来进行进一步改进。
注意,node 环境下没有 document 对象,需要使用 JSDom 这个库模拟一个。
先为 mocha 添加钩子:
1// .mocharc.js 2 3module.exports = { 4 {/**... */} 5 beforeEach: () => { 6 const dom = new JSDOM("", { 7 pretendToBeVisual: true, 8 url: "<http://localhost>", 9 }); 10 global.window = dom.window; 11 }, 12};
更新测试代码:
1import { queries, within } from "@testing-library/react/pure"; 2 3describe("general rendering", async () => { 4 it("render in Container", async () => { 5 render(<ListItem>KindleUI</ListItem>); 6 7 expect( 8 within(document.body, { ...queries }) 9 .getByRole("ListItem") 10 .toHaveTextContent("KindleUI") 11 ).to.be(true); 12 }); 13}); 14