7

使用 vitest 做单元测试 - rxliuli blog

 1 year ago
source link: https://blog.rxliuli.com/p/a9f8e0634b3f476687a2e844470fba44/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

使用 vitest 做单元测试

使用 vitest 做单元_
2023年2月22日 下午

2.7k 字

23 分钟

本文最后更新于:2023年2月22日 晚上

vitest 是一个新的单元测试工具,它很快,默认支持 esm,兼容 jest api,可以被视为更好的 jest。在默认情况下,它支持以下正在使用的功能

  • 支持 esm
  • 兼容 jest api
  • 支持 vite 的功能
  • 支持多框架 react/vue

官网: https://vitest.dev/

vitest 内部依赖 vite,但不需要安装 vite。

npm i -D vitest

好吧,实际上 vitest 是真正的零配置,支持 ts/esm/tsx,但如果你想要更多的功能,确实可以创建 vitest.config.ts 文件或者直接在 vite.config.ts 中添加配置。

基本上,它与 jest 类似,在要测试文件的同级目录创建一个 __tests__ 文件夹,然后在其中创建一个文件,文件名以 .test.ts 结尾,文件内容如下

import { expect, it } from 'vitest'

it('hello', () => {
expect(1 + 2).eq(3)
})

然后运行 pnpm vitest hello.test.ts 就可以以监视模式运行单元测试了

如果有多个测试时可以使用 describe 分组

import { describe, expect, it } from 'vitest'

describe('math', () => {
it('add', () => {
expect(1 + 2).eq(3)
})
it('less', () => {
expect(1 - 2).eq(-1)
})
})

describe('string', () => {
it('hello', () => {
const hello = (name: string) => `hello ${name}`
expect(hello('world')).eq('hello world')
})
})

也可以使用 -t 参数指定要执行的测试,例如

pnpm vitest hello.test.ts -t 'add'

也可以使用 it.only/descrive.only 来指定要执行的测试

另外一些 beforeEach/afterEach 等钩子函数也是支持的

例如默认创建一个测试目录

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const tempPath = path.resolve(__dirname, '.temp', path.basename(__filename))
beforeEach(async () => {
await rm(tempPath, { recursive: true, force: true })
await mkdir(tempPath, { recursive: true })
})
afterEach(async () => {
await rm(tempPath, { recursive: true, force: true })
})

vitest 默认内嵌 chaijs 作为断言库,并且兼容了 jest 的断言 api。

最有趣的是,它支持某些断言很简洁,例如断言一些常见的值

expect(true).true
expect(false).false
expect(undefined).undefined
expect(null).null

或者对比值

expect(1).eq(1)
expect({ name: 'world' }).deep.eq({ name: 'world' }) // 深度对比

web api polyfill

通常在 web 项目中测试时也会包含一些 dom api,例如 localStorage/indexedDB 等。

happy-dom

dom 相关的 api mock 可以通过 happy-dom 来实现,它是一个简单的 dom 实现,可以在 node 中运行,虽然 api 比 jsdom 少一些,但速度要更快。

{
"test": {
"environment": "happy-dom"
}
}

使用 localStorage

expect(localStorage.getItem('test')).null
localStorage.setItem('test', 'test')
expect(localStorage.getItem('test')).eq('test')
localStorage.removeItem('test')

fetch

nodejs@18 支持了 fetch 请求,不再需要 polyfill。

indexedDB

遗憾的是 hyppy-dom 没有实现 indexedDB,所以我们需要使用 fake-indexeddb 做 polyfill。
这个不需要做什么配置,只需要在测试文件中引入即可

import 'fake-indexeddb/auto'
import { openDB } from 'idb'

it('indexeddb', async () => {
const db = await openDB<{
books: {
title: string
author: string
isbn: string
}
}>('test', 1, {
upgrade(db) {
db.createObjectStore('books', {
autoIncrement: true,
keyPath: 'isbn',
})
},
})
expect(await db.getAll('books')).empty
await db.add('books', {
title: 'Quarry Memories',
author: 'Fred',
isbn: 123456,
})
await db.add('books', {
title: 'Water Buffaloes',
author: 'Fred',
isbn: 234567,
})
expect(await db.getAll('books')).length(2)
})
  • vitest 有一个 vscode 插件,但目前尚未支持 monorepo,所以建议不要使用
  • vitest 基于 vite,__dirname/__filename 等变量在测试中可用,但实际上在 nodejs esm 中不可用
  • vitest 与 node:test 的 api 有重叠,尤其是 it/describe,要留意不要错误引用

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK