API 参考

下面的变量中使用了以下类型

  1. type DoneCallback = (error?: any) => void
  2. type Awaitable<T> = T | PromiseLike<T>
  3. type TestFunction = () => Awaitable<void> | (done: DoneCallback) => void

当一个测试函数返回一个 promise 时,Vitest 将等待直到它被解决以收集异步的期望值。 如果 promise 被拒绝,测试将失败。

为了兼容 Jest 的用法, TestFunction 也可以是 (done: DoneCallback) => void 类型。 如果使用这种形式, 则 done 在调用之前不会结束测试(无参数或参数为假值表示测试通过,而真值或错误值作为参数则测试不通过)。 我们不建议使用这种形式,因为你可以使用 async 函数实现相同的目的。

test

  • 类型: (name: string, fn: TestFunction, timeout?: number) => void
  • 别名: it

    test 定义了一组关于测试期望的方法。它接收测试名称和一个含有测试期望的函数。

    同时,你也可以提供一个超时时限(以毫秒为单位)用于指定等待多长时间后终止测试,默认为 5 秒。也可以通过 testTimeout 选项进行全局配置。

    1. import { test, expect } from 'vitest'
    2. test('should work as expected', () => {
    3. expect(Math.sqrt(4)).toBe(2);
    4. })

test.skip

  • 类型: (name: string, fn: TestFunction, timeout?: number) => void
  • 别名: it.skip

    如果你想跳过运行某些测试,但由于一些原因不想删除代码,你可以使用 test.skip 来避免运行它们。

    1. import { test, assert } from 'vitest'
    2. test.skip("skipped test", () => {
    3. // 跳过测试,没有错误
    4. assert.equal(Math.sqrt(4), 3);
    5. });

test.only

  • 类型: (name: string, fn: TestFunction, timeout?: number) => void
  • 别名: it.only

    使用 test.only 可以仅在给定测试套件中运行某些测试。这在调试时会非常有用。

    同时,你也可以提供一个超时时限(以毫秒为单位)用于指定等待多长时间后终止测试,默认为 5 秒。也可以通过 testTimeout 选项进行全局配置。

    1. import { test, assert } from 'vitest'
    2. test.only("test", () => {
    3. // 仅运行此测试(以及仅标记有的其他测试)
    4. assert.equal(Math.sqrt(4), 2);
    5. });

test.concurrent

  • 类型: (name: string, fn: TestFunction, timeout?: number) => void
  • 别名: it.concurrent

    test.concurrent 会将连续的多个测试并发运行。它将接收测试名称、带有要收集测试的异步函数以及可选的超时参数(以毫秒为单位)。

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

    test.skiptest.onlytest.todo 都适用于并发测试。以下所有组合均有效:

    1. test.concurrent(...)
    2. test.skip.concurrent(...), test.concurrent.skip(...)
    3. test.only.concurrent(...), test.concurrent.only(...)
    4. test.todo.concurrent(...), test.concurrent.todo(...)

test.todo

  • 类型: (name: string) => void
  • 别名: it.todo

    使用 test.todo 将稍后实现的测试进行存档。测试报告中将显示一个记录,以便你知道还多少条未实现的测试。

    1. // 测试的报告中将显示一个记录
    2. test.todo("unimplemented test");

test.fails

  • 类型: (name: string, fn: TestFunction, timeout?: number) => void
  • 别名: it.fails

    使用 test.fails 表示断言将显式失败。

    1. import { expect, test } from 'vitest'
    2. const myAsyncFunc = () => new Promise((resolve) => resolve(1))
    3. test.fails("fail test", () => {
    4. expect(myAsyncFunc()).rejects.toBe(1)
    5. })

test.each

  • 类型: (cases: ReadonlyArray<T>) => void
  • 别名: it.each

    当你需要使用不同的变量运行相同的测试时,可以使用 test.each

    你可以按照测试参数的顺序,在测试名称插入符合printf格式的参数。

    • %s:字符串
    • %d:数值
    • %i:整数
    • %f:小数
    • %j:json格式
    • %o:对象
    • %#:对应的测试参数下标
    • %%:单个百分比符号 (‘%’)
    1. test.each([
    2. [1, 1, 2],
    3. [1, 2, 3],
    4. [2, 1, 3],
    5. ])('add(%i, %i) -> %i', (a, b, expected) => {
    6. expect(a + b).toBe(expected)
    7. })
    8. // this will return
    9. // √ add(1, 1) -> 2
    10. // √ add(1, 2) -> 3
    11. // √ add(2, 1) -> 3

describe

当你在文件的顶层使用 test 时,它们将作为隐式测试套件的一部分被收集。你可以使用 describe 在当前上下文中定义一个新的测试套件,将其看作一组相关测试或者有别于其它的嵌套测试套件。测试套件可让你组织你的测试用例,使报告更清晰。

  1. import { describe, expect, test } from 'vitest'
  2. const person = {
  3. isActive: true,
  4. age: 32,
  5. };
  6. describe('person', () => {
  7. test('person is defined', () => {
  8. expect(person).toBeDefined()
  9. });
  10. test('is active', () => {
  11. expect(person.isActive).toBeTruthy();
  12. });
  13. test('age limit', () => {
  14. expect(person.age).toBeLessThanOrEqual(32);
  15. });
  16. });

如果你需要有测试层次结构,你还可以嵌套描述块:

  1. import { describe, test, expect } from 'vitest'
  2. const numberToCurrency = (value) => {
  3. if (typeof value !== 'number') {
  4. throw new Error(`Value must be a number`);
  5. }
  6. return value.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  7. }
  8. describe('numberToCurrency', () => {
  9. describe('given an invalid number', () => {
  10. test('composed of non-numbers to throw error', () => {
  11. expect(() => numberToCurrency('abc')).toThrow();
  12. });
  13. });
  14. describe('given a valid number', () => {
  15. test('returns the correct currency format', () => {
  16. expect(numberToCurrency(10000)).toBe('10,000.00');
  17. });
  18. });
  19. });

describe.skip

  • 类型: (name: string, fn: TestFunction) => void

    在测试套件中使用 describe.skip 避免运行特定的描述块。

    1. import { assert, describe, test } from 'vitest'
    2. describe.skip("skipped suite", () => {
    3. test("sqrt", () => {
    4. // 跳过测试套件,不会有错误
    5. assert.equal(Math.sqrt(4), 3);
    6. });
    7. });

describe.only

  • 类型: (name: string, fn: TestFunction) => void

    使用 describe.only 仅运行指定的测试套件。

    1. // 仅运行此测试套件(以及仅标有的其他测试套件)
    2. describe.only("suite", () => {
    3. test("sqrt", () => {
    4. assert.equal(Math.sqrt(4), 3);
    5. });
    6. });
    7. describe('other suite', () => {
    8. // ... 这里的测试套件将会被跳过
    9. });

describe.concurrent

  • 类型: (name: string, fn: TestFunction, timeout?: number) => void

    使用 describe.concurrent 在测试套件中将每个测试标记为并发。

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

    .skip.only.todo 可以与并发测试套件一起使用。 以下所有组合均有效:

    1. describe.concurrent(...)
    2. describe.skip.concurrent(...), describe.concurrent.skip(...)
    3. describe.only.concurrent(...), describe.concurrent.only(...)
    4. describe.todo.concurrent(...), describe.concurrent.todo(...)

describe.todo

  • 类型: (name: string) => void

    使用 describe.todo 将稍后实现的测试套件进行存档。测试报告中将显示一个记录,以便你知道还多少条未实现的测试。

    1. // 测试套件的报告中将显示一个记录
    2. describe.todo("unimplemented suite");

describe.each

  • 类型: (cases: ReadonlyArray<T>): (name: string, fn: (...args: T[]) => void) => void

    如果你有多个测试依赖相同的数据,可以使用 describe.each

    1. describe.each([
    2. { a: 1, b: 1, expected: 2 },
    3. { a: 1, b: 2, expected: 3 },
    4. { a: 2, b: 1, expected: 3 },
    5. ])('describe object add(%i, %i)', ({ a, b, expected }) => {
    6. test(`returns ${expected}`, () => {
    7. expect(a + b).toBe(expected)
    8. })
    9. test(`returned value not be greater than ${expected}`, () => {
    10. expect(a + b).not.toBeGreaterThan(expected)
    11. })
    12. test(`returned value not be less than ${expected}`, () => {
    13. expect(a + b).not.toBeLessThan(expected)
    14. })
    15. })

expect

  • 类型: ExpectStatic & (actual: any) => Assertions

    expect 用来创建断言。在当前上下文中,可以使用 assertions 方法来断言一个语句。 Vitest 默认提供 chai 进行断言,同时基于 chai 实现兼容 Jest 的断言语句。

    例如,这里会断言 input 的值是否等于 2 ,如果它们不相等,断言则会抛出错误,并且测试失败。

    1. import { expect } from 'vitest'
    2. const input = Math.sqrt(4)
    3. expect(input).to.equal(2) // chai API
    4. expect(input).toBe(2) // jest API

    从技术上来说,这里并没有使用 test 方法,所以我们在控制台会看到 Nodejs 的报错,而不是 Vitest 的报错。想要了解更多关于 test 的信息,请参阅 test 章节

    此外,expect 可用于静态访问匹配器功能,这个后面会介绍。

not

使用 not 将会否定断言。举例,此代码断言 input 的值不等于 2。如果它们相等,断言则会抛出错误,并且测试失败。

  1. import { expect, test } from 'vitest'
  2. const input = Math.sqrt(16)
  3. expect(input).not.to.equal(2) // chai API
  4. expect(input).not.toBe(2) // jest API

toBe

  • 类型: (value: any) => Awaitable<void>

    toBe 可用于断言基础对象是否相等,或者对象是否共享相同的引用。它相当于调用了 expect(Object.is(3, 3)).toBe(true)。 如果对象不相同,但你想检查它们的结构是否相同,则可以使用 toEqual

    例如,下面的测试将会检查 stock 是否有13个苹果。

    1. import { test, expect } from 'vitest'
    2. const stock = {
    3. type: 'apples',
    4. count: 13
    5. }
    6. test('stock has 13 apples', () => {
    7. expect(stock.type).toBe('apples')
    8. expect(stock.count).toBe(13)
    9. })
    10. test('stocks are the same', () => {
    11. const refStock = stock // 相同的引用
    12. expect(stock).toBe(refStock)
    13. })

    尽量不要将 toBe 与浮点数一起使用。由于 JavaScript 会对它们进行四舍五入,例如 0.1 + 0.2 的结果严格来说并不是 0.3 。如果需要可靠地断言浮点数,请使用 toBeCloseTo 进行断言。

toBeCloseTo

  • 类型: (value: number, numDigits?: number) => Awaitable<void>

    使用 toBeCloseTo 进行浮点数的比较。可以选择使用 numDigits 参数限制小数点后的检查位数。例如:

    1. import { test, expect } from 'vitest'
    2. test.fails('decimals are not equal in javascript', () => {
    3. expect(0.2 + 0.1).toBe(0.3); // 0.2 + 0.1 = 0.30000000000000004
    4. });
    5. test('decimals are rounded to 5 after the point', () => {
    6. // 0.2 + 0.1 = 0.30000 | 移除了 "000000000004"
    7. expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
    8. // 0.30000000000000004 中的任何内容都不会被删除
    9. expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50);
    10. });

toBeDefined

  • 类型: () => Awaitable<void>

    toBeDefined 断言检查值是否不等于 undefined 。在检查函数是否有返回值时非常有用。

    1. import { test, expect } from 'vitest'
    2. const getApples = () => 3
    3. test('function returned something', () => {
    4. expect(getApples()).toBeDefined()
    5. })

toBeUndefined

  • 类型: () => Awaitable<void>

    toBeDefined 相反,toBeUndefined 断言检查值是否等于 undefined 。在检查函数是否没有返回任何内容时非常有用。

    1. import { test, expect } from 'vitest'
    2. function getApplesFromStock(stock) {
    3. if(stock === 'Bill') return 13
    4. }
    5. test('mary doesn\'t have a stock', () => {
    6. expect(getApplesFromStock('Mary')).toBeUndefined()
    7. })

toBeTruthy

  • 类型: () => Awaitable<void>

    toBeTruthy 会将检查值转换为布尔值,断言该值是否为 true 。该方法在当你不关心检查值的内容,而只想知道它是否可以转换为 true 时很有用。

    例如下面这段代码,我们就不需要关心 stocks.getInfo 的返回值,可能是复杂的对象、字符串或者是其他内容,代码仍然可以运行。

    1. import { Stocks } from './stocks'
    2. const stocks = new Stocks()
    3. stocks.sync('Bill')
    4. if(stocks.getInfo('Bill')) {
    5. stocks.sell('apples', 'Bill')
    6. }

    所以如果我们想测试 stocks.getInfo 是否为 true,我们可以这样写:

    1. import { test, expect } from 'vitest'
    2. import { Stocks } from './stocks'
    3. const stocks = new Stocks()
    4. test('if we know Bill stock, sell apples to him', () => {
    5. stocks.sync('Bill')
    6. expect(stocks.getInfo('Bill')).toBeTruthy()
    7. })

    JavaScript 中除了 false0''nullundefinedNaN,其他一切都是为真。

toBeFalsy

  • 类型: () => Awaitable<void>

    toBeFalsy 会将检测值转换为布尔值,断言该值是否为 false。该方法在当你不关心该检查值的内容,但只想知道它是否可以转换为 false 时很有用。

    例如下面这段代码,我们就不需要关心 stocks.stockFailed 的返回值,可能是复杂的对象、字符串或者是其他内容,代码仍然可以运行。

    1. import { Stocks } from './stocks'
    2. const stocks = new Stocks()
    3. stocks.sync('Bill')
    4. if(!stocks.stockFailed('Bill')) {
    5. stocks.sell('apples', 'Bill')
    6. }

    所以如果我们想测试 stocks.stockFailed 是否为 false,我们可以这样写:

    1. import { test, expect } from 'vitest'
    2. import { Stocks } from './stocks'
    3. const stocks = new Stocks()
    4. test('if Bill stock hasnt failed, sell apples to him', () => {
    5. stocks.syncStocks('Bill')
    6. expect(stocks.stockFailed('Bill')).toBeFalsy()
    7. })

    JavaScript 中除了 false0''nullundefinedNaN,其他一切都是为真。

toBeNull

  • 类型: () => Awaitable<void>

    toBeNull 将简单地断言检查值是否为 null。 是 .toBe(null) 的别名。

    1. import { test, expect } from 'vitest'
    2. function apples() {
    3. return null
    4. }
    5. test('we dont have apples', () => {
    6. expect(apples()).toBeNull()
    7. })

toBeNaN

  • 类型: () => Awaitable<void>

    toBeNaN 将简单地断言是否为 NaN。 是 .toBe(NaN) 的别名,

    1. import { test, expect } from 'vitest'
    2. let i = 0
    3. function getApplesCount() {
    4. i++
    5. return i > 1 ? NaN : i
    6. }
    7. test('getApplesCount has some unusual side effects...', () => {
    8. expect(getApplesCount()).not.toBeNaN()
    9. expect(getApplesCount()).toBeNaN()
    10. })

toBeTypeOf

  • 类型: (c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>

    toBeTypeOf 用于断言检查值是否属于接收的类型。

    1. import { test, expect } from 'vitest'
    2. const actual = 'stock'
    3. test('stock is type of string', () => {
    4. expect(actual).toBeTypeOf('string')
    5. })

toBeInstanceOf

  • 类型: (c: any) => Awaitable<void>

    toBeInstanceOf 用于断言检查值是否为接收的类的实例。

    1. import { test, expect } from 'vitest'
    2. import { Stocks } from './stocks'
    3. const stocks = new Stocks()
    4. test('stocks are instance of Stocks', () => {
    5. expect(stocks).toBeInstanceOf(Stocks)
    6. })

toBeGreaterThan

  • 类型: (n: number) => Awaitable<void>

    toBeGreaterThan 用于断言检查值是否大于接收值,如果相等将无法通过测试。

    1. import { test, expect } from 'vitest'
    2. import { getApples } from './stock'
    3. test('have more then 10 apples', () => {
    4. expect(getApples()).toBeGreaterThan(10)
    5. })

toBeGreaterThanOrEqual

  • 类型: (n: number) => Awaitable<void>

    toBeGreaterThanOrEqual 用于断言检查值是否大于等于接收值。

    1. import { test, expect } from 'vitest'
    2. import { getApples } from './stock'
    3. test('have 11 apples or more', () => {
    4. expect(getApples()).toBeGreaterThanOrEqual(11)
    5. })

toBeLessThan

  • 类型: (n: number) => Awaitable<void>

    toBeLessThan 用于断言检查值是否小于接收值,如果相等将无法通过测试。

    1. import { test, expect } from 'vitest'
    2. import { getApples } from './stock'
    3. test('have less then 20 apples', () => {
    4. expect(getApples()).toBeLessThan(20)
    5. })

toBeLessThanOrEqual

  • 类型: (n: number) => Awaitable<void>

    toBeLessThanOrEqual 用于断言检查值是否小于等于接收值。

    1. import { test, expect } from 'vitest'
    2. import { getApples } from './stock'
    3. test('have 11 apples or less', () => {
    4. expect(getApples()).toBeLessThanOrEqual(11)
    5. })

toEqual

  • 类型: (received: any) => Awaitable<void>

    toEqual 断言检查值是否等于接收值,或者是同样的结构,如果是对象类型(将会使用递归的方法进行比较)。

    在本例中,你可以看到 toEqualtoBe 之间的区别:

    1. import { test, expect } from 'vitest'
    2. const stockBill = {
    3. type: 'apples',
    4. count: 13
    5. }
    6. const stockMary = {
    7. type: 'apples',
    8. count: 13
    9. }
    10. test('stocks have the same properties', () => {
    11. expect(stockBill).toEqual(stockMary)
    12. })
    13. test('stocks are not the same', () => {
    14. expect(stockBill).not.toBe(stockMary)
    15. })

    :::warning 警告 该方法不会对 Error 对象执行深度相同比较。如果要测试是否抛出了某个内容,建议使用 toThrow 断言。 :::

toStrictEqual

  • 类型: (received: any) => Awaitable<void>

    toStrictEqual 断言检查值是否等于接收值或者同样的结构,如果是对象类型(将会使用递归的方法进行比较),并且会比较它们是否是相同的类型。

    .toEqual 之间的区别:

    • 检查属性值为 undefined 的键。例如使用 .toStrictEqual 时, {a: undefined, b: 2}{b: 2} 不会匹配。
    • 检查数组的稀疏性。 例如使用 .toStrictEqual 时,[, 1][undefined, 1] 不会匹配。
    • 检查对象类型是否相等。例如具有字段 ab 的实例对象不等于具有字段 ab 的字面量对象。
    1. import { test, expect } from 'vitest'
    2. class Stock {
    3. constructor(type) {
    4. this.type = type
    5. }
    6. }
    7. test('structurally the same, but semantically different', () => {
    8. expect(new Stock('apples')).toEqual({ type: 'apples' })
    9. expect(new Stock('apples')).not.toStrictEqual({ type: 'apples' })
    10. })

toContain

  • 类型: (received: string) => Awaitable<void>

    toContain 用于断言检查值是否在数组中。还可以检查一个字符串是否为另一个字符串的子串。

    1. import { expect, test } from 'vitest'
    2. import { getAllFruits } from './stock'
    3. test('the fruit list contains orange', () => {
    4. expect(getAllFruits()).toContain('orange');
    5. })

toContainEqual

  • 类型: (received: any) => Awaitable<void>

    toContainEqual 用于断言在数组中是否包含具有特定结构和值的元素。它就像对每个元素进行 toEqual 操作。

    1. import { test, expect } from 'vitest'
    2. import { getFruitStock } from './stock'
    3. test("apple available", () => {
    4. expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 })
    5. })

