Skip to content
Vitest 3
Main Navigation 指南 & API配置瀏覽器模式進階 API
3.2.0
2.1.9
1.6.1
0.34.6

繁體中文

English
简体中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

繁體中文

English
简体中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

外觀

Sidebar Navigation

簡介

為何選擇 Vitest

快速入門

功能特色

配置參考

API

測試 API 參考

模擬函式

Vi

expect

expectTypeOf

assert

assertType

指南

命令列介面

測試篩選

測試專案

報告器

程式碼覆蓋率

快照

模擬(Mocking)

平行化

型別測試

Vitest UI

內聯測試

測試上下文

測試註解

測試環境

擴展匹配器

IDE 整合

偵錯

常見錯誤

遷移指南

遷移到 Vitest 3.0

從 Jest 遷移

效能

測試效能分析

提升效能

瀏覽器模式

進階 API

與其他測試執行器的比較

本頁導覽

測試上下文 ​

受 Playwright Fixtures 啟發,Vitest 的測試上下文允許您定義可在測試中使用的輔助函數、狀態及夾具(fixtures)。

用法 ​

每個測試回呼函數的第一個參數都是測試上下文。

ts
import { it } from 'vitest';

it('should work', ({ task }) => {
  // 輸出測試名稱
  console.log(task.name);
});

內建測試上下文 ​

task ​

一個唯讀物件,包含關於測試的元資料。

expect ​

綁定到當前測試的 expect API:

ts
import { it } from 'vitest';

it('math is easy', ({ expect }) => {
  expect(2 + 2).toBe(4);
});

此 API 對於並行執行快照測試非常有用,因為全域的 expect 無法追蹤它們:

ts
import { it } from 'vitest';

it.concurrent('math is easy', ({ expect }) => {
  expect(2 + 2).toMatchInlineSnapshot();
});

it.concurrent('math is hard', ({ expect }) => {
  expect(2 * 2).toMatchInlineSnapshot();
});

skip ​

ts
function skip(note?: string): never;
function skip(condition: boolean, note?: string): void;

跳過後續測試執行並將測試標記為已跳過:

ts
import { expect, it } from 'vitest';

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

自 Vitest 3.1 起,它接受一個布林值參數,以便根據條件跳過測試:

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

annotate 3.2.0+ ​

ts
function annotate(
  message: string,
  attachment?: TestAttachment
): Promise<TestAnnotation>;

function annotate(
  message: string,
  type?: string,
  attachment?: TestAttachment
): Promise<TestAnnotation>;

添加一個將由您的 reporter 顯示的測試註解。

ts
test('annotations API', async ({ annotate }) => {
  await annotate('https://github.com/vitest-dev/vitest/pull/7953', 'issues');
});

signal 3.2.0+ ​

一個可由 Vitest 中止的 AbortSignal。在以下情況下,信號會中止:

  • 測試逾時
  • 使用者手動按下 Ctrl+C 取消測試執行
  • vitest.cancelCurrentRun 透過程式碼呼叫
  • 另一個測試在並行執行時失敗且已設定 bail 旗標
ts
it('stop request when test times out', async ({ signal }) => {
  await fetch('/resource', { signal });
}, 2000);

onTestFailed ​

綁定到當前測試的 onTestFailed 鉤子。如果您並行執行測試且僅需針對此特定測試進行特殊處理,則此 API 很有用。

onTestFinished ​

綁定到當前測試的 onTestFinished 鉤子。如果您並行執行測試且僅需針對此特定測試進行特殊處理,則此 API 很有用。

擴展測試上下文 ​

Vitest 提供兩種擴展測試上下文的方式。

test.extend ​

與 Playwright 類似,您可以使用此方法定義自己的 test API,其中包含自訂夾具並在任何地方重複使用。

例如,我們首先建立一個包含兩個夾具的 test 收集器:todos 和 archive。

ts
import { test as baseTest } from 'vitest';

const todos = [];
const archive = [];

