技术选型:Jest + Enzyme
Jest
Jest是Facebook开源的一个前端测试框架,主要用于React和React Native的单元测试,已被集成在create-react-app中。Jest特点:
-
易用性:基于Jasmine,提供断言库,支持多种测试风格
-
适应性:Jest是模块化、可扩展和可配置的
-
沙箱和快照:Jest内置了JSDOM,能够模拟浏览器环境,并且并行执行
-
快照测试:Jest能够对React组件树进行序列化,生成对应的字符串快照,通过比较字符串提供高性能的UI检测
-
Mock系统:Jest实现了一个强大的Mock系统,支持自动和手动mock
-
支持异步代码测试:支持Promise和async/await
-
自动生成静态分析结果:内置Istanbul,测试代码覆盖率,并生成对应的报告
下面是一个使用Jest进行单元测试的例子:
javascript
// sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
// sum.test.js
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
Enzyme
Enzyme是Airbnb开源的React测试工具库库,它功能过对官方的测试工具库ReactTestUtils的二次封装,提供了一套简洁强大的 API,并内置Cheerio,实现了jQuery风格的方式进行DOM 处理,开发体验十分友好。在开源社区有超高人气,同时也获得了React 官方的推荐。
下面是一个使用Enzyme进行单元测试的例子:
javascript
import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('renders correctly', () => {
const wrapper = shallow(<MyComponent />);
expect(wrapper).toMatchSnapshot();
});
it('increments the count when the button is clicked', () => {
const wrapper = shallow(<MyComponent />);
const button = wrapper.find('button');
button.simulate('click');
expect(wrapper.state('count')).toEqual(1);
});
});
约定
推荐按照业界通用实践的规范,我们有如下约定:
- 单元测试的代码放置在 tests 目录下
- 单元测试文件命名格式使用 xxx.test.ts
相关配置
在项目根目录下创建jest.config.js文件,参数说明可以参考:jestjs.io/docs/en/con...
javascript
module.exports = {
// 块名称的映射关系
moduleNameMapper: {
'^#src/(.*)$': '<rootDir>/src/$1',
'^@tencent/uno-ui': '<rootDir>/../../node_modules/@tencent/uno-ui-v2',
},
// 指定哪些文件不需要被收集代码覆盖率
coveragePathIgnorePatterns: [
'<rootDir>/.storybook/',
'<rootDir>/.bin/',
'<rootDir>/.build/',
'<rootDir>/.build-docs/',
],
// 指定需要收集代码覆盖率的文件
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'],
// 指定在运行测试之前需要执行的脚本文件
setupFilesAfterEnv: ['<rootDir>/src/test/setupTests.ts'],
// 测试环境
testEnvironment: 'jsdom',
// 指定模块解析器,这里指定了一个自定义的解析器用于解决uuid库报错的问题
resolver: `${__dirname}/src/test/resolver.js`,
};
遇到的问题
因为uuid只提供ESM浏览器导出,而不提供CommonJS导出出现了下面的报错,详情见下面的git链接
github.com/uuidjs/uuid...
javascript
/jest-bug/node_modules/uuid/dist/esm-browser/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { default as v1 } from './v1.js';
^^^^^^
SyntaxError: Unexpected token 'export'
> 1 | import { v4 } from "uuid";
| ^
2 | import { nanoid } from "nanoid";
3 |
4 | export function getUuid() {
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1773:14)
解决办法
github.com/jestjs/jest...
github.com/microsoft/a...
javascript
// https://github.com/jestjs/jest/issues/12770
// https://github.com/microsoft/accessibility-insights-web/pull/5421/commits/9ad4e618019298d82732d49d00aafb846fb6bac7
module.exports = (path, options) =>
// Call the defaultResolver, so we leverage its cache, error handling, etc.
options.defaultResolver(path, {
...options,
// Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
packageFilter: (pkg) => {
// This is a workaround for https://github.com/uuidjs/uuid/pull/616
//
// jest-environment-jsdom 28+ tries to use browser exports instead of default exports,
// but uuid only offers an ESM browser export and not a CommonJS one. Jest does not yet
// support ESM modules natively, so this causes a Jest error related to trying to parse
// "export" syntax.
//
// This workaround prevents Jest from considering uuid's module-based exports at all;
// it falls back to uuid's CommonJS+node "main" property.
//
// Once we're able to migrate our Jest config to ESM and a browser crypto
// implementation is available for the browser+ESM version of uuid to use (eg, via
// https://github.com/jsdom/jsdom/pull/3352 or a similar polyfill), this can go away.
if (pkg.name === 'uuid') {
delete pkg.exports;
delete pkg.module;
}
return pkg;
},
});
相关框架
ts-jest 是 Jest 的 TypeScript 预处理器。
@types/jest 和 @jest/types 是 Jest 的类型声明文件。
jest-environment-jsdom 是 Jest 的一个测试环境,用于在 Node.js 中模拟浏览器环境。
babel-jest 是 Jest 的一个预处理器,用于处理 ES6+ 语法。
enzyme 是一个流行的 React 组件测试工具。
enzyme-adapter-react-16 是适用于 React 16 版本的 Enzyme 适配器。
@types/enzyme 和 @types/enzyme-adapter-react-16 是 Enzyme 的类型声明文件