toHaveLength

  • 类型: (received: number) => Awaitable<void>

    toHaveLength 用于断言一个对象是否具有 .length 属性,并且它被设置为某个数值。

    1. import { test, expect } from 'vitest'
    2. test('toHaveLength', () => {
    3. expect('abc').toHaveLength(3);
    4. expect([1, 2, 3]).toHaveLength(3);
    5. expect('').not.toHaveLength(3); // .length 的值并不是3
    6. expect({ length: 3 }).toHaveLength(3)
    7. })

toHaveProperty

  • 类型: (key: any, received?: any) => Awaitable<void>

    toHaveProperty 用于断言对象上是否存在指定 key 的属性。

    同时该方法还提供了一个可选参数,用于进行深度对比,就像使用 toEqual 匹配器来比较接收到的属性值。

    1. import { test, expect } from 'vitest'
    2. const invoice = {
    3. isActive: true,
    4. customer: {
    5. first_name: 'John',
    6. last_name: 'Doe',
    7. location: 'China',
    8. },
    9. total_amount: 5000,
    10. items: [
    11. {
    12. type: 'apples',
    13. quantity: 10,
    14. },
    15. {
    16. type: 'oranges',
    17. quantity: 5,
    18. },
    19. ]
    20. }
    21. test('John Doe Invoice', () => {
    22. expect(invoice).toHaveProperty('isActive') // 断言密钥存在
    23. expect(invoice).toHaveProperty('total_amount', 5000) //断言 key 存在且值相等
    24. expect(invoice).not.toHaveProperty('account') //断言这个 key 不存在
    25. // 使用 . 进行深度引用
    26. expect(invoice).toHaveProperty('customer.first_name')
    27. expect(invoice).toHaveProperty('customer.last_name', 'Doe')
    28. expect(invoice).not.toHaveProperty('customer.location', 'India')
    29. // 使用包含 key 的数组进行深度引用
    30. expect(invoice).toHaveProperty('items[0].type', 'apples')
    31. expect(invoice).toHaveProperty('items.0.type', 'apples') // .也有效
    32. })

toMatch

  • 类型: (received: string | regexp) => Awaitable<void>

    toMatch 用于断言字符串是否匹配指定的正则表达式或字符串。

    1. import { expect, test } from 'vitest'
    2. test('top fruits', () => {
    3. expect('top fruits include apple, orange and grape').toMatch(/apple/)
    4. expect('applefruits').toMatch('fruit') // toMatch 也可以是一个字符串
    5. })

toMatchObject

  • 类型: (received: object | array) => Awaitable<void>

    toMatchObject 用于断言对象是否匹配指定的对象属性的子集。

    我们还可以传递对象数组。如果我们只想检查两个数组的元素数量是否匹配,该方法就会很有用,它不同于 arrayContaining ,它允许接收数组中的额外元素。

    1. import { test, expect } from 'vitest'
    2. const johnInvoice = {
    3. isActive: true,
    4. customer: {
    5. first_name: 'John',
    6. last_name: 'Doe',
    7. location: 'China',
    8. },
    9. total_amount: 5000,
    10. items: [
    11. {
    12. type: 'apples',
    13. quantity: 10,
    14. },
    15. {
    16. type: 'oranges',
    17. quantity: 5,
    18. }
    19. ]
    20. }
    21. const johnDetails = {
    22. customer: {
    23. first_name: 'John',
    24. last_name: 'Doe',
    25. location: 'China',
    26. }
    27. }
    28. test('invoice has john personal details', () => {
    29. expect(johnInvoice).toMatchObject(johnDetails)
    30. })
    31. test('the number of elements must match exactly', () => {
    32. // 断言对象数组是否匹配
    33. expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([
    34. { foo: 'bar' },
    35. { baz: 1 },
    36. ])
    37. })

toThrowError

  • 类型: (received: any) => Awaitable<void>

    toThrowError 用于断言函数在调用时是否抛出错误。

    例如,如果我们想测试 getFruitStock('pineapples') 是否会抛出异常,我们可以这样写:

    你可以提供一个可选参数来测试是否引发了指定的错误:

    • 正则表达式:错误信息通过正则表达式匹配
    • 字符串:错误消息包含指定子串

    :::tip 提示 你必须将代码包装在一个函数中,否则将无法捕获错误并且断言将会失败。 :::

    1. import { test, expect } from 'vitest'
    2. function getFruitStock(type) {
    3. if (type === 'pineapples') {
    4. throw new DiabetesError('Pineapples is not good for people with diabetes')
    5. }
    6. // 可以做一些其他的事情
    7. }
    8. test('throws on pineapples', () => {
    9. // 测试错误消息是否在某处显示 "diabetes" :这些是等效的
    10. expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/)
    11. expect(() => getFruitStock('pineapples')).toThrowError('diabetes')
    12. // 测试确切的错误信息
    13. expect(() => getFruitStock('pineapples')).toThrowError(
    14. /^Pineapples is not good for people with diabetes$/,
    15. )
    16. })

toHaveBeenCalled

  • 类型: () => Awaitable<void>

    此断言可以测试一个函数是否被调用过。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. const market = {
    3. buy(subject: string, amount: number) {
    4. // ...
    5. },
    6. }
    7. test('spy function', () => {
    8. const buySpy = vi.spyOn(market, 'buy')
    9. expect(buySpy).not.toHaveBeenCalled()
    10. market.buy('apples', 10)
    11. expect(buySpy).toHaveBeenCalled()
    12. })