export const test = baseTest.extend({
  todos: async ({}, use) => {
    // 在每個測試函數之前設定夾具
    todos.push(1, 2, 3);

    // 使用夾具值
    await use(todos);

    // 在每個測試函數之後清理夾具
    todos.length = 0;
  },
  archive,
});

然後我們可以導入並使用它。

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

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

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

test('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);
});

我們還可以透過擴展我們的 test 來添加更多夾具或覆寫現有夾具。

ts
import { test as todosTest } from './my-test.js';

export const test = todosTest.extend({
  settings: {
    // ...
  },
});

夾具初始化 ​

Vitest 執行器將根據使用情況智能地初始化您的夾具並將它們注入測試上下文。

ts
import { test as baseTest } from 'vitest';

const test = baseTest.extend<{
  todos: number[];
  archive: number[];
}>({
  todos: async ({ task }, use) => {
    await use([1, 2, 3]);
  },
  archive: [],
});

// todos 將不會執行
test('skip', () => {});
test('skip', ({ archive }) => {});

// todos 將會執行
test('run', ({ todos }) => {});

WARNING

當使用 test.extend() 搭配夾具時,您應該始終使用物件解構模式 { todos } 來存取夾具函數和測試函數中的上下文。

ts
test('context must be destructured', (context) => { 
  expect(context.todos.length).toBe(2)
})

test('context must be destructured', ({ todos }) => { 
  expect(todos.length).toBe(2)
})

自動夾具 ​

Vitest 也支援夾具的元組(tuple)語法,允許您為每個夾具傳遞選項。例如,您可以使用它來顯式初始化夾具,即使它未在測試中使用。

ts
import { test as base } from 'vitest';

const test = base.extend({
  fixture: [
    async ({}, use) => {
      // 此函數將會執行
      setup();
      await use();
      teardown();
    },
    { auto: true }, // 標記為自動夾具
  ],
});

test('works correctly');

預設夾具 ​

自 Vitest 3 起,您可以在不同的專案中設置不同的值。要啟用此功能,請將 { injected: true } 傳遞至選項。如果專案配置中未指定該鍵,則將使用預設值。

ts
import { test as base } from 'vitest';

const test = base.extend({
  url: [
    // 如果配置中未定義 "url" 的預設值
    '/default',
    // 將夾具標記為 "injected" 以允許覆寫
    { injected: true },
  ],
});

test('works correctly', ({ url }) => {
  // 在 "project-new" 中 url 為 "/default"
  // 在 "project-full" 中 url 為 "/full"
  // 在 "project-empty" 中 url 為 "/empty"
});
ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    projects: [
      {
        test: {
          name: 'project-new',
        },
      },
      {
        test: {
          name: 'project-full',
          provide: {
            url: '/full',
          },
        },
      },
      {
        test: {
          name: 'project-empty',
          provide: {
            url: '/empty',
          },
        },
      },
    ],
  },
});

將值作用範圍到套件 3.1.0+ ​

自 Vitest 3.1 起,您可以使用 test.scoped API 覆寫每個套件及其子級的上下文值:

ts
import { test as baseTest, describe, expect } from 'vitest';

const test = baseTest.extend({
  dependency: 'default',
  dependant: ({ dependency }, use) => use({ dependency }),
});

describe('use scoped values', () => {
  test.scoped({ dependency: 'new' });

  test('uses scoped value', ({ dependant }) => {
    // dependant 使用新的覆寫值,該值作用範圍於
    // 此套件中的所有測試
    expect(dependant).toEqual({ dependency: 'new' });
  });

  describe('keeps using scoped value', () => {
    test('uses scoped value', ({ dependant }) => {
      // 巢狀套件繼承了該值
      expect(dependant).toEqual({ dependency: 'new' });
    });
  });
});

test('keep using the default values', ({ dependant }) => {
  // dependency 正在使用預設值
  // 在 .scoped 套件之外的值
  expect(dependant).toEqual({ dependency: 'default' });
});

如果您有一個依賴於動態變數(例如資料庫連線)的上下文值,則此 API 特別有用:

ts
const test = baseTest.extend<{
  db: Database;
  schema: string;
}>({
  db: async ({ schema }, use) => {
    const db = await createDb({ schema });
    await use(db);
    await cleanup(db);
  },
  schema: '',
});

describe('one type of schema', () => {
  test.scoped({ schema: 'schema-1' });

  // ... tests
});

describe('another type of schema', () => {
  test.scoped({ schema: 'schema-2' });

  // ... tests
});

每作用範圍上下文 3.2.0+ ​

您可以定義每個檔案或每個工作者僅初始化一次的上下文。它的初始化方式與帶有物件參數的常規夾具相同:

ts
import { test as baseTest } from 'vitest';

export const test = baseTest.extend({
  perFile: [({}, { use }) => use([]), { scope: 'file' }],
  perWorker: [({}, { use }) => use([]), { scope: 'worker' }],
});

除非夾具選項中設定了 auto: true,否則該值會在任何測試首次存取時初始化——在這種情況下,該值會在任何測試執行之前初始化。

ts
const test = baseTest.extend({
  perFile: [
    ({}, { use }) => use([]),
    {
      scope: 'file',
      // 總是在任何測試之前執行此鉤子
      auto: true,
    },
  ],
});

worker 作用範圍將為每個工作者執行夾具一次。正在執行的工作者數量取決於各種因素。預設情況下,每個檔案都在單獨的工作者中執行,因此 file 和 worker 作用範圍的工作方式相同。

但是,如果您禁用隔離,則工作者數量將受 maxWorkers 或 poolOptions 配置的限制。

請注意,在 vmThreads 或 vmForks 中執行測試時,指定 scope: 'worker' 的行為與 scope: 'file' 相同。存在此限制是因為每個測試檔案都有自己的 VM 上下文,因此如果 Vitest 僅初始化一次,一個上下文可能會洩漏到另一個上下文並導致許多參考不一致(例如,相同類別的實例可能會參考不同的建構函式)。

TypeScript ​

要為所有自訂上下文提供夾具類型,您可以將夾具類型以泛型形式傳遞。

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

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

test('types are defined correctly', ({ todos, archive }) => {
  expectTypeOf(todos).toEqualTypeOf<number[]>();
  expectTypeOf(archive).toEqualTypeOf<number[]>();
});

類型推論

請注意,Vitest 不支援在呼叫 use 函數時進行類型推論。當呼叫 test.extend 時,最好始終將整個上下文類型以泛型類型傳遞:

ts
import { test as baseTest } from 'vitest';

const test = baseTest.extend<{
  todos: number[];
  schema: string;
}>({
  todos: ({ schema }, use) => use([]),
  schema: 'test',
});

test('types are correct', ({
  todos, // number[]
  schema, // string
}) => {
  // ...
});

beforeEach 和 afterEach ​

已棄用

這是一種過時的擴展上下文方式,當 test 使用 test.extend 擴展時,它將不起作用。

每個測試的上下文都不同。您可以在 beforeEach 和 afterEach 鉤子中存取和擴展它們。

ts
import { beforeEach, it } from 'vitest';

beforeEach(async context => {
  // 擴展上下文
  context.foo = 'bar';
});

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

TypeScript ​

要為所有自訂上下文提供屬性類型,您可以透過添加以下內容來擴充 TestContext 類型:

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

如果您只想為特定的 beforeEach、afterEach、it 和 test 鉤子提供屬性類型,您可以將類型以泛型形式傳遞。

ts
interface LocalTestContext {
  foo: string;
}

beforeEach<LocalTestContext>(async context => {
  // context 的類型為 'TestContext & LocalTestContext'
  context.foo = 'bar';
});

it<LocalTestContext>('should work', ({ foo }) => {
  // foo 的類型為 'string'
  console.log(foo); // 'bar'
});
Pager
上一頁內聯測試
下一頁測試註解

以 MIT 授權條款 發布。

版權所有 (c) 2021-Present Vitest Team

https://vitest.dev/guide/test-context

以 MIT 授權條款 發布。

版權所有 (c) 2021-Present Vitest Team