Vite+TS+Jest, 配置+踩坑记录

1,553 阅读3分钟

前言

手上有个项目规模越来越大了, 开始时偷懒没有写测试, 后面越想越后悔, 不少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"
    }
}

这样配置下来, 就可以开始写测试了, 如果没有其他问题, 就应该不会有问题了。

Suggestion (2).gif

好嘛, 我就知道不会那么顺利, 在写完一个测试准备执行的时候给我报错了...

报错一: 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"来解决:

  1. 文件内使用import.meta.env的地方换成process.env
  2. 修改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
  }
})

到目前为止我遇到的就是这两个问题, 修改完之后终于可以顺利跑完测试了(虽然我也只写了一个测试用例😁)

image.png

关于vitest

上面那个vite repo的讨论里, 最后Vite给出的方案是写了一个新的,Vite原生的单元测试框架 Vitest | A blazing fast unit test framework powered by Vite, 兼容Jest, 解决了讨论重提到的各种问题(比如那个alias不用配置两遍了!)...就...看起来真棒。

关键是为啥我是在把坑踩完了之后才看到这个的呢😂, 后面有空再看看这个, 好用的话再迁移过去吧。