跳至内容

测试上下文

Playwright Fixtures 的启发,Vitest 的测试上下文允许您定义可以在测试中使用的工具、状态和夹具。

用法

每个测试回调的第一个参数都是一个测试上下文。

ts
import {  } from 'vitest'

('should work', () => {
  // prints name of the test
  .(..)
})

内置测试上下文

context.task

包含有关测试的元数据的只读对象。

context.expect

绑定到当前测试的 expect API

ts
import {  } from 'vitest'

('math is easy', ({  }) => {
  (2 + 2).(4)
})

此 API 对于并发运行快照测试很有用,因为全局 expect 无法跟踪它们

ts
import {  } from 'vitest'

.('math is easy', ({  }) => {
  (2 + 2).()
})

.('math is hard', ({  }) => {
  (2 * 2).()
})

context.skip

跳过后续测试执行并将测试标记为跳过

ts
import { expect, it } from 'vitest'

it('math is hard', ({ skip }) => {
  skip()
  expect(2 + 2).toBe(5)
})

扩展测试上下文

Vitest 提供两种不同的方法来帮助您扩展测试上下文。

test.extend

警告

此 API 自 Vitest 0.32.3 起可用。

Playwright 一样,您可以使用此方法定义自己的 test API,并使用自定义夹具,并在任何地方重用它。

例如,我们首先使用两个夹具 todosarchive 创建 myTest

ts
// my-test.ts
import { test } from 'vitest'

const todos = []
const archive = []

export const myTest = test.extend({
  todos: async ({}, use) => {
    // setup the fixture before each test function
    todos.push(1, 2, 3)

    // use the fixture value
    await use(todos)

    // cleanup the fixture after each test function
    todos.length = 0
  },
  archive
})

然后我们可以导入并使用它。

ts
import { expect } from 'vitest'
import { myTest } from './my-test.js'

myTest('add items to todos', ({ todos }) => {
  expect(todos.length).toBe(3)

  todos.push(4)
  expect(todos.length).toBe(4)
})

myTest('move items from todos to archive', ({ todos, archive }) => {
  expect(todos.length).toBe(3)
  expect(archive.length).toBe(0)

  archive.push(todos.pop())
  expect(todos.length).toBe(2)
  expect(archive.length).toBe(1)
})

我们还可以通过扩展 myTest 添加更多夹具或覆盖现有夹具。

ts
export const myTest2 = myTest.extend({
  settings: {
    // ...
  }
})

夹具初始化

Vitest 运行器将根据使用情况智能地初始化您的夹具并将它们注入测试上下文。

ts
import { test } from 'vitest'

async function todosFn({ task }, use) {
  await use([1, 2, 3])
}

const myTest = test.extend({
  todos: todosFn,
  archive: []
})

// todosFn will not run
myTest('', () => {})
myTest('', ({ archive }) => {})

// todosFn will run
myTest('', ({ todos }) => {})

警告

在使用 test.extend() 和夹具时,您应该始终使用对象解构模式 { todos } 在夹具函数和测试函数中访问上下文。

自动夹具

警告

此功能自 Vitest 1.3.0 起可用。

Vitest 还支持夹具的元组语法,允许您为每个夹具传递选项。例如,您可以使用它来显式初始化夹具,即使它没有在测试中使用。

ts
import { test as base } from 'vitest'

const test = base.extend({
  fixture: [
    async ({}, use) => {
      // this function will run
      setup()
      await use()
      teardown()
    },
    { auto: true } // Mark as an automatic fixture
  ],
})

test('', () => {})

TypeScript

要为所有自定义上下文提供夹具类型,您可以将夹具类型作为泛型传递。

ts
interface MyFixtures {
  todos: number[]
  archive: number[]
}

const myTest = test.extend<MyFixtures>({
  todos: [],
  archive: []
})

myTest('', (context) => {
  expectTypeOf(context.todos).toEqualTypeOf<number[]>()
  expectTypeOf(context.archive).toEqualTypeOf<number[]>()
})

beforeEachafterEach

每个测试的上下文都不同。您可以在 beforeEachafterEach 钩子中访问和扩展它们。

ts
import { beforeEach, it } from 'vitest'

beforeEach(async (context) => {
  // extend context
  context.foo = 'bar'
})

it('should work', ({ foo }) => {
  console.log(foo) // 'bar'
})

TypeScript

要为所有自定义上下文提供属性类型,您可以通过添加来聚合 TestContext 类型

ts
declare module 'vitest' {
  export interface TestContext {
    foo?: string
  }
}

如果您只想为特定的 beforeEachafterEachittest 钩子提供属性类型,您可以将类型作为泛型传递。

ts
interface LocalTestContext {
  foo: string
}

beforeEach<LocalTestContext>(async (context) => {
  // typeof context is 'TestContext & LocalTestContext'
  context.foo = 'bar'
})

it<LocalTestContext>('should work', ({ foo }) => {
  // typeof foo is 'string'
  console.log(foo) // 'bar'
})