toHaveBeenCalledTimes

  • 类型: (amount: number) => Awaitable<void>

    此断言将会检查一个函数是否被调用了一定的次数。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. const market = {
    3. buy(subject: string, amount: number) {
    4. // ...
    5. },
    6. }
    7. test('spy function called two times', () => {
    8. const buySpy = vi.spyOn(market, 'buy')
    9. market.buy('apples', 10)
    10. market.buy('apples', 20)
    11. expect(buySpy).toHaveBeenCalledTimes(2)
    12. })

toHaveBeenCalledWith

  • 类型: (...args: any[]) => Awaitable<void>

    此断言将会检查一个函数是否被调用过,并且传入了指定的参数。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. const market = {
    3. buy(subject: string, amount: number) {
    4. // ...
    5. },
    6. }
    7. test('spy function', () => {
    8. const buySpy = vi.spyOn(market, 'buy')
    9. market.buy('apples', 10)
    10. market.buy('apples', 20)
    11. expect(buySpy).toHaveBeenCalledWith('apples', 10)
    12. expect(buySpy).toHaveBeenCalledWith('apples', 20)
    13. })

toHaveBeenLastCalledWith

  • 类型: (...args: any[]) => Awaitable<void>

    此断言将会检查一个函数在最后一次被调用时,是否使用了某些参数。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. const market = {
    3. buy(subject: string, amount: number) {
    4. // ...
    5. },
    6. }
    7. test('spy function', () => {
    8. const buySpy = vi.spyOn(market, 'buy')
    9. market.buy('apples', 10)
    10. market.buy('apples', 20)
    11. expect(buySpy).not.toHaveBeenLastCalledWith('apples', 10)
    12. expect(buySpy).toHaveBeenLastCalledWith('apples', 20)
    13. })

toHaveBeenNthCalledWith

  • 类型: (time: number, ...args: any[]) => Awaitable<void>

    此断言将会检查一个函数在第某次调用时是否使用了某些参数,从第 1 次开始。所以如果要检查第 2 次调用,你可以这样写 .toHaveBeenNthCalledWith(2, ...)

    需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. const market = {
    3. buy(subject: string, amount: number) {
    4. // ...
    5. },
    6. }
    7. test('first call of spy function called with right params', () => {
    8. const buySpy = vi.spyOn(market, 'buy')
    9. market.buy('apples', 10)
    10. market.buy('apples', 20)
    11. expect(buySpy).toHaveBeenNthCalledWith(1, 'apples', 10)
    12. })

toHaveReturned

  • 类型: () => Awaitable<void>

    此断言检查一个函数是否至少成功返回了一次值(即没有抛出错误)。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. const getApplesPrice = (amount: number) => {
    3. const PRICE = 10
    4. return amount * PRICE
    5. }
    6. test('spy function returned a value', () => {
    7. const getPriceSpy = vi.fn(getApplesPrice)
    8. const price = getPriceSpy(10)
    9. expect(price).toBe(100)
    10. expect(getPriceSpy).toHaveReturned()
    11. })

toHaveReturnedTimes

  • 类型: (amount: number) => Awaitable<void>

    此断言将会检查一个函数是否成功返回了确切的次数(即没有抛出错误)。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. test('spy function returns a value two times', () => {
    3. const sell = vi.fn((product: string) => ({ product }))
    4. sell('apples')
    5. sell('bananas')
    6. expect(sell).toHaveReturnedTimes(2)
    7. })

toHaveReturnedWith

  • 类型: (returnValue: any) => Awaitable<void>

    此断言将会检查一个函数是否至少一次成功返回了指定的值(即没有抛出错误)。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. test('spy function returns a product', () => {
    3. const sell = vi.fn((product: string) => ({ product }))
    4. sell('apples')
    5. expect(sell).toHaveReturnedWith({ procuct: 'apples' })
    6. })

toHaveLastReturnedWith

  • 类型: (returnValue: any) => Awaitable<void>

    此断言将会检查一个函数是否在最后一次被调用时返回了指定的值。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. test('spy function returns bananas on a last call', () => {
    3. const sell = vi.fn((product: string) => ({ product }))
    4. sell('apples')
    5. sell('bananas')
    6. expect(sell).toHaveLastReturnedWith({ procuct: 'bananas' })
    7. })

toHaveNthReturnedWith

  • 类型: (time: number, returnValue: any) => Awaitable<void>

    此断言将会检查一个函数是否第某次被调用时返回了指定的值。需要给 expect 传递一个监听函数。

    1. import { expect, test, vi } from 'vitest'
    2. test('spy function returns bananas on second call', () => {
    3. const sell = vi.fn((product: string) => ({ product }))
    4. sell('apples')
    5. sell('bananas')
    6. expect(sell).toHaveNthReturnedWith(2, { product: 'bananas' })
    7. })

resolves

  • 类型: Promisify<Assertions>

    resolves 可以在断言异步代码时有意地删除样板语法。使用它可以从待处理的 Promise 中去展开它的值,并使用通常的断言语句来断言它的值。如果 Promise 被拒绝,则断言将会失败。

    它返回相同的 Assertions 对象,但所有匹配器现在都是返回 Promise,因此你需要使用 await 去阻塞它。同样也适用于 chai 断言。

    例如,如果我们有一个函数,它调用 API 并返回一些数据,你可以使用下列代码来断言它的返回值:

    1. import { test, expect } from 'vitest'
    2. function buyApples() {
    3. return fetch('/buy/apples').then(r => r.json())
    4. }
    5. test('buyApples returns new stock id', async () => {
    6. // toEqual 现在返回一个 Promise ,所以我们必须等待它
    7. await expect(buyApples()).resolves.toEqual({ id: 1 })
    8. })

    :::warning 警告 如果没有等待断言,那么我们将有一个每次都会通过的误报测试。为了确保断言确实发生,我们可以使用 expect.assertions(number) . :::

