Vitest 是基于 vite 的一款测试框架,其几近完美地兼容了 jest 的语法,使得迁移起来非常简单,可以在 StackBlitz 上在线尝试 Vitest。

安装

# 使用 npm
$ npm install -D vitest
# 使用 yarn
$ yarn add -D vitest
# 使用 pnpm
$ pnpm add -D vitest

Vitest 需要 Vite >=v2.7.10 和 Node >=v14

配置

Vitest 的配置可以写在 vite 的配置文件中,Vite 的 resolve.alias 和 plugins 的配置将会在 Vitest 中起作用;也可以单独书写 vitest.config.ts,且优先级高于集成的写法。

import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  test: {
    globals: true,
  },
  plugins: [vue()],
})

注意,在集成的写法中,引入的 defineConfig 的 target 需要该问 vitest/config。globals 开启之后将会和 jest 一样,不需要引入方法。例如

未开启 globals 之前的测试用例

image-20220822194316350

开启 globals 之后,就可以不需要引入了

image-20220822194254459

这样运行测试是没问题的,但是 ts 的类型检查还存在问题,我们需要在 tsconfig.json 中添加类型

{
  "compilerOptions": {
    // ......
    "types": [
      "vitest/globals"
    ]
  },

我上面是安装了 vitest 的插件,可以在 vscode 的插件商店直接搜索下载

image-20220823074511456

更多配置项参考 Vitest 配置索引

在 package.json 中添加执行脚本

{
  "scripts": {
    "test": "vitest",
    "coverage": "vitest run --coverage"
  }
}

test 用于执行测试用例,默认会执行项目中的spec.ts结尾的测试文件,可以添加参数来控制执行范围,例如test reactivity 就只会执行文件名中带有 reactivity 的测试文件,可以和 Jest 一样对文件改定进行监听,文件变更时自动执行测试test watch

coverage 用于计算覆盖率,需要安装额外的依赖pnpm add -D @vitest/coverage-c8,安装完成之后执行就能看到测试用例的覆盖率了,例如我有如下文件

export function add(num1: number, num2: number) {
  return num1 + num2
}

export function sub(num1: number, num2: number) {
  return num1 - num2
}

针对这个文件有如下测试用例

describe('utils test', () => {
  it('add', () => {
    expect(add(1, 3)).toBe(4)
  })

  it('sub', () => {
    expect(sub(4, 1)).toBe(3)
  })
})

执行覆盖率测试之后的结果是

image-20220823075615100

快照测试

Vitest 的快照测试同 Jest 一致,会在测试目录下生成快照文件,后续的测试会跟文件内的快照进行匹配,如果匹配不一致则会抛出错误。

it('snapShot', () => {
  expect('snapShot').toMatchSnapshot()
})

运行测试之后,生成文件

image-20220823111705943

如果修改 expect 的值则会抛出异常

image-20220823111824690

如果要更新快照,使用-u 参数

$ vitest -u

需要全局安装 Vitest(npm install -g vitest)或者使用 npx vitest -u命令

Vitest 几乎完全支持 Jest 的快照测试代码,除了极少数的区别

  • 文件标注不同,Vitest 中是// Vitest Snapshot v1,Jest 中是// Jest Snapshot v1, https://goo.gl/fbAQLP

  • printBasicPrototype 默认为 false,Jest 和 VItest 的快照功能都由 pretty-format 支持,区别在于 Jest 的默认值为 true。如果仍然需要开启,可以在配置中打开。

    export default defineConfig({
      test: {
        snapshotFormat: {
          printBasicPrototype: true
        }
      }
    })
    

Vitest UI

Vitest 提供了一套非常美观的 Web UI,可以安装依赖之后启动

$ npm i -D @vitest/ui

完成安装之后通过vitest --ui来启动测试的 UI 界面

image-20220823141853570

Web UI可以查看测试文件,点击测试文件之后会列出文件下的测试套件等信息,右侧有测试结果,依赖关系,源码以及控制台打印等选项,在依赖关系中点击对应的节点即可显示该节点对应的源码以及编译后的代码。

image-20220823142415270

总的来说这套 UI 的颜值还是在线的。

内联测试

Vitest 除了支持测试文件爱你之外,还支持内联测试,即在源码文件中进行测试用例的编写。例如

export function add(num1: number, num2: number) {
  return num1 + num2
}

export function sub(num1: number, num2: number) {
  return num1 - num2
}

if (import.meta.vitest) {
  const { it, expect } = import.meta.vitest
  it('add123', () => {
    expect(add(1, 2)).toBe(3)
  })
}

此时typescript 环境下编辑器会报错 import.meta.vitest 找不到,此时需要在 tsconfig.json 中添加类型。

"compilerOptions": {
  "types": [
    "vitest/importMeta"
  ]
},

上面只是解决了语法检查的爆报错,要想成功运行内联测试还需要再 vitest 的配置中将源码目录添加到执行范围。

export default defineConfig({
  test: {
    includeSource: ['src/**/*.{js,ts}']
  },
  // 生产环境开启,将会删除掉内联测试代码
  // define: {
  //   'import.meta.vitest': 'undefined'
  // },
})

此时执行测试就会发现内联测试已经执行。

image-20220823144109868

内联测试只针对于简单的功能进行小范围测试,如果是复杂的测试最好还是单独分理出测试文件。

附:Vitest 命令选项

选项 描述
-v, --version 显示版本号
-r, --root <path> 定义项目根目录
-c, --config <path> 定义配置文件路径
-u, --update 更新快照
-w, --watch 智能即时浏览模式
-t, --testNamePattern <pattern> 使用与模式匹配的全名运行测试
--dir <path> 用于扫描测试文件的基本目录
--ui 启用 UI
--open 如果启用,则自动打开 UI (default: true)
--api [api] 服务 API,可用选项:--api.port <port>--api.host [host]--api.strictPort
--threads 启用线程 (default: true)
--silent 测试的控制台输出
--isolate 为每个测试文件隔离环境 (default: true)
--reporter <name> 选择报告器:defaultverbosedotjunitjson 或自定义报告器的路径
--outputTruncateLength <length> 使用 <length> 指定截断输出差异的字符行数
--outputDiffLines <lines> 使用 <lines> 指定输出差线的数量
--outputFile <filename/-s> 当还指定了 --reporter=json--reporter=junit 选项时,将测试结果写入文件 通过 [cac’s dot notation] 可以为多个报告器指定单独的输出
--coverage 使用 c8 进行覆盖率输出
--run 不使用浏览模式
--mode 覆盖 Vite 模式 (default: test)
--mode <name> 覆盖 Vite 模式 (default: test)
--globals 注入全局 API
--dom 使用 happy-dom 模拟浏览器 API
--browser 在浏览器中运行测试
--environment <env> 设置运行的环境 (default: node)
--passWithNoTests 未找到测试时通过
--allowOnly 允许标记为 only 的测试和套件 (default: false in CI, true otherwise)
--dangerouslyIgnoreUnhandledErrors 忽略发生的任何未处理的错误
--changed [since] 运行受更改文件影响的测试 (default: false),更多内容请查看 文档
--shard <shard> 配置测试分片
--sequence 定义运行测试的顺序,使用 [cac’s dot notation] 来指定选项(例如,使用 --sequence.suffle 以随机顺序运行测试)
--no-color 从控制台输出中禁用颜色
-h, --help 显示可用的 CLI 选项


前端小白