特性

一套配置可以运用在多种环境

与 Vite 的配置、转换器、解析器和插件通用,将会使用应用程序中的相同配置来运行测试。

监听模式

智能文件监听模式,像用于测试的 HMR !

  1. $ vitest -w

Vitest 智能搜索模块依赖树并只重新运行相关测试(就像 HMR 在 Vite 中的工作方式一样!)。

vitestvitest devvitest watch 是别名,默认情况下它们都以监听模式启动 vitest。它们还依赖于 CI 环境变量,如果它已定义,Vitest 将只运行一次测试,就像是 vitest run 一样。

与 UI 框架的平滑集成

可以测试 Vue、React、Lit 等框架中的组件

开箱即用的常见 Web 支持

开箱即用的 TypeScript / JSX 支持 / PostCSS

ESM 优先

ESM 优先,支持模块顶级 await

多线程

通过 tinypool 使用 Worker 线程尽可能多地并发运行( Piscina 的轻量级分支),允许多个测试同时运行。Vitest 默认启动多线程,可以通过 CLI 中的 --no-threads 禁用。

Vitest 还隔离了每个测试文件的运行环境,因此一个文件中的运行环境改变不会影响其他文件。可以通过将 --no-isolate 传递给 CLI 来禁用隔离(以正确性换取运行性能)。

过滤

套件和测试的过滤、超时、并发配置

CLI

你可以使用 CLI 按名称过滤测试文件:

  1. $ vitest basic

只能执行文件名包含 basic 的测试文件,例如

  1. basic.test.ts
  2. basic-foo.test.ts

指定超时时间

可以选择以毫秒为单位将超时时间作为第三个参数传递给测试。默认值为 5 秒。

  1. import { test } from 'vitest'
  2. test('name', async () => { ... }, 1000)

Hooks 也可以接收超时时间,默认值为 5 秒。

  1. import { beforeAll } from 'vitest'
  2. beforeAll(async () => { ... }, 1000)

跳过测试套件和测试用例

使用 .skip 来跳过运行某些测试套件或测试用例。

  1. import { describe, assert, it } from 'vitest';
  2. describe.skip("skipped suite", () => {
  3. it("test", () => {
  4. // 测试套件已跳过,没有错误
  5. assert.equal(Math.sqrt(4), 3);
  6. });
  7. });
  8. describe("suite", () => {
  9. it.skip("skipped test", () => {
  10. // 测试用例跳过,没有错误
  11. assert.equal(Math.sqrt(4), 3);
  12. });
  13. });

指定运行测试套件和测试用例

使用 .only 仅运行某些测试套件或测试。

  1. import { describe, assert, it } from 'vitest'
  2. // 仅运行此测试套件(以及其他标有 `only` 的测试套件)
  3. describe.only("suite", () => {
  4. it("test", () => {
  5. assert.equal(Math.sqrt(4), 3);
  6. });
  7. });
  8. describe("another suite", () => {
  9. it("skipped test", () => {
  10. // 测试已跳过,因为测试在 Only 模式下运行
  11. assert.equal(Math.sqrt(4), 3);
  12. });
  13. it.only("test", () => {
  14. // 仅运行此测试用例(以及其他标记 `only` 的测试用例)
  15. assert.equal(Math.sqrt(4), 2);
  16. });
  17. });

未实现的测试套件和测试用例

使用 .todo 记录应该实现的测试套件和测试用例

  1. import { describe, it } from 'vitest'
  2. // 该测试套件的报告中将显示一个条目
  3. describe.todo("unimplemented suite");
  4. // 此测试的报告中将显示一个条目
  5. describe("suite", () => {
  6. it.todo("unimplemented test");
  7. });

同时运行多个测试

在连续测试中使用 .concurrent 将会并发运行它们。

  1. import { describe, it } from 'vitest'
  2. // 标有 `concurrent` 的两个测试用例将并发运行
  3. describe("suite", () => {
  4. it("serial test", async () => { /* ... */ });
  5. it.concurrent("concurrent test 1", async () => { /* ... */ });
  6. it.concurrent("concurrent test 2", async () => { /* ... */ });
  7. });

如果在测试套件中使用 .concurrent,则其中的每个测试用例都将并发运行。

  1. import { describe, it } from 'vitest'
  2. // 该测试套件中的所有测试都将并行运行
  3. describe.concurrent("suite", () => {
  4. it("concurrent test 1", async () => { /* ... */ });
  5. it("concurrent test 2", async () => { /* ... */ });
  6. it.concurrent("concurrent test 3", async () => { /* ... */ });
  7. });

您还可以将 .skip.only.todo 用于并发测试套件和测试用例。 在 API 参考 中阅读更多信息。

快照

支持 Jest Snapshot 功能

Chai 和兼容 Jest expect 语法

内置 Chai 进行断言和与 Jest expect 兼容的 API

注意,如果你正在使用添加匹配器的第三方库,将 test.globals 设置为 true 将提供更好的兼容性。

对象模拟

内置 Tinyspy 用于在 vi 对象上使用 jest 兼容的 API 进行对象模拟。

  1. import { vi, expect } from 'vitest'
  2. const fn = vi.fn()
  3. fn('hello', 1)
  4. expect(vi.isMockFunction(fn)).toBe(true)
  5. expect(fn.mock.calls[0]).toEqual(['hello', 1])
  6. fn.mockImplementation((arg) => arg)
  7. fn('world', 2)
  8. expect(fn.mock.returns[1]).toBe('world')

Vitest 支持 happy-domjsdom 来模拟 DOM 和浏览器 API。Vitest 并不内置它们,所以您可能需要安装:

  1. $ npm i -D happy-dom
  2. # 或
  3. $ npm i -D jsdom

之后,更改 environment 配置文件中的选项:

  1. // vite.config.ts
  2. import { defineConfig } from 'vitest/config'
  3. export default defineConfig({
  4. test: {
  5. environment: 'happy-dom' // 或 'jsdom', 'node'
  6. }
  7. })

了解更多关于对象模拟的信息

代码测试覆盖率

Vitest 通过 c8 来输出代码测试覆盖率

  1. {
  2. "scripts": {
  3. "test": "vitest",
  4. "coverage": "vitest run --coverage"
  5. }
  6. }

可以在配置文件中设置 test.coverage 选项来配置它:

  1. // vite.config.ts
  2. import { defineConfig } from 'vitest/config'
  3. export default defineConfig({
  4. test: {
  5. coverage: {
  6. reporter: ['text', 'json', 'html']
  7. }
  8. }
  9. })

源码内联测试

Vitest 还提供了一种方式,可以运行与你的代码实现放在一起的测试,就像是 Rust 语言的模块测试一样

这使得测试与实现共享相同的闭包,并且能够在不导出的情况下针对私有状态进行测试。同时,它也使开发更加接近反馈循环。

  1. // src/index.ts
  2. // the implementation
  3. export function add(...args: number[]) {
  4. return args.reduce((a, b) => a + b, 0)
  5. }
  6. // in-source test suites
  7. if (import.meta.vitest) {
  8. const { it, expect } = import.meta.vitest
  9. it('add', () => {
  10. expect(add()).toBe(0)
  11. expect(add(1)).toBe(1)
  12. expect(add(1, 2, 3)).toBe(6)
  13. })
  14. }

了解更多 源码内联测试