rejects

  • 类型: Promisify<Assertions>

    rejects 可以在断言异步代码时有意地删除样板语法。使用它可以来展开 Promise 被拒绝的原因,并使用通常的断言语句来断言它的值。如果 Promise 成功解决,则断言将失败。

    它返回相同的 Assertions 对象,但所有匹配器现在都返回 Promise,因此你需要使用 await 去阻塞它。同样也适用于 chai 断言。

    例如,如果我们有一个调用失败的函数,我们可以使用此代码来断言原因:

    1. import { test, expect } from 'vitest'
    2. function buyApples(id) {
    3. if(!id) {
    4. throw new Error('no id')
    5. }
    6. }
    7. test('buyApples throws an error when no id provided', async () => {
    8. // toThrow 现在返回一个 Promise ,所以你必须等待它
    9. await expect(buyApples()).rejects.toThrow('no id')
    10. })

    :::warning 警告 如果不等待断言,那么我们将有一个每次都会通过的误报测试。 为确保断言确实发生,我们可以使用 expect.assertions(number)。 :::

expect.assertions

  • 类型: (count: number) => void

    在测试通过或失败后,它将会验证在测试期间调用了多少次断言。它常用于检查异步代码是否被调用了。

    例如,如果我们有一个异步调用两个匹配器的函数,我们可以断言它们实际上是被调用的。

    1. import { test, expect } from 'vitest'
    2. async function doAsync(...cbs) {
    3. await Promise.all(
    4. cbs.map((cb, index) => cb({ index }))
    5. )
    6. }
    7. test('all assertions are called', async () => {
    8. expect.assertions(2);
    9. function callback1(data) {
    10. expect(data).toBeTruthy();
    11. }
    12. function callback2(data) {
    13. expect(data).toBeTruthy();
    14. }
    15. await doAsync(callback1, callback2);
    16. })

expect.hasAssertions

  • 类型: (count: number) => void

    在测试通过或失败后,它将会验证在测试期间是否至少调用了一个断言。它常用于检查是否调用了异步代码。

    例如,如果我们有一个调用回调的代码,我们可以在回调中进行断言,但如果我们不检查是否调用了断言,测试将始终通过。

    1. import { test, expect } from 'vitest'
    2. import { db } from './db'
    3. const cbs = []
    4. function onSelect(cb) {
    5. cbs.push(cb)
    6. }
    7. // 从 db 中选择后,我们调用所有的回调
    8. function select(id) {
    9. return db.select({ id }).then(data => {
    10. return Promise.all(
    11. cbs.map(cb => cb(data))
    12. )
    13. })
    14. }
    15. test('callback was called', async () => {
    16. expect.hasAssertions()
    17. onSelect((data) => {
    18. // 在选择时调用
    19. expect(data).toBeTruthy();
    20. })
    21. // 如果不等待,测试将失败
    22. // 如果你没有 expect.hasAssertions(),测试将通过
    23. await select(3)
    24. })

Setup and Teardown

这些功能允许我们连接到测试的生命周期,以避免重复设置和拆卸代码。 它们适用于当前上下文:如果它们在顶层使用,则适用于文件;如果它们在 describe 块内,则适用于当前测试套件。

beforeEach

  • 类型: beforeEach(fn: () => Awaitable<void>, timeout?: number)

    注册一个回调,在当前上下文中的每个测试运行之前被调用。 如果函数返回一个 PromiseVitest 会等到 Promise 解决后再运行测试。

    或者,我们可以传递一个超时(以毫秒为单位),定义在终止之前等待多长时间。 默认值为 5 秒。

    1. import { beforeEach } from 'vitest'
    2. beforeEach(async () => {
    3. // 在每次测试运行之前清除模拟并添加一些测试数据
    4. await stopMocking()
    5. await addUser({ name: 'John'})
    6. })

    beforeEach 确保为每个测试都添加用户。

afterEach

  • 类型: afterEach(fn: () => Awaitable<void>, timeout?: number)

    注册一个回调,在当前上下文中的每个测试运行之后被调用。 如果函数返回一个 Promise ,Vitest 会等到 Promise 解决后再继续。

    或者,你可以设置超时(以毫秒为单位)以指定在终止前等待多长时间。 默认值为 5 秒。

    1. import { afterEach } from 'vitest'
    2. afterEach(async () => {
    3. await clearTestingData() // 每次测试运行后清除测试数据
    4. })

    afterEach 确保在每次测试运行后清除测试数据。

beforeAll

  • 类型: beforeAll(fn: () => Awaitable<void>, timeout?: number)

    注册一个回调,在开始运行当前上下文中的所有测试之前被调用一次。 如果函数返回一个 PromiseVitest 会等到 Promise 解决后再运行测试。

    或者,你可以提供超时(以毫秒为单位)以指定在终止之前等待多长时间。 默认值为 5 秒。

    1. import { beforeAll } from 'vitest'
    2. beforeAll(async () => {
    3. await startMocking() // 在所有测试运行之前调用一次
    4. })

    beforeAll 确保在测试运行之前设置模拟数据

afterAll

  • 类型: afterAll(fn: () => Awaitable<void>, timeout?: number)

    注册一个回调,在当前上下文中运行所有测试后被调用一次。 如果函数返回一个 Promise,Vitest 会等到 Promise 解决后再继续。

    或者,你可以提供超时(以毫秒为单位)以指定在终止之前等待多长时间。 默认值为 5 秒。

    1. import { afterAll } from 'vitest'
    2. afterAll(async () => {
    3. await stopMocking() // 在所有测试运行后调用此方法
    4. })

    afterAll 确保在所有测试运行后调用 stopMocking 方法。

Vi

Vitest 通过 vi 提供工具函数来帮助你。你可以 import { vi } from 'vitest'全局地 访问它 (当 globals configuration 启用 时)。

vi.advanceTimersByTime

  • 类型: (ms: number) => Vitest

    就像 runAllTimers 一样工作,但会在经过几毫秒后结束。例如,这将输出 1, 2, 3 并且不会抛出:

    1. let i = 0
    2. setInterval(() => console.log(++i), 50)
    3. vi.advanceTimersByTime(150)

vi.advanceTimersToNextTimer

  • 类型: () => Vitest

    调用下一个可调用的计时器。这在每个计时器调用间隔内进行断言很有用。你可以链式调用它来自己管理计时器。

    1. let i = 0
    2. setInterval(() => console.log(++i), 50)
    3. vi.advanceTimersToNextTimer() // 输出 1
    4. .advanceTimersToNextTimer() // 输出 2
    5. .advanceTimersToNextTimer() // 输出 3

vi.clearAllTimers

删除所有计划运行的计时器。这些计时器后续将不会运行。

