当前位置: 首页 > 工具软件 > Vitest > 使用案例 >

jest迁移vitest的心智认知与实践指南

百里飞捷
2023-12-01

前言

开门见山,Why vitest ? Why migrate vitest from jest ? 在官方文档中已经给出了答案:

vite 也在 antfu 的影响下迁移到了 vitest ,详见:

在一个实践的角度,从 Vite 上来看,从 jest 迁移到 vitest 的成本并不高,大多是配置文件和环境的适配,对于业务代码不需要有太大的变动,这也是坚定我们从 jest 迁移 vitest 的一个先见之明。

对于迁移 jest 的方法官方已经给出了一套简单的教程:

这里我们只描述几个迁移的重点,提升心智上的认知。

正文

commonjs 场景的转换适配

由于 vitest 是 esm first 的,这意味着他不支持混合场景测试,比如用 typescript 编写的产物为 cjs 格式的库(在 nodejs 应用领域比较多),这种情况我们的解法是手动人为 transform typescript 到 cjs 格式。

关于此部分的内容和具体底层逻辑心智较重,详见此文来打通认知:

最大可能的 jest 兼容

如果你没有用到特殊的 jest 专有特性,那么 vitest 和 jest 在测试 api 上完全一致的设计可以让你无缝过渡到 vitest ,而不需要变动任何测试的代码逻辑。

虽然 api 设计一致,但命名空间不同,此处显著的问题即是 global.jest ,比如 jest.fn() 等 api 是会混杂带 jest 主体命名的,而对应在 vitest 中是 vi.fn() ,命名主体是 vi 。对此我们的解法是在 setup 阶段前置脚本中进行等价兼容:

// vitest-compatible-jest.js

// 举一个例子,比如 jest 中 `test.skip` 的别名是 `xtest`
// 但是在 vitest 中没有该别名,于是我们手动兼容即可。
if (!global.xtest) {
  global.xtest = test.skip
}

// 此处进行全局 jest 对象的兼容
if (!global.jest) {
  global.jest = vi
}
// vitest.config.ts

import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    setupFiles: [
      './vitest-compatible-jest.js'
    ]
  }
})

如此一来,全局对象、一些 alias 问题便迎刃而解,当然,如果可以在全部源码中搜索并替换 jestvi 则更清真一些,毕竟兼容无法确保 100% 没有 edge case 。

区分 browser 和 lib 的场景关系

我们往往不光有 lib 代码的测试,还有 react 的 web 应用测试,所以要区分开他们的关系。

react scene

react 场景下我们要考虑的基本点如下。

虚拟 dom 环境

在 jest 中 jsdom 是由 jest-environment-jsdom 支持的,到了 vitest 则需要选择一种虚拟 dom 环境应对策略,如:

// vitest.config.ts

import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    environment: 'jsdom', // or `happy-dom` / `node`
  }
})

<= jest 27 时 jsdom 是 jest 内置的,到了 jest 28 则需要显示安装 jest-environment-jsdom

而在 vitest 中是全部显示安装的,使用 jsdom 就安装 jsdom ,否则依赖会找不到。

project settings 等价

关于这一点,就是要消除项目配置(一般是 webpack)和测试框架间的 gap ,让他们等价。比如 alias 的配置,要在 resolve.alias 进行适配。

由于 vitest 底层是 vite ,所以所有 vite 的选项也将在 vitest 可用,更多配置详见 vite 官方文档( Vite Shared Options )。

包括 css modules 等的适配也是同理,因为 vite 天生支持 css modules ,而在 jest 中需要使用 object proxy 对象代理,所以在一些细节上会有不同,需要留心注意。

lib scene

此处的场景我们只需要关注 cjs 产物需要被 hook 转译即可:

// vitest-transform-ts.ts

// hook 对 `.ts` 文件的导入,进行热转译加载
// ......
// vitest.config.ts

import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    setupFiles: [
      './vitest-transform-ts'
    ]
  }
})

总结

综合来说,我们的注意力主要用于突破 react 和 commonjs 两个最常见场景的心智,但实际上还存在集成测试,e2e 等场景,关于这一点,vite 为我们提供了良好的示范,你可以在 vite 仓库内学习到更多。

在收益上,不但迁移的改动小,迁移后速度也有 30% 以上的提升。其实在某些底层原理上两者大同小异,但回顾来看, jest 的臃肿才是拖慢我们测试速度不可忽视的一个要因。

 类似资料: