expect
以下类型用于下面的类型签名
type Awaitable<T> = T | PromiseLike<T>
expect
用于创建断言。在此上下文中,断言
是可以调用的函数来断言一个语句。Vitest 默认提供 chai
断言,并且还基于 chai
构建了与 Jest
兼容的断言。
例如,这段代码断言 input
值等于 2
。如果不是,断言将抛出错误,测试将失败。
import { } from 'vitest'
const = .(4)
()..(2) // chai API
().(2) // jest API
从技术上讲,此示例没有使用 test
函数,因此您将在控制台中看到 Node.js 错误而不是 Vitest 输出。要了解有关 test
的更多信息,请阅读 测试 API 参考。
此外,expect
可以静态地用于访问匹配器函数(稍后描述)等等。
警告
expect
对测试类型没有影响,如果表达式没有类型错误。如果您想将 Vitest 用作 类型检查器,请使用 expectTypeOf
或 assertType
。
soft
- 类型:
ExpectStatic & (actual: any) => Assertions
expect.soft
的功能类似于 expect
,但它不会在断言失败时终止测试执行,而是继续运行并将失败标记为测试失败。测试期间遇到的所有错误都将显示,直到测试完成。
import { , } from 'vitest'
('expect.soft test', () => {
.(1 + 1).(3) // mark the test as fail and continue
.(1 + 2).(4) // mark the test as fail and continue
})
// At the end of the test, the above errors will be output.
它也可以与 expect
一起使用。如果 expect
断言失败,测试将被终止,所有错误都将被显示。
import { , } from 'vitest'
('expect.soft test', () => {
.(1 + 1).(3) // mark the test as fail and continue
(1 + 2).(4) // failed and terminate the test, all previous errors will be output
.(1 + 3).(5) // do not run
})
警告
expect.soft
只能在 test
函数内使用。
not
使用 not
将否定断言。例如,这段代码断言 input
值不等于 2
。如果相等,断言将抛出错误,测试将失败。
import { , } from 'vitest'
const = .(16)
()...(2) // chai API
()..(2) // jest API
toBe
- 类型:
(value: any) => Awaitable<void>
toBe
可用于断言基本类型是否相等,或者对象是否共享相同的引用。它等效于调用 expect(Object.is(3, 3)).toBe(true)
。如果对象不同,但您想检查它们的结构是否相同,可以使用 toEqual
。
例如,下面的代码检查交易者是否有 13 个苹果。
import { , } from 'vitest'
const = {
: 'apples',
: 13,
}
('stock has 13 apples', () => {
(.).('apples')
(.).(13)
})
('stocks are the same', () => {
const = // same reference
().()
})
尽量不要将 toBe
用于浮点数。由于 JavaScript 对它们进行了舍入,因此 0.1 + 0.2
并不严格等于 0.3
。要可靠地断言浮点数,请使用 toBeCloseTo
断言。
toBeCloseTo
- 类型:
(value: number, numDigits?: number) => Awaitable<void>
使用 toBeCloseTo
比较浮点数。可选的 numDigits
参数限制了要检查的小数点后数字的数量。例如
import { , } from 'vitest'
.('decimals are not equal in javascript', () => {
(0.2 + 0.1).(0.3) // 0.2 + 0.1 is 0.30000000000000004
})
('decimals are rounded to 5 after the point', () => {
// 0.2 + 0.1 is 0.30000 | "000000000004" removed
(0.2 + 0.1).(0.3, 5)
// nothing from 0.30000000000000004 is removed
(0.2 + 0.1)..(0.3, 50)
})
toBeDefined
- 类型:
() => Awaitable<void>
toBeDefined
断言该值不等于 undefined
。有用的用例是检查函数是否返回了任何内容。
import { , } from 'vitest'
function () {
return 3
}
('function returned something', () => {
(()).()
})
toBeUndefined
- 类型:
() => Awaitable<void>
与 toBeDefined
相反,toBeUndefined
断言该值等于 undefined
。有用的用例是检查函数是否没有返回任何内容。
import { , } from 'vitest'
function (: string) {
if ( === 'Bill')
return 13
}
('mary doesn\'t have a stock', () => {
(('Mary')).()
})
toBeTruthy
- 类型:
() => Awaitable<void>
toBeTruthy
断言该值转换为布尔值时为真。如果您不关心该值,但只想了解它是否可以转换为 true
,这很有用。
例如,有了这段代码,您就不关心 stocks.getInfo
的返回值——它可能是复杂的对象、字符串或任何其他东西。代码仍然可以工作。
import { Stocks } from './stocks.js'
const stocks = new Stocks()
stocks.sync('Bill')
if (stocks.getInfo('Bill'))
stocks.sell('apples', 'Bill')
因此,如果您想测试 stocks.getInfo
是否为真值,您可以编写
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'
const stocks = new Stocks()
test('if we know Bill stock, sell apples to him', () => {
stocks.sync('Bill')
expect(stocks.getInfo('Bill')).toBeTruthy()
})
JavaScript 中的所有内容都是真值,除了 false
、null
、undefined
、NaN
、0
、-0
、0n
、""
和 document.all
。
toBeFalsy
- 类型:
() => Awaitable<void>
toBeFalsy
断言该值转换为布尔值时为假。如果您不关心该值,但只想了解它是否可以转换为 false
,这很有用。
例如,有了这段代码,您就不关心 stocks.stockFailed
的返回值——它可能会返回任何假值,但代码仍然可以工作。
import { Stocks } from './stocks.js'
const stocks = new Stocks()
stocks.sync('Bill')
if (!stocks.stockFailed('Bill'))
stocks.sell('apples', 'Bill')
因此,如果您想测试 stocks.stockFailed
是否为假值,您可以编写
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'
const stocks = new Stocks()
test('if Bill stock hasn\'t failed, sell apples to him', () => {
stocks.syncStocks('Bill')
expect(stocks.stockFailed('Bill')).toBeFalsy()
})
JavaScript 中的所有内容都是真值,除了 false
、null
、undefined
、NaN
、0
、-0
、0n
、""
和 document.all
。
toBeNull
- 类型:
() => Awaitable<void>
toBeNull
只是断言某物是否为 null
。.toBe(null)
的别名。
import { , } from 'vitest'
function () {
return null
}
('we don\'t have apples', () => {
(()).()
})
toBeNaN
- 类型:
() => Awaitable<void>
toBeNaN
只是断言某物是否为 NaN
。.toBe(NaN)
的别名。
import { , } from 'vitest'
let = 0
function () {
++
return > 1 ? . :
}
('getApplesCount has some unusual side effects...', () => {
(())..()
(()).()
})
toBeTypeOf
- 类型:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
断言实际值是否为接收类型的类型。
import { , } from 'vitest'
const = 'stock'
('stock is type of string', () => {
().('string')
})
toBeInstanceOf
- 类型:
(c: any) => Awaitable<void>
toBeInstanceOf
断言实际值是否为接收类的实例。
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'
const stocks = new Stocks()
test('stocks are instance of Stocks', () => {
expect(stocks).toBeInstanceOf(Stocks)
})
toBeGreaterThan
- 类型:
(n: number | bigint) => Awaitable<void>
toBeGreaterThan
断言实际值是否大于接收的值。相等的值将使测试失败。
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'
test('have more then 10 apples', () => {
expect(getApples()).toBeGreaterThan(10)
})
toBeGreaterThanOrEqual
- 类型:
(n: number | bigint) => Awaitable<void>
toBeGreaterThanOrEqual
断言实际值是否大于接收的值或等于它。
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'
test('have 11 apples or more', () => {
expect(getApples()).toBeGreaterThanOrEqual(11)
})
toBeLessThan
- 类型:
(n: number | bigint) => Awaitable<void>
toBeLessThan
断言实际值是否小于接收的值。相等的值将使测试失败。
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'
test('have less then 20 apples', () => {
expect(getApples()).toBeLessThan(20)
})
toBeLessThanOrEqual
- 类型:
(n: number | bigint) => Awaitable<void>
toBeLessThanOrEqual
断言实际值是否小于接收的值或等于它。
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'
test('have 11 apples or less', () => {
expect(getApples()).toBeLessThanOrEqual(11)
})
toEqual
- 类型:
(received: any) => Awaitable<void>
toEqual
断言实际值是否等于接收的值,或者如果它是对象,则具有相同的结构(递归地比较它们)。您可以在此示例中看到 toEqual
和 toBe
之间的区别
import { , } from 'vitest'
const = {
: 'apples',
: 13,
}
const = {
: 'apples',
: 13,
}
('stocks have the same properties', () => {
().()
})
('stocks are not the same', () => {
()..()
})
警告
对于 Error
对象,不会执行深度相等。只有 Error
的 message
属性被认为是相等的。要自定义相等以检查除 message
之外的属性,请使用 expect.addEqualityTesters
。要测试是否抛出了某物,请使用 toThrowError
断言。
toStrictEqual
- 类型:
(received: any) => Awaitable<void>
toStrictEqual
断言实际值是否等于接收的值,或者如果它是对象,则具有相同的结构(递归地比较它们),并且类型相同。
与 .toEqual
的区别
- 具有
undefined
属性的键将被检查。例如,{a: undefined, b: 2}
在使用.toStrictEqual
时与{b: 2}
不匹配。 - 将检查数组稀疏性。例如,
[, 1]
在使用.toStrictEqual
时与[undefined, 1]
不匹配。 - 将检查对象类型是否相等。例如,具有字段
a
和b
的类实例将不等于具有字段a
和b
的文字对象。
import { expect, test } from 'vitest'
class Stock {
constructor(type) {
this.type = type
}
}
test('structurally the same, but semantically different', () => {
expect(new Stock('apples')).toEqual({ type: 'apples' })
expect(new Stock('apples')).not.toStrictEqual({ type: 'apples' })
})
toContain
- 类型:
(received: string) => Awaitable<void>
toContain
断言实际值是否在数组中。toContain
还可以检查字符串是否是另一个字符串的子字符串。从 Vitest 1.0 开始,如果您在类似浏览器的环境中运行测试,此断言还可以检查类是否包含在 classList
中,或者元素是否在另一个元素内。
import { expect, test } from 'vitest'
import { getAllFruits } from './stocks.js'
test('the fruit list contains orange', () => {
expect(getAllFruits()).toContain('orange')
const element = document.querySelector('#el')
// element has a class
expect(element.classList).toContain('flex')
// element is inside another one
expect(document.querySelector('#wrapper')).toContain(element)
})
toContainEqual
- 类型:
(received: any) => Awaitable<void>
toContainEqual
断言具有特定结构和值的项目是否包含在数组中。它在每个元素内部的工作方式类似于 toEqual
。
import { expect, test } from 'vitest'
import { getFruitStock } from './stocks.js'
test('apple available', () => {
expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 })
})
toHaveLength
- 类型:
(received: number) => Awaitable<void>
toHaveLength
断言对象是否具有 .length
属性,并且它是否设置为某个数值。
import { , } from 'vitest'
('toHaveLength', () => {
('abc').(3)
([1, 2, 3]).(3)
('')..(3) // doesn't have .length of 3
({ : 3 }).(3)
})
toHaveProperty
- 类型:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
断言对象在提供的引用 key
处是否存在属性。
您还可以提供一个可选的值参数,也称为深度相等,就像 toEqual
匹配器一样,用于比较接收到的属性值。
import { , } from 'vitest'
const = {
'isActive': true,
'P.O': '12345',
'customer': {
: 'John',
: 'Doe',
: 'China',
},
'total_amount': 5000,
'items': [
{
: 'apples',
: 10,
},
{
: 'oranges',
: 5,
},
],
}
('John Doe Invoice', () => {
().('isActive') // assert that the key exists
().('total_amount', 5000) // assert that the key exists and the value is equal
()..('account') // assert that this key does not exist
// Deep referencing using dot notation
().('customer.first_name')
().('customer.last_name', 'Doe')
()..('customer.location', 'India')
// Deep referencing using an array containing the key
().('items[0].type', 'apples')
().('items.0.type', 'apples') // dot notation also works
// Deep referencing using an array containing the keyPath
().(['items', 0, 'type'], 'apples')
().(['items', '0', 'type'], 'apples') // string notation also works
// Wrap your key in an array to avoid the key from being parsed as a deep reference
().(['P.O'], '12345')
})
toMatch
- 类型:
(received: string | regexp) => Awaitable<void>
toMatch
断言字符串是否与正则表达式或字符串匹配。
import { , } from 'vitest'
('top fruits', () => {
('top fruits include apple, orange and grape').(/apple/)
('applefruits').('fruit') // toMatch also accepts a string
})
toMatchObject
- 类型:
(received: object | array) => Awaitable<void>
toMatchObject
断言对象是否与对象的属性子集匹配。
您也可以传递一个对象数组。如果您想检查两个数组在元素数量上是否匹配,这很有用,而不是 arrayContaining
,它允许接收数组中存在额外的元素。
import { , } from 'vitest'
const = {
: true,
: {
: 'John',
: 'Doe',
: 'China',
},
: 5000,
: [
{
: 'apples',
: 10,
},
{
: 'oranges',
: 5,
},
],
}
const = {
: {
: 'John',
: 'Doe',
: 'China',
},
}
('invoice has john personal details', () => {
().()
})
('the number of elements must match exactly', () => {
// Assert that an array of object matches
([{ : 'bar' }, { : 1 }]).([
{ : 'bar' },
{ : 1 },
])
})
toThrowError
类型:
(received: any) => Awaitable<void>
别名:
toThrow
toThrowError
断言函数在被调用时是否抛出错误。
您可以提供一个可选参数来测试是否抛出了特定错误
- 正则表达式:错误消息与模式匹配
- 字符串:错误消息包含子字符串
提示
您必须将代码包装在函数中,否则错误将不会被捕获,测试将失败。
例如,如果我们想测试 getFruitStock('pineapples')
是否抛出,我们可以编写
import { , } from 'vitest'
function (: string) {
if ( === 'pineapples')
throw new ('Pineapples are not in stock')
// Do some other stuff
}
('throws on pineapples', () => {
// Test that the error message says "stock" somewhere: these are equivalent
(() => ('pineapples')).(/stock/)
(() => ('pineapples')).('stock')
// Test the exact error message
(() => ('pineapples')).(
/^Pineapples are not in stock$/,
)
})
提示
要测试异步函数,请与 rejects 结合使用。
function () {
return .(new ('empty'))
}
test('throws on pineapples', async () => {
await expect(() => ()).rejects.toThrowError('empty')
})
toMatchSnapshot
- 类型:
<T>(shape?: Partial<T> | string, message?: string) => void
这确保了一个值与最新的快照匹配。
您可以提供一个可选的 hint
字符串参数,该参数将附加到测试名称。虽然 Vitest 始终在快照名称末尾附加一个数字,但简短的描述性提示可能比数字更有用,可以区分单个 it 或测试块中的多个快照。Vitest 在相应的 .snap
文件中按名称对快照进行排序。
提示
当快照不匹配并导致测试失败时,如果预期不匹配,您可以按 u
键更新一次快照。或者,您可以传递 -u
或 --update
CLI 选项,使 Vitest 始终更新测试。
import { , } from 'vitest'
('matches snapshot', () => {
const = { : new (['bar', 'snapshot']) }
().()
})
您也可以提供一个对象的形状,如果您只是测试一个对象的形状,并且不需要它与 100% 兼容。
import { , } from 'vitest'
('matches snapshot', () => {
const = { : new (['bar', 'snapshot']) }
().({ : .() })
})
toMatchInlineSnapshot
- 类型:
<T>(shape?: Partial<T> | string, snapshot?: string, message?: string) => void
这确保了一个值与最新的快照匹配。
Vitest 将 inlineSnapshot 字符串参数添加到测试文件中的匹配器中(而不是外部 .snap
文件)。
import { , } from 'vitest'
('matches inline snapshot', () => {
const = { : new (['bar', 'snapshot']) }
// Vitest will update following content when updating the snapshot
().(`
{
"foo": Set {
"bar",
"snapshot",
},
}
`)
})
您也可以提供一个对象的形状,如果您只是测试一个对象的形状,并且不需要它与 100% 兼容。
import { , } from 'vitest'
('matches snapshot', () => {
const = { : new (['bar', 'snapshot']) }
().(
{ : .() },
`
{
"foo": Any<Set>,
}
`
)
})
toMatchFileSnapshot 0.30.0+
- 类型:
<T>(filepath: string, message?: string) => Promise<void>
将快照与显式指定的文件(而不是 .snap
文件)的内容进行比较或更新。
import { expect, it } from 'vitest'
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }))
await expect(result).toMatchFileSnapshot('./test/basic.output.html')
})
请注意,由于文件系统操作是异步的,因此您需要使用 await
与 toMatchFileSnapshot()
一起使用。
toThrowErrorMatchingSnapshot
- 类型:
(message?: string) => void
与 toMatchSnapshot
相同,但期望与 toThrowError
相同的值。
toThrowErrorMatchingInlineSnapshot
- 类型:
(snapshot?: string, message?: string) => void
与 toMatchInlineSnapshot
相同,但期望与 toThrowError
相同的值。
toHaveBeenCalled
- 类型:
() => Awaitable<void>
此断言对于测试函数是否已被调用很有用。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
const = {
(: string, : number) {
// ...
},
}
('spy function', () => {
const = .(, 'buy')
()..()
.('apples', 10)
().()
})
toHaveBeenCalledTimes
- 类型:
(amount: number) => Awaitable<void>
此断言检查函数是否被调用了一定次数。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
const = {
(: string, : number) {
// ...
},
}
('spy function called two times', () => {
const = .(, 'buy')
.('apples', 10)
.('apples', 20)
().(2)
})
toHaveBeenCalledWith
- 类型:
(...args: any[]) => Awaitable<void>
此断言检查函数是否至少被调用了一次,并且使用某些参数。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
const = {
(: string, : number) {
// ...
},
}
('spy function', () => {
const = .(, 'buy')
.('apples', 10)
.('apples', 20)
().('apples', 10)
().('apples', 20)
})
toHaveBeenLastCalledWith
- 类型:
(...args: any[]) => Awaitable<void>
此断言检查函数是否在其最后一次调用中使用某些参数被调用。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
const = {
(: string, : number) {
// ...
},
}
('spy function', () => {
const = .(, 'buy')
.('apples', 10)
.('apples', 20)
()..('apples', 10)
().('apples', 20)
})
toHaveBeenNthCalledWith
- 类型:
(time: number, ...args: any[]) => Awaitable<void>
此断言检查函数是否在特定时间使用某些参数被调用。计数从 1 开始。因此,要检查第二个条目,您将编写 .toHaveBeenNthCalledWith(2, ...)
。
需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
const = {
(: string, : number) {
// ...
},
}
('first call of spy function called with right params', () => {
const = .(, 'buy')
.('apples', 10)
.('apples', 20)
().(1, 'apples', 10)
})
toHaveReturned
- 类型:
() => Awaitable<void>
此断言检查函数是否至少成功返回了一次值(即没有抛出错误)。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
function (: number) {
const = 10
return *
}
('spy function returned a value', () => {
const = .()
const = (10)
().(100)
().()
})
toHaveReturnedTimes
- 类型:
(amount: number) => Awaitable<void>
此断言检查函数是否成功返回了一定次数的值(即没有抛出错误)。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
('spy function returns a value two times', () => {
const = .((: string) => ({ }))
('apples')
('bananas')
().(2)
})
toHaveReturnedWith
- 类型:
(returnValue: any) => Awaitable<void>
您可以调用此断言来检查函数是否至少成功返回了一次具有某些参数的值。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
('spy function returns a product', () => {
const = .((: string) => ({ }))
('apples')
().({ : 'apples' })
})
toHaveLastReturnedWith
- 类型:
(returnValue: any) => Awaitable<void>
您可以调用此断言来检查函数是否在其最后一次调用中成功返回了具有某些参数的值。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
('spy function returns bananas on a last call', () => {
const = .((: string) => ({ }))
('apples')
('bananas')
().({ : 'bananas' })
})
toHaveNthReturnedWith
- 类型:
(time: number, returnValue: any) => Awaitable<void>
您可以调用此断言来检查函数是否在特定调用中成功返回了具有某些参数的值。需要将间谍函数传递给 expect
。
import { , , } from 'vitest'
('spy function returns bananas on second call', () => {
const = .((: string) => ({ }))
('apples')
('bananas')
().(2, { : 'bananas' })
})
toSatisfy
- 类型:
(predicate: (value: any) => boolean) => Awaitable<void>
此断言检查一个值是否满足某个谓词。
import { , , } from 'vitest'
('toSatisfy()', () => {
const = (: number) => % 2 !== 0
('pass with 0', () => {
(1).()
})
('pass with negation', () => {
(2)..()
})
})
resolves
- 类型:
Promisify<Assertions>
resolves
旨在在断言异步代码时消除样板代码。使用它从挂起的 promise 中解包值,并使用通常的断言断言其值。如果 promise 被拒绝,则断言将失败。
它返回相同的 Assertions
对象,但所有匹配器现在都返回 Promise
,因此您需要 await
它。也适用于 chai
断言。
例如,如果您有一个函数,它进行 API 调用并返回一些数据,您可以使用此代码来断言其返回值
import { expect, test } from 'vitest'
async function buyApples() {
return fetch('/buy/apples').then(r => r.json())
}
test('buyApples returns new stock id', async () => {
// toEqual returns a promise now, so you HAVE to await it
await expect(buyApples()).resolves.toEqual({ id: 1 }) // jest API
await expect(buyApples()).resolves.to.equal({ id: 1 }) // chai API
})
警告
如果断言没有被等待,那么您将有一个每次都会通过的假阳性测试。为了确保断言实际上被调用,您可以使用 expect.assertions(number)
。
rejects
- 类型:
Promisify<Assertions>
rejects
旨在在断言异步代码时消除样板代码。使用它来解包 promise 被拒绝的原因,并使用通常的断言断言其值。如果 promise 成功解析,则断言将失败。
它返回相同的 Assertions
对象,但所有匹配器现在都返回 Promise
,因此您需要 await
它。也适用于 chai
断言。
例如,如果您有一个函数,当您调用它时会失败,您可以使用此代码来断言原因
import { expect, test } from 'vitest'
async function buyApples(id) {
if (!id)
throw new Error('no id')
}
test('buyApples throws an error when no id provided', async () => {
// toThrow returns a promise now, so you HAVE to await it
await expect(buyApples()).rejects.toThrow('no id')
})
警告
如果断言没有被等待,那么您将有一个每次都会通过的假阳性测试。为了确保断言实际上被调用,您可以使用 expect.assertions(number)
。
expect.assertions
- 类型:
(count: number) => void
在测试通过或失败后,验证在测试期间调用了一定数量的断言。一个有用的情况是检查异步代码是否被调用。
例如,如果我们有一个异步调用两个匹配器的函数,我们可以断言它们实际上被调用了。
import { expect, test } from 'vitest'
async function doAsync(...cbs) {
await Promise.all(
cbs.map((cb, index) => cb({ index })),
)
}
test('all assertions are called', async () => {
expect.assertions(2)
function callback1(data) {
expect(data).toBeTruthy()
}
function callback2(data) {
expect(data).toBeTruthy()
}
await doAsync(callback1, callback2)
})
警告
在使用 assertions
进行异步并发测试时,必须使用本地 测试上下文 中的 expect
来确保检测到正确的测试。
expect.hasAssertions
- 类型:
() => void
在测试通过或失败后,验证在测试期间至少调用了一个断言。一个有用的情况是检查异步代码是否被调用。
例如,如果您有一段代码调用回调,我们可以在回调中进行断言,但如果我们不检查断言是否被调用,测试将始终通过。
import { expect, test } from 'vitest'
import { db } from './db.js'
const cbs = []
function onSelect(cb) {
cbs.push(cb)
}
// after selecting from db, we call all callbacks
function select(id) {
return db.select({ id }).then((data) => {
return Promise.all(
cbs.map(cb => cb(data)),
)
})
}
test('callback was called', async () => {
expect.hasAssertions()
onSelect((data) => {
// should be called on select
expect(data).toBeTruthy()
})
// if not awaited, test will fail
// if you don't have expect.hasAssertions(), test will pass
await select(3)
})
expect.unreachable
- 类型:
(message?: string) => never
此方法用于断言永远不应该到达一行。
例如,如果我们想测试 build()
由于接收到的目录没有 src
文件夹而抛出异常,并且还分别处理每个错误,我们可以这样做
import { expect, test } from 'vitest'
async function build(dir) {
if (dir.includes('no-src'))
throw new Error(`${dir}/src does not exist`)
}
const errorDirs = [
'no-src-folder',
// ...
]
test.each(errorDirs)('build fails with "%s"', async (dir) => {
try {
await build(dir)
expect.unreachable('Should not pass build')
}
catch (err: any) {
expect(err).toBeInstanceOf(Error)
expect(err.stack).toContain('build')
switch (dir) {
case 'no-src-folder':
expect(err.message).toBe(`${dir}/src does not exist`)
break
default:
// to exhaust all error tests
expect.unreachable('All error test must be handled')
break
}
}
})
expect.anything
- 类型:
() => any
此非对称匹配器,当与相等性检查一起使用时,将始终返回 true
。有用,如果您只是想确保属性存在。
import { expect, test } from 'vitest'
test('object has "apples" key', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() })
})
expect.any
- 类型:
(constructor: unknown) => any
此非对称匹配器,当与相等性检查一起使用时,只有当值为指定构造函数的实例时才返回 true
。有用,如果您有一个每次都会生成的 value,并且您只想了解它是否存在于适当的类型中。
import { expect, test } from 'vitest'
import { generateId } from './generators.js'
test('"id" is a number', () => {
expect({ id: generateId() }).toEqual({ id: expect.any(Number) })
})
expect.closeTo 1.0.0+
- 类型:
(expected: any, precision?: number) => any
expect.closeTo
在比较对象属性或数组项中的浮点数时很有用。如果您需要比较一个数字,请改用 .toBeCloseTo
。
可选的 numDigits
参数限制了小数点后要检查的位数。对于默认值 2
,测试标准是 Math.abs(expected - received) < 0.005 (即 10 ** -2 / 2)
。
例如,此测试以 5 位精度通过
test('compare float in object properties', () => {
expect({
title: '0.1 + 0.2',
sum: 0.1 + 0.2,
}).toEqual({
title: '0.1 + 0.2',
sum: expect.closeTo(0.3, 5),
})
})
expect.arrayContaining
- 类型:
<T>(expected: T[]) => any
当与相等性检查一起使用时,此非对称匹配器将返回 true
,如果该值是一个数组并且包含指定的项目。
import { , } from 'vitest'
('basket includes fuji', () => {
const = {
: [
'Empire',
'Fuji',
'Gala',
],
: 3
}
().({
: 3,
: .(['Fuji'])
})
})
提示
您可以使用 expect.not
与此匹配器一起使用来否定预期值。
expect.objectContaining
- 类型:
(expected: any) => any
当与相等性检查一起使用时,此非对称匹配器将返回 true
,如果该值具有类似的形状。
import { , } from 'vitest'
('basket has empire apples', () => {
const = {
: [
{
: 'Empire',
: 1,
}
],
}
().({
: [
.({ : 'Empire' }),
]
})
})
提示
您可以使用 expect.not
与此匹配器一起使用来否定预期值。
expect.stringContaining
- 类型:
(expected: any) => any
当与相等性检查一起使用时,此非对称匹配器将返回 true
,如果该值是一个字符串并且包含指定的子字符串。
import { , } from 'vitest'
('variety has "Emp" in its name', () => {
const = {
: 'Empire',
: 1,
}
().({
: .('Emp'),
: 1,
})
})
提示
您可以使用 expect.not
与此匹配器一起使用来否定预期值。
expect.stringMatching
- 类型:
(expected: any) => any
当与相等性检查一起使用时,此非对称匹配器将返回 true
,如果该值是一个字符串并且包含指定的子字符串,或者如果该字符串与正则表达式匹配。
import { , } from 'vitest'
('variety ends with "re"', () => {
const = {
: 'Empire',
: 1,
}
().({
: .(/re$/),
: 1,
})
})
提示
您可以使用 expect.not
与此匹配器一起使用来否定预期值。
expect.addSnapshotSerializer
- 类型:
(plugin: PrettyFormatPlugin) => void
此方法添加自定义序列化器,这些序列化器在创建快照时被调用。这是一个高级功能 - 如果你想了解更多,请阅读 关于自定义序列化器的指南。
如果你正在添加自定义序列化器,你应该在 setupFiles
中调用此方法。这将影响每个快照。
提示
如果你之前使用过 Vue CLI with Jest,你可能想安装 jest-serializer-vue。否则,你的快照将被包装在一个字符串中,这会导致 "
被转义。
expect.extend
- 类型:
(matchers: MatchersObject) => void
你可以用你自己的匹配器扩展默认匹配器。此函数用于用自定义匹配器扩展匹配器对象。
当你以这种方式定义匹配器时,你也会创建非对称匹配器,这些匹配器可以像 expect.stringContaining
一样使用。
import { expect, test } from 'vitest'
test('custom matchers', () => {
expect.extend({
toBeFoo: (received, expected) => {
if (received !== 'foo') {
return {
message: () => `expected ${received} to be foo`,
pass: false,
}
}
},
})
expect('foo').toBeFoo()
expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() })
})
提示
如果你想让你的匹配器出现在每个测试中,你应该在 setupFiles
中调用此方法。
此函数与 Jest 的 expect.extend
兼容,因此任何使用它来创建自定义匹配器的库都可以在 Vitest 中使用。
如果你正在使用 TypeScript,从 Vitest 0.31.0 开始,你可以在环境声明文件(例如:vitest.d.ts
)中使用以下代码扩展默认的 Assertion
接口
interface CustomMatchers<R = unknown> {
toBeFoo: () => R
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
警告
不要忘记在你的 tsconfig.json
中包含环境声明文件。
提示
如果你想了解更多,请查看 关于扩展匹配器的指南。
expect.addEqualityTesters 1.2.0+
- 类型:
(tester: Array<Tester>) => void
你可以使用此方法来定义自定义测试器,这些测试器是匹配器使用的方法,用于测试两个对象是否相等。它与 Jest 的 expect.addEqualityTesters
兼容。
import { , } from 'vitest'
class {
public : string
constructor(: string) {
this. =
}
(: ): boolean {
const = this..(/ /g, '').()
const = ..(/ /g, '').()
const = .('').().('')
const = .('').().('')
return ===
}
}
function (: unknown): is {
return instanceof
}
function (: unknown, : unknown): boolean | undefined {
const = ()
const = ()
if ( && )
return .()
else if ( === )
return
else
return false
}
.([])
('custom equality tester', () => {
(new ('listen')).(new ('silent'))
})