vi.fn

  • 类型: (fn: Function) => CallableMockInstance

    为函数创建一个监听,但也可以在没有监听的情况下启动。每次调用函数时,存储其调用参数、返回值和实例。此外,你可以使用 methods 操纵它的行为。 如果没有给出函数,mock 将在调用时返回 undefined

    1. const getApples = vi.fn(() => 0)
    2. getApples()
    3. expect(getApples).toHaveBeenCalled()
    4. expect(getApples).toHaveReturnedWith(0)
    5. getApples.mockReturnValueOnce(5)
    6. const res = getApples()
    7. expect(res).toBe(5)
    8. expect(getApples).toHaveNthReturnedWith(2, 5)

vi.getMockedSystemTime

  • 类型: () => Date | null

    返回使用 setSystemTime 设置的模拟的当前日期。如果日期没有被模拟,将返回 null

vi.getRealSystemTime

  • 类型: () => number

    使用 vi.useFakeTimers 时,会模拟 Date.now 调用。如果需要获取毫秒级的实时时间,你可以调用这个函数。

vi.mock

类型: (path: string, factory?: () => unknown) => void

使传递的模块的所有 imports都被模拟。在 path 中,你可以使用配置好的 Vite 别名。

  • 如果定义了 factory,将返回其结果。工厂函数可以是异步的。你可以在内部调用 vi.importActual 来获取原始模块。对 vi.mock 的调用将被提升到文件的顶部,因此你无法访问在全局文件范围内声明的变量!

    1. vi.mock('path', () => {
    2. return {
    3. default: { myDefaultKey: vi.fn() },
    4. namedExport: vi.fn(),
    5. // etc...
    6. }
    7. })
  • 如果 __mocks__ 文件夹下存在同名文件,则所有导入都将返回其导出。例如,带有 <root>/__mocks__/axios.ts 文件夹的 vi.mock('axios') 将返回从 axios.ts 中导出的所有内容。

  • 如果里面没有 __mocks__ 文件夹或同名文件,将调用原始模块并对其进行模拟。(有关应用的规则,请参阅 自动模拟算法。)

vi.setSystemTime

  • 类型: (date: string | number | Date) => void

    将当前日期设置为一个过去的日期。所有 Date 调用都将返回此日期。

    有助于你测试依赖当前日期的任何内容 —— 例如,你代码中的 luxon 调用。

    1. const date = new Date(1998, 11, 19)
    2. vi.useFakeTimers()
    3. vi.setSystemTime(date)
    4. expect(Date.now()).toBe(date.valueOf())
    5. vi.useRealTimers()

vi.mocked

  • 类型: <T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>

    TypeScript 的类型助手。实际上只是返回传递的对象。

    1. import example from './example'
    2. vi.mock('./example')
    3. test('1+1 equals 2', async() => {
    4. vi.mocked(example.calc).mockRestore()
    5. const res = example.calc(1, '+', 1)
    6. expect(res).toBe(2)
    7. })

vi.importActual

  • 类型: <T>(path: string) => Promise<T>

    导入模块,如果它应该被模拟,则绕过所有检查。如果你想部分模拟模块,这可能会很有用。

    1. vi.mock('./example', async() => {
    2. const axios = await vi.importActual('./example')
    3. return { ...axios, get: vi.fn() }
    4. })

vi.importMock

  • 类型: <T>(path: string) => Promise<MaybeMockedDeep<T>>

    导入一个被模拟的包含其所有属性 (包括嵌套属性) 的模块。遵循与 vi.mock 相同的规则。有关应用的规则,请参阅 自动模拟算法

vi.resetModules

  • 类型: () => Vitest

    通过清除所有模块的缓存来重置模块的注册表。在我们对隔离测试本地状态冲突的模块时很有用。

    1. import { vi } from 'vitest'
    2. beforeAll(() => {
    3. vi.resetModules()
    4. })
    5. test('change state', async() => {
    6. const mod = await import('./some/path')
    7. mod.changeLocalState('new value')
    8. expect(mod.getlocalState()).toBe('new value')
    9. })
    10. test('module has old state', async() => {
    11. const mod = await import('./some/path')
    12. expect(mod.getlocalState()).toBe('old value')
    13. })

vi.restoreCurrentDate

  • 类型: () => void

    Date 恢复为系统时间。

vi.runAllTicks

  • 类型: () => Vitest

    调用每个微任务。它们通常排列在 proccess.nextTick 中。它也将运行它们自己安排的所有微任务。

vi.runAllTimers

  • 类型: () => Vitest

    此方法将调用每个被创建的计时器,直到计时器队列为空。这意味着在 runAllTimers 期间调用的每个计时器都将被触发。如果你有一个无限的区间,它会在 10000 次尝试后抛出。例如,这将输出 1, 2, 3

    1. let i = 0
    2. setTimeout(() => console.log(++i))
    3. const interval = setInterval(() => {
    4. console.log(++i)
    5. if (i === 2)
    6. clearInterval(interval)
    7. }, 50)
    8. vi.runAllTimers()

vi.runOnlyPendingTimers

  • 类型: () => Vitest

    此方法将调用在 vi.useFakeTimers() 调用之后创建的每个计时器。它不会触发在其调用期间创建的任何计时器。例如,这只会输出 1

    1. let i = 0
    2. setInterval(() => console.log(++i), 50)
    3. vi.runOnlyPendingTimers()

vi.spyOn

  • 类型: <T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance

    在对象的方法或 getter/setter 上创建一个监听。

    1. let apples = 0
    2. const obj = {
    3. getApples: () => 13,
    4. }
    5. const spy = vi.spyOn(obj, 'getApples').mockImplementation(() => apples)
    6. apples = 1
    7. expect(obj.getApples()).toBe(1)
    8. expect(spy).toHaveBeenCalled()
    9. expect(spy).toHaveReturnedWith(1)

vi.unmock

类型: (path: string) => void

从模拟注册表中删除模块 所有后续的 import 调用都将返回原始模块,即使它被模拟了。

vi.useFakeTimers

  • 类型: () => Vitest

    要启用模拟计时器,你需要调用此方法。它将包装对计时器的所有进一步调用 (例如 setTimeoutsetIntervalclearTimeoutclearIntervalnextTicksetImmediateclearImmediateDate),直到 vi.useRealTimers() 被调用。

    它的内部实现基于 @sinonjs/fake-timers

vi.useRealTimers

  • 类型: () => Vitest

    当计时器结束时,你可以调用此方法,将模拟计时器恢复其原始实现。之前运行的所有计时器将不会恢复。

MockInstance Methods

getMockName

  • 类型: () => string

    它返回使用 .mockName(name) 方法设置给模拟对象的 name 。

mockClear

  • 类型: () => MockInstance

    清除每一个对象模拟调用的所有信息。调用后,spy.mock.callsspy.mock.results 将返回空数组。 如果你需要清理不同断言之间的对象监听,这会很有用。

    如果你希望在每次测试之前自动调用此方法,你可以在配置中启用 clearMocks 设置。

mockName

  • 类型: (name: string) => MockInstance

    设置内部模拟对象名称。有助于查看哪些模拟对象导致断言失败。

mockImplementation

  • 类型: (fn: Function) => MockInstance

    接收一个用于模拟对象实现的函数。

    例如:

    1. const mockFn = vi.fn().mockImplementation(apples => apples + 1)
    2. // or: vi.fn(apples => apples + 1);
    3. const NelliesBucket = mockFn(0)
    4. const BobsBucket = mockFn(1)
    5. NelliesBucket === 1 // true
    6. BobsBucket === 2 // true
    7. mockFn.mock.calls[0][0] === 0 // true
    8. mockFn.mock.calls[1][0] === 1 // true

mockImplementationOnce

  • 类型: (fn: Function) => MockInstance

    接收一个只会被对象模拟函数调用一次,用于模拟对象实现的函数。可以链式调用,以便多个函数调用产生不同的结果。

    1. const myMockFn = vi
    2. .fn()
    3. .mockImplementationOnce(() => true)
    4. .mockImplementationOnce(() => false)
    5. myMockFn() // true
    6. myMockFn() // false

    当对象模拟函数执行完毕,它将调用 vi.fn(() => defaultValue).mockImplementation(() => defaultValue) 设置的默认实现。如果它们被调用:

    1. const myMockFn = vi
    2. .fn(() => 'default')
    3. .mockImplementationOnce(() => 'first call')
    4. .mockImplementationOnce(() => 'second call')
    5. // 'first call', 'second call', 'default', 'default'
    6. console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn())

mockRejectedValue

  • 类型: (value: any) => MockInstance

    当异步函数被调用时,接收一个将被拒绝 ( reject ) 的错误。

    1. test('async test', async() => {
    2. const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'))
    3. await asyncMock() // throws "Async error"
    4. })

mockRejectedValueOnce

  • 类型: (value: any) => MockInstance

    接收一个只会被对象模拟函数拒绝一次的值。如果链式调用,每个连续调用都将拒绝传入的值。

    1. test('async test', async() => {
    2. const asyncMock = vi
    3. .fn()
    4. .mockResolvedValueOnce('first call')
    5. .mockRejectedValueOnce(new Error('Async error'))
    6. await asyncMock() // first call
    7. await asyncMock() // throws "Async error"
    8. })

mockReset

  • 类型: () => MockInstance

    执行 mockClear 同样的操作,并将内部实现设置为空函数 (调用时返回 undefined )。当你想要完全重置一个模拟对象为其初始状态时,这会很有用。

    如果你希望在每次测试之前自动调用此方法,你可以在配置中启用 mockReset 设置。

mockRestore

  • 类型: () => MockInstance

    执行 mockRestore 同样的操作,并将内部实现恢复为初始的函数。

    请注意,从 vi.fn() 恢复模拟对象会将实现设置为返回 undefined 的空函数。恢复 vi.fn(impl) 会将实现恢复为 impl

    如果你希望在每次测试之前自动调用此方法,我们可以在配置中启用 restoreMocks 设置。

mockResolvedValue

  • 类型: (value: any) => MockInstance

    当异步函数被调用时,接收一个将被决议 ( resolve ) 的值。

    1. test('async test', async() => {
    2. const asyncMock = vi.fn().mockResolvedValue(43)
    3. await asyncMock() // 43
    4. })

mockResolvedValueOnce

  • 类型: (value: any) => MockInstance

    接收一个只会被对象模拟函数决议一次的值。如果链式调用,每个连续调用都将决议传入的值。

    1. test('async test', async() => {
    2. const asyncMock = vi
    3. .fn()
    4. .mockResolvedValue('default')
    5. .mockResolvedValueOnce('first call')
    6. .mockResolvedValueOnce('second call')
    7. await asyncMock() // first call
    8. await asyncMock() // second call
    9. await asyncMock() // default
    10. await asyncMock() // default
    11. })

mockReturnThis

  • 类型: () => MockInstance

    设置内部实现返回 this 上下文。

mockReturnValue

  • 类型: (value: any) => MockInstance

    接收一个调用对象模拟函数时将返回的值。

    1. const mock = vi.fn()
    2. mock.mockReturnValue(42)
    3. mock() // 42
    4. mock.mockReturnValue(43)
    5. mock() // 43

mockReturnValueOnce

  • 类型: (value: any) => MockInstance

    接收一个只会被对象模拟函数返回一次的值。如果链式调用,每个连续调用都会返回传入的值。当没有更多的 mockReturnValueOnce 值要使用时,调用由 mockImplementation 或其他 mockReturn* 方法指定的函数。

    1. const myMockFn = vi
    2. .fn()
    3. .mockReturnValue('default')
    4. .mockReturnValueOnce('first call')
    5. .mockReturnValueOnce('second call')
    6. // 'first call', 'second call', 'default', 'default'
    7. console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn())

MockInstance Properties

mock.calls

这是一个包含每个调用的所有参数的数组。数组的每一项都是该调用的参数。

如果一个函数被调用两次,并依次使用以下参数 fn(arg1, arg2)fn(arg3, arg4),那么 mock.calls 将是:

  1. [
  2. ['arg1', 'arg2'],
  3. ['arg3', 'arg4'],
  4. ]

mock.results

这是一个包含所有函数 return 的值的数组。该数组的一项是具有 typevalue 属性的对象。可用类型有:

  • 'return' - 函数返回而不抛出。
  • 'throw' - 函数抛出了一个值。

value 属性包含返回值或抛出的错误。

如果函数返回 result ,然后抛出错误,那么 mock.results 将是:

  1. [
  2. {
  3. type: 'return',
  4. value: 'result',
  5. },
  6. {
  7. type: 'throw',
  8. value: Error,
  9. },
  10. ]

mock.instances

还未实现。