前言
手上有个项目规模越来越大了, 开始时偷懒没有写测试, 后面越想越后悔, 不少bug有测试的话应该能避免的。 而且现在功能越加越多, 每次迭代都只能依靠类型检查来稍微提供一些安全感🤦♂️, 思来想去, 还是打算配置一个测试框架, 把单元测试补起来, 正所谓磨刀不误砍柴工啊。
关于Jest这里就不多介绍了, 反正就...挺好使, 看看官方文档就成。
ts-jest
Jest会将测试代码转换为js来执行测试,而我的项目用的是Typescript, 就需要一个代码转换的过程。
Jest默认提供了一个转换器:babel-jest, 此外因为babel不会进行类型检查, 还提供了一个可选的转换器:ts-jest。
ts-jest提供了包括类型检查在内的所有TS特性 It supports all features of TypeScript including type-checking. 这么厉害那我们当然选择它了。
安装
pnpm add -D jest ts-jest @types/jest
配置
首先是jest.config.ts, 主要是下面几个配置项
export default {
// ...
globals: {
'ts-jest': {
// 指定ts config文件
tsconfig: '<rootDir>/tsconfig.test.json',
// 使用esm而非commonjs
useESM: true,
},
},
}
extensionsToTreatAsEsm: ['.ts'],
preset: 'ts-jest',
// ...
然后是tsconfig.json:
{
// ...
"compilerOptions": {
// ...
"types": ["vite/client", "jest"],
"module": 'esnext'
}
}
最后在package.json内加上测试命令:
{
//...
"scripts": {
// ...
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest"
}
}
这样配置下来, 就可以开始写测试了, 如果没有其他问题, 就应该不会有问题了。
好嘛, 我就知道不会那么顺利, 在写完一个测试准备执行的时候给我报错了...
报错一: Cannot find module
项目Vite内配置了若干别名, 在导入时可以直接从别名导入:
// file: vite.config.ts
resolve: {
alias: [
// ...
{ find: 'widgets', replacement: `${srcPath}/widgets` },
]
}
但Jest执行的时候没有这个上下文, 从别名导出的语句就会引起Cannot find module报错, 需要在Jest配置文件内再配置一遍:
// file: jest.config.ts
{
moduleNameMapper: {
// ...
'^widgets/(.*)': '<rootDir>/src/widgets/$1',
},
}
报错二: import.meta.env is undefined
import.meta 是ESM提供的模块元数据对象, vite把自己的环境变量写在了这个对象上, 同样的Jest运行时因为跟Vite完全无关, 也就得不到这些环境变量了, 在遇到使用这个边境变量的文件时就会报错。
vite repo 内有个相关的, 很长很长的讨论feature: first class Jest integration · Issue #1955 · vitejs/vite (github.com), 基本上就是如何获得更好的Vite+Jest体验, 针对我遇到的这个问题, 暂时可以通过"降级为process.env"来解决:
- 文件内使用
import.meta.env的地方换成process.env - 修改vite.config.ts:
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd())
// expose .env as process.env instead of import.meta since jest does not import meta yet
const envWithProcessPrefix = Object.entries(env).reduce(
(prev, [key, val]) => {
return {
...prev,
['process.env.' + key]: `"${val}"`,
}
},
{},
)
return {
define: envWithProcessPrefix,
// other config
}
})
到目前为止我遇到的就是这两个问题, 修改完之后终于可以顺利跑完测试了(虽然我也只写了一个测试用例😁)
关于vitest
上面那个vite repo的讨论里, 最后Vite给出的方案是写了一个新的,Vite原生的单元测试框架 Vitest | A blazing fast unit test framework powered by Vite, 兼容Jest, 解决了讨论重提到的各种问题(比如那个alias不用配置两遍了!)...就...看起来真棒。
关键是为啥我是在把坑踩完了之后才看到这个的呢😂, 后面有空再看看这个, 好用的话再迁移过去吧。