集成 Vitest
Vitest 是来自 Vite 生态系统的测试运行器。将其与 Turborepo 集成将带来巨大的速度提升。
Vitest 文档展示了如何创建一个"Vitest 工作区",从一个根命令运行单体仓库中的所有测试,使得合并覆盖率报告等功能开箱即用。这个功能不遵循单体仓库的现代最佳实践,因为它的设计是为了与 Jest 兼容(其工作区功能是在包管理器工作区之前构建的)。
因此,你有两个选择,每个选择都有自己的权衡:
利用 Turborepo 进行缓存
为了提高缓存命中率并且只运行有变化的测试,你可以选择为每个包配置任务,将 Vitest 命令拆分成每个包中单独的、可缓存的脚本。这种速度带来的权衡是你需要自己创建合并的覆盖率报告。
完整示例,请运行 npx create-turbo@latest --example with-vitest
或
访问示例的源代码。
设置
假设我们有一个简单的包管理器工作区,如下所示:
apps/web
和 packages/ui
都有自己的测试套件,vitest
安装在使用它们的包中。它们的 package.json
文件包含运行 Vitest 的 test
脚本:
在根目录的 turbo.json
中,创建一个 test
任务:


现在,turbo run test
可以并行化并缓存每个包的所有测试套件,只测试已更改的代码。
在监视模式下运行测试
当你在 CI 中运行测试套件时,它会记录结果并最终在完成时退出。这意味着你可以用 Turborepo 缓存它。但是当你在开发过程中使用 Vitest 的监视模式运行测试时,进程永远不会退出。这使得监视任务更像是一个长期运行的开发任务。
因为这种差异,我们建议指定两个单独的 Turborepo 任务:一个用于运行测试,一个用于在监视模式下运行它们。
下面的策略创建了两个任务,一个用于本地开发,另一个用于 CI。你可以选择将 test
任务用于本地开发,而创建一个 test:ci
任务。
例如,在每个工作区的 package.json
文件中:
以及,在根目录的 turbo.json
中:


你现在可以使用全局 turbo
运行 turbo run test:watch
,或者从根 package.json
中的脚本运行:
创建合并的覆盖率报告
Vitest 的工作区功能创建了一个开箱即用的覆盖率报告,合并了所有包的测试覆盖率报告。但是按照 Turborepo 策略,你将不得不自己合并覆盖率报告。
with-vitest
示例
展示了一个完整的例子,你可以根据自己的需求进行调整。你可以使用 npx create-turbo@latest --example with-vitest
快速开始。
要做到这一点,你需要遵循几个一般步骤:
- 运行
turbo run test
创建覆盖率报告。 - 使用
nyc merge
合并覆盖率报告。 - 使用
nyc report
创建报告。
要完成的 Turborepo 任务看起来像:


这样设置后,运行 turbo test && turbo report
创建合并的覆盖率报告。
with-vitest
示例
展示了一个完整的例子,你可以根据自己的需求进行调整。你可以使用 npx create-turbo@latest --example with-vitest
快速开始。
使用 Vitest 的工作区功能
Vitest 工作区功能不遵循与包管理器工作区相同的模型。相反,它使用一个根脚本,然后延伸到仓库中的每个包,处理该包中的测试。
在这个模型中,从现代 JavaScript 生态系统的角度来看,没有包边界。这意味着你不能依赖 Turborepo 的缓存,因为 Turborepo 依赖于这些包边界。
因此,如果你想使用 Turborepo 运行测试,你需要使用根任务。一旦你配置了 Vitest 工作区,为 Turborepo 创建根任务:


**值得注意的是,根任务的文件输入默认包括所有包,因此任何包中的任何更改都将导致缓存未命中。**虽然这确实简化了创建合并覆盖率报告的配置,但你将错过缓存重复工作的机会。
使用混合方法
你可以通过实施混合解决方案来结合两种方法的优势。这种方法在保留 Turborepo 在 CI 中的缓存的同时,统一了使用 Vitest 工作区方法的本地开发。这带来的权衡是稍微更多的配置和仓库中的混合任务运行模型。
在这种设置中,你的包保持各自的 Vitest 配置和脚本:
而你的根 package.json
包含全局运行测试的脚本:
这种配置允许开发者在根目录运行 pnpm test:workspace:watch
以获得无缝的本地开发体验,而 CI 继续使用 turbo run test
来利用包级缓存。你仍然需要像上一节描述的那样手动处理合并的覆盖率报告。