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

與其他測試執行器的比較

本頁導覽

測試 API 參考 ​

以下類型在下面的類型簽名中被使用。

ts
type Awaitable<T> = T | PromiseLike<T>;
type TestFunction = () => Awaitable<void>;

interface TestOptions {
  /**
   * 若測試執行時間過長,該測試將會失敗。
   */
  timeout?: number;
  /**
   * 若測試失敗,將重試指定次數。
   *
   * @default 0
   */
  retry?: number;
  /**
   * 即使每次都失敗,也會重複執行相同的測試數次。
   * 若您設定了「retry」選項且測試失敗,它將在每個循環中使用所有重試次數。
   * 有助於偵錯隨機失敗的案例。
   *
   * @default 0
   */
  repeats?: number;
}

當測試函數回傳一個 Promise 時,執行器將等待其解析,以收集非同步斷言。若 Promise 被拒絕,該測試將會失敗。

TIP

在 Jest 中,TestFunction 亦可為 (done: DoneCallback) => void 類型。若使用此形式,測試將不會結束,直到 done 被呼叫。您可以使用 async 函數達到相同的效果,請參閱遷移指南的 Done Callback 部分。

您可以透過在函數上鏈式呼叫屬性來定義選項:

ts
import { test } from 'vitest';

test.skip('skipped test', () => {
  // some logic that fails right now
});

test.concurrent.skip('skipped concurrent test', () => {
  // some logic that fails right now
});

但您也可以提供一個物件作為第二個參數:

ts
import { test } from 'vitest';

test('skipped test', { skip: true }, () => {
  // some logic that fails right now
});

test('skipped concurrent test', { skip: true, concurrent: true }, () => {
  // some logic that fails right now
});

兩者的運作方式完全相同。使用哪一種純粹是風格上的選擇。

請注意,若您將逾時作為最後一個參數提供,則不能再使用選項物件:

ts
import { test } from 'vitest';

// ✅ 這可行
test.skip('heavy test', () => {
  // ...
}, 10_000);

// ❌ 這不可行
test(
  'heavy test',
  { skip: true },
  () => {
    // ...
  },
  10_000
);

然而,您可以在選項物件中提供逾時:

ts
import { test } from 'vitest';

// ✅ 這可行
test('heavy test', { skip: true, timeout: 10_000 }, () => {
  // ...
});

test ​

  • 別名: it

test 定義了一組相關的斷言。它接收測試名稱和一個包含要測試斷言的函數。

您可以選擇提供一個逾時(毫秒),用於指定在終止之前等待多長時間。預設為 5 秒,可透過 testTimeout 進行全域配置。

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

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

test.extend ​

  • 別名: it.extend

使用 test.extend 擴展測試上下文,加入自訂夾具(fixtures)。這將回傳一個新的 test 實例,且該實例亦可擴展,因此您可以根據需要組合更多夾具或覆蓋現有夾具。有關更多資訊,請參閱擴展測試上下文。

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

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

const myTest = test.extend({
  todos: async ({ task }, use) => {
    todos.push(1, 2, 3);
    await use(todos);
    todos.length = 0;
  },
  archive,
});

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

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

test.skip ​

  • 別名: it.skip

若您想跳過執行某些測試,但因任何原因不想刪除程式碼,您可以使用 test.skip 來避免執行它們。

ts
import { assert, test } from 'vitest';

test.skip('skipped test', () => {
  // 測試已跳過,無錯誤
  assert.equal(Math.sqrt(4), 3);
});

您也可以透過在測試的上下文上動態呼叫 skip 來跳過測試:

ts
import { assert, test } from 'vitest';

test('skipped test', context => {
  context.skip();
  // 測試已跳過,無錯誤
  assert.equal(Math.sqrt(4), 3);
});

自 Vitest 3.1 起,若條件未知,您可以將其作為第一個參數提供給 skip 方法:

ts
import { assert, test } from 'vitest';

test('skipped test', context => {
  context.skip(Math.random() < 0.5, 'optional message');
  // 測試已跳過,無錯誤
  assert.equal(Math.sqrt(4), 3);
});

test.skipIf ​

  • 別名: it.skipIf

在某些情況下,您可能會在不同的環境中多次執行測試,且某些測試可能是環境特定的。與其用 if 語句包裹測試程式碼,不如使用 test.skipIf 在條件為真時跳過測試。

ts
import { assert, test } from 'vitest';

const isDev = process.env.NODE_ENV === 'development';

test.skipIf(isDev)('prod only test', () => {
  // 此測試僅在生產環境中執行
});

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

test.runIf ​

  • 別名: it.runIf

與 test.skipIf 相反。

ts
import { assert, test } from 'vitest';

const isDev = process.env.NODE_ENV === 'development';

test.runIf(isDev)('dev only test', () => {
  // 此測試僅在開發環境中執行
});

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

test.only ​

  • 別名: it.only

使用 test.only 僅在給定套件中執行某些測試。這在偵錯時很有用。

您可以選擇提供一個逾時(毫秒),用於指定在終止之前等待多長時間。預設為 5 秒,可透過 testTimeout 進行全域配置。

ts
import { assert, test } from 'vitest';

test.only('test', () => {
  // 僅執行此測試(以及其他標記為 only 的測試)
  assert.equal(Math.sqrt(4), 2);
});

有時,在特定檔案中執行 only 測試,而忽略整個測試套件中的所有其他測試,這非常有用,因為它們會污染輸出。

為此,請執行包含相關測試的特定檔案的 vitest 命令。

# vitest interesting.test.ts

test.concurrent ​

  • 別名: it.concurrent

test.concurrent 標記連續測試以並行執行。它接收測試名稱、一個包含要收集測試的非同步函數,以及一個可選的逾時(毫秒)。

ts
import { describe, test } from 'vitest';

// 兩個標記為 concurrent 的測試將並行執行
describe('suite', () => {
  test('serial test', async () => {
    /* ... */
  });
  test.concurrent('concurrent test 1', async () => {
    /* ... */
  });
  test.concurrent('concurrent test 2', async () => {
    /* ... */
  });
});

test.skip、test.only 和 test.todo 適用於並行測試。以下所有組合都是有效的:

ts
test.concurrent(/* ... */);
test.skip.concurrent(/* ... */); // 或 test.concurrent.skip(/* ... */)
test.only.concurrent(/* ... */); // 或 test.concurrent.only(/* ... */)
test.todo.concurrent(/* ... */); // 或 test.concurrent.todo(/* ... */)

執行並行測試時,快照和斷言必須使用來自本地測試上下文的 expect,以確保偵測到正確的測試。

ts
test.concurrent('test 1', async ({ expect }) => {
  expect(foo).toMatchSnapshot();
});
test.concurrent('test 2', async ({ expect }) => {
  expect(foo).toMatchSnapshot();
});

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

test.sequential ​

  • 別名: it.sequential

test.sequential 將測試標記為循序執行。這在您希望在 describe.concurrent 內部或使用 --sequence.concurrent 命令選項時循序執行測試時很有用。

ts
import { describe, test } from 'vitest';

// 帶有配置選項 { sequence: { concurrent: true } }
test('concurrent test 1', async () => {
  /* ... */
});
test('concurrent test 2', async () => {
  /* ... */
});

test.sequential('sequential test 1', async () => {
  /* ... */
});
test.sequential('sequential test 2', async () => {
  /* ... */
});

// 在並行套件內
describe.concurrent('suite', () => {
  test('concurrent test 1', async () => {
    /* ... */
  });
  test('concurrent test 2', async () => {
    /* ... */
  });

  test.sequential('sequential test 1', async () => {
    /* ... */
  });
  test.sequential('sequential test 2', async () => {
    /* ... */
  });
});

test.todo ​

  • 別名: it.todo

使用 test.todo 來存根(stub)稍後要實現的測試。報告中將顯示這些測試的條目,以便您知道還有多少測試需要實現。

ts
// 報告中將顯示此測試的條目
test.todo('unimplemented test');

test.fails ​

  • 別名: it.fails

使用 test.fails 明確指示斷言將失敗。

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

function myAsyncFunc() {
  return new Promise(resolve => resolve(1));
}
test.fails('fail test', async () => {
  await expect(myAsyncFunc()).rejects.toBe(1);
});

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

test.each ​

  • 別名: it.each

TIP

雖然提供了 test.each 以與 Jest 相容, Vitest 也提供了 test.for,它具有整合 TestContext 的額外功能。

當您需要使用不同的變數執行相同的測試時,請使用 test.each。 您可以使用 printf 格式化在測試名稱中按照測試函數參數的順序注入參數。

  • %s:字串
  • %d:數字
  • %i:整數
  • %f:浮點值
  • %j:JSON
  • %o:物件
  • %#:測試案例的 0 基礎索引
  • %$:測試案例的 1 基礎索引
  • %%:單個百分號('%')
ts
import { expect, test } from 'vitest';

test.each([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
  expect(a + b).toBe(expected);
});

// 這將回傳
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3

您也可以使用 $ 前綴存取物件屬性和陣列元素:

ts
test.each([
  { a: 1, b: 1, expected: 2 },
  { a: 1, b: 2, expected: 3 },
  { a: 2, b: 1, expected: 3 },
])('add($a, $b) -> $expected', ({ a, b, expected }) => {
  expect(a + b).toBe(expected);
});

// 這將回傳
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3

test.each([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add($0, $1) -> $2', (a, b, expected) => {
  expect(a + b).toBe(expected);
});

// 這將回傳
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3

若您使用物件作為參數,您也可以使用 . 存取物件屬性:

ts
test.each`
  a             | b      | expected
  ${{ val: 1 }} | ${'b'} | ${'1b'}
  ${{ val: 2 }} | ${'b'} | ${'2b'}
  ${{ val: 3 }} | ${'b'} | ${'3b'}
`('add($a.val, $b) -> $expected', ({ a, b, expected }) => {
  expect(a.val + b).toBe(expected);
});

// 這將回傳
// ✓ add(1, b) -> 1b
// ✓ add(2, b) -> 2b
// ✓ add(3, b) -> 3b

從 Vitest 0.25.3 開始,您也可以使用模板字串表格。

  • 第一行應為欄位名稱,以 | 分隔;
  • 一或多個後續資料列以模板字面表達式 ${value} 語法提供。
ts
import { expect, test } from 'vitest';

test.each`
  a             | b      | expected
  ${1}          | ${1}   | ${2}
  ${'a'}        | ${'b'} | ${'ab'}
  ${[]}         | ${'b'} | ${'b'}
  ${{}}         | ${'b'} | ${'[object Object]b'}
  ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'}
`('returns $expected when $a is added $b', ({ a, b, expected }) => {
  expect(a + b).toBe(expected);
});

TIP

Vitest 使用 Chai 的 format 方法處理 $values。若值被截斷過多,您可以在配置檔中增加 chaiConfig.truncateThreshold。

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

test.for ​

  • 別名: it.for

test.each 的替代方案,用於提供 TestContext。

與 test.each 的區別在於參數中提供陣列的方式。 test.for 的非陣列參數(包括模板字串用法)與 test.each 的工作方式完全相同。

ts
// `each` 展開陣列
test.each([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => { 
  expect(a + b).toBe(expected);
});

// `for` 不展開陣列(注意參數周圍的方括號)
test.for([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', ([a, b, expected]) => { 
  expect(a + b).toBe(expected);
});

第二個參數是 TestContext,可用於並行快照,例如:

ts
test.concurrent.for([
  [1, 1],
  [1, 2],
  [2, 1],
])('add(%i, %i)', ([a, b], { expect }) => {
  expect(a + b).matchSnapshot();
});

bench ​

  • 類型: (name: string | Function, fn: BenchFunction, options?: BenchOptions) => void

bench 定義了一個基準測試。在 Vitest 中,基準測試是一個定義一系列操作的函數。Vitest 會多次執行此函數以顯示不同的效能結果。

Vitest 底層使用 tinybench 函式庫,繼承了所有可作為第三個參數使用的選項。

ts
import { bench } from 'vitest';

bench(
  'normal sorting',
  () => {
    const x = [1, 5, 4, 2, 3];
    x.sort((a, b) => {
      return a - b;
    });
  },
  { time: 1000 }
);
ts
export interface Options {
  /**
   * 執行基準測試任務所需時間(毫秒)
   * @default 500
   */
  time?: number;

  /**
   * 即使時間選項已完成,任務也應執行的次數
   * @default 10
   */
  iterations?: number;

  /**
   * 取得目前時間戳記(毫秒)的函數
   */
  now?: () => number;

  /**
   * 用於中止基準測試的 AbortSignal
   */
  signal?: AbortSignal;

  /**
   * 若任務失敗則拋出(若為 true,事件將不起作用)
   */
  throws?: boolean;

  /**
   * 暖身時間(毫秒)
   * @default 100ms
   */
  warmupTime?: number;

  /**
   * 暖身迭代次數
   * @default 5
   */
  warmupIterations?: number;

  /**
   * 在每個基準測試任務(循環)之前執行的設定函數
   */
  setup?: Hook;

  /**
   * 在每個基準測試任務(循環)之後執行的拆卸函數
   */
  teardown?: Hook;
}

測試案例執行後,輸出結構資訊如下:

  name                      hz     min     max    mean     p75     p99    p995    p999     rme  samples
· normal sorting  6,526,368.12  0.0001  0.3638  0.0002  0.0002  0.0002  0.0002  0.0004  ±1.41%   652638
ts
export interface TaskResult {
  /*
   * 執行任務時拋出的最後一個錯誤
   */
  error?: unknown;

  /**
   * 執行基準測試任務(循環)所需的總時間(毫秒)。
   */
  totalTime: number;

  /**
   * 樣本中的最小值
   */
  min: number;
  /**
   * 樣本中的最大值
   */
  max: number;

  /**
   * 每秒操作數
   */
  hz: number;

  /**
   * 每個操作所需時間(毫秒)
   */
  period: number;

  /**
   * 每個任務迭代時間的任務樣本(毫秒)
   */
  samples: number[];

  /**
   * 樣本平均值/平均數(總體平均值的估計)
   */
  mean: number;

  /**
   * 樣本變異數(總體變異數的估計)
   */
  variance: number;

  /**
   * 樣本標準差(總體標準差的估計)
   */
  sd: number;

  /**
   * 平均值的標準誤差(又稱樣本平均值抽樣分佈的標準差)
   */
  sem: number;

  /**
   * 自由度
   */
  df: number;

  /**
   * 樣本的臨界值
   */
  critical: number;

  /**
   * 誤差範圍
   */
  moe: number;

  /**
   * 相對誤差範圍
   */
  rme: number;

  /**
   * 中位數絕對偏差
   */
  mad: number;

  /**
   * p50/中位數百分位數
   */
  p50: number;

  /**
   * p75 百分位數
   */
  p75: number;

  /**
   * p99 百分位數
   */
  p99: number;

  /**
   * p995 百分位數
   */
  p995: number;

  /**
   * p999 百分位數
   */
  p999: number;
}

bench.skip ​

  • 類型: (name: string | Function, fn: BenchFunction, options?: BenchOptions) => void

您可以使用 bench.skip 語法來跳過執行某些基準測試。

ts
import { bench } from 'vitest';

bench.skip('normal sorting', () => {
  const x = [1, 5, 4, 2, 3];
  x.sort((a, b) => {
    return a - b;
  });
});

bench.only ​

  • 類型: (name: string | Function, fn: BenchFunction, options?: BenchOptions) => void

使用 bench.only 僅在給定套件中執行某些基準測試。這在偵錯時很有用。

ts
import { bench } from 'vitest';

bench.only('normal sorting', () => {
  const x = [1, 5, 4, 2, 3];
  x.sort((a, b) => {
    return a - b;
  });
});

bench.todo ​

  • 類型: (name: string | Function) => void

使用 bench.todo 來存根(stub)稍後要實現的基準測試。

ts
import { bench } from 'vitest';

bench.todo('unimplemented test');

describe ​

當您在檔案的頂層使用 test 或 bench 時,它們會被收集為其隱式套件的一部分。使用 describe,您可以在目前上下文中定義一個新套件,作為一組相關的測試或基準測試以及其他巢狀套件。套件可讓您組織測試和基準測試,使報告更清晰。

ts
// basic.spec.ts
// 組織測試

import { describe, expect, test } from 'vitest';

const person = {
  isActive: true,
  age: 32,
};

describe('person', () => {
  test('person is defined', () => {
    expect(person).toBeDefined();
  });

  test('is active', () => {
    expect(person.isActive).toBeTruthy();
  });

  test('age limit', () => {
    expect(person.age).toBeLessThanOrEqual(32);
  });
});
ts
// basic.bench.ts
// 組織基準測試

import { bench, describe } from 'vitest';

describe('sort', () => {
  bench('normal', () => {
    const x = [1, 5, 4, 2, 3];
    x.sort((a, b) => {
      return a - b;
    });
  });

  bench('reverse', () => {
    const x = [1, 5, 4, 2, 3];
    x.reverse().sort((a, b) => {
      return a - b;
    });
  });
});

若您有測試或基準測試的層次結構,您也可以巢狀 describe 區塊:

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

function numberToCurrency(value: number | string) {
  if (typeof value !== 'number') {
    throw new TypeError('Value must be a number');
  }

  return value
    .toFixed(2)
    .toString()
    .replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

describe('numberToCurrency', () => {
  describe('given an invalid number', () => {
    test('composed of non-numbers to throw error', () => {
      expect(() => numberToCurrency('abc')).toThrowError();
    });
  });

  describe('given a valid number', () => {
    test('returns the correct currency format', () => {
      expect(numberToCurrency(10000)).toBe('10,000.00');
    });
  });
});

describe.skip ​

  • 別名: suite.skip

在套件中使用 describe.skip 以避免執行特定的 describe 區塊。

ts
import { assert, describe, test } from 'vitest';

describe.skip('skipped suite', () => {
  test('sqrt', () => {
    // 套件已跳過,無錯誤
    assert.equal(Math.sqrt(4), 3);
  });
});

describe.skipIf ​

  • 別名: suite.skipIf

在某些情況下,您可能會在不同的環境中多次執行套件,且某些套件可能是環境特定的。與其用 if 語句包裹套件,不如使用 describe.skipIf 在條件為真時跳過套件。

ts
import { describe, test } from 'vitest';

const isDev = process.env.NODE_ENV === 'development';

describe.skipIf(isDev)('prod only test suite', () => {
  // 此測試套件僅在生產環境中執行
});

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

describe.runIf ​

  • 別名: suite.runIf

與 describe.skipIf 相反。

ts
import { assert, describe, test } from 'vitest';

const isDev = process.env.NODE_ENV === 'development';

describe.runIf(isDev)('dev only test suite', () => {
  // 此測試套件僅在開發環境中執行
});

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

describe.only ​

  • 類型: (name: string | Function, fn: TestFunction, options?: number | TestOptions) => void

使用 describe.only 僅執行某些套件。

ts
import { assert, describe, test } from 'vitest';

// 僅執行此套件(以及其他標記為 only 的套件)
describe.only('suite', () => {
  test('sqrt', () => {
    assert.equal(Math.sqrt(4), 3);
  });
});

describe('other suite', () => {
  // ... 將被跳過
});

有時,在特定檔案中執行 only 測試,而忽略整個測試套件中的所有其他測試,這非常有用,因為它們會污染輸出。

為此,請執行包含相關測試的特定檔案的 vitest 命令。

# vitest interesting.test.ts

describe.concurrent ​

  • 別名: suite.concurrent

describe.concurrent 並行執行所有內部套件和測試。

ts
import { describe, test } from 'vitest';

// 此套件中的所有套件和測試都將並行執行
describe.concurrent('suite', () => {
  test('concurrent test 1', async () => {
    /* ... */
  });
  describe('concurrent suite 2', async () => {
    test('concurrent test inner 1', async () => {
      /* ... */
    });
    test('concurrent test inner 2', async () => {
      /* ... */
    });
  });
  test.concurrent('concurrent test 3', async () => {
    /* ... */
  });
});

.skip、.only 和 .todo 適用於並行套件。以下所有組合都是有效的:

ts
describe.concurrent(/* ... */);
describe.skip.concurrent(/* ... */); // 或 describe.concurrent.skip(/* ... */)
describe.only.concurrent(/* ... */); // 或 describe.concurrent.only(/* ... */)
describe.todo.concurrent(/* ... */); // 或 describe.concurrent.todo(/* ... */)

執行並行測試時,快照和斷言必須使用來自本地測試上下文的 expect,以確保偵測到正確的測試。

ts
describe.concurrent('suite', () => {
  test('concurrent test 1', async ({ expect }) => {
    expect(foo).toMatchSnapshot();
  });
  test('concurrent test 2', async ({ expect }) => {
    expect(foo).toMatchSnapshot();
  });
});

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

describe.sequential ​

  • 別名: suite.sequential

套件中的 describe.sequential 將每個測試標記為循序執行。這在您希望在 describe.concurrent 內部或使用 --sequence.concurrent 命令選項時循序執行測試時很有用。

ts
import { describe, test } from 'vitest';

describe.concurrent('suite', () => {
  test('concurrent test 1', async () => {
    /* ... */
  });
  test('concurrent test 2', async () => {
    /* ... */
  });

  describe.sequential('', () => {
    test('sequential test 1', async () => {
      /* ... */
    });
    test('sequential test 2', async () => {
      /* ... */
    });
  });
});

describe.shuffle ​

  • 別名: suite.shuffle

Vitest 提供了透過 CLI 旗標 --sequence.shuffle 或配置選項 sequence.shuffle 以隨機順序執行所有測試的方式,但若您只想讓測試套件的一部分以隨機順序執行測試,您可以用此旗標標記它。

ts
import { describe, test } from 'vitest';

// 或 describe('suite', { shuffle: true }, ...)
describe.shuffle('suite', () => {
  test('random test 1', async () => {
    /* ... */
  });
  test('random test 2', async () => {
    /* ... */
  });
  test('random test 3', async () => {
    /* ... */
  });

  // `shuffle` 是繼承的
  describe('still random', () => {
    test('random 4.1', async () => {
      /* ... */
    });
    test('random 4.2', async () => {
      /* ... */
    });
  });

  // 內部停用 shuffle
  describe('not random', { shuffle: false }, () => {
    test('in order 5.1', async () => {
      /* ... */
    });
    test('in order 5.2', async () => {
      /* ... */
    });
  });
});
// 順序取決於配置中的 sequence.seed 選項(預設為 Date.now())

.skip、.only 和 .todo 適用於隨機套件。

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

describe.todo ​

  • 別名: suite.todo

使用 describe.todo 來存根(stub)稍後要實現的套件。報告中將顯示這些測試的條目,以便您知道還有多少測試需要實現。

ts
// 報告中將顯示此套件的條目
describe.todo('unimplemented suite');

describe.each ​

  • 別名: suite.each

TIP

雖然提供了 describe.each 以與 Jest 相容, Vitest 也提供了 describe.for,它簡化了參數類型並與 test.for 對齊。

若您有多個測試依賴於相同的資料,請使用 describe.each。

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

describe.each([
  { a: 1, b: 1, expected: 2 },
  { a: 1, b: 2, expected: 3 },
  { a: 2, b: 1, expected: 3 },
])('describe object add($a, $b)', ({ a, b, expected }) => {
  test(`returns ${expected}`, () => {
    expect(a + b).toBe(expected);
  });

  test(`returned value not be greater than ${expected}`, () => {
    expect(a + b).not.toBeGreaterThan(expected);
  });

  test(`returned value not be less than ${expected}`, () => {
    expect(a + b).not.toBeLessThan(expected);
  });
});

從 Vitest 0.25.3 開始,您也可以使用模板字串表格。

  • 第一行應為欄位名稱,以 | 分隔;
  • 一或多個後續資料列以模板字面表達式 ${value} 語法提供。
ts
import { describe, expect, test } from 'vitest';

describe.each`
  a             | b      | expected
  ${1}          | ${1}   | ${2}
  ${'a'}        | ${'b'} | ${'ab'}
  ${[]}         | ${'b'} | ${'b'}
  ${{}}         | ${'b'} | ${'[object Object]b'}
  ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'}
`('describe template string add($a, $b)', ({ a, b, expected }) => {
  test(`returns ${expected}`, () => {
    expect(a + b).toBe(expected);
  });
});

WARNING

當您使用 Vitest 作為類型檢查器時,您不能使用此語法。

describe.for ​

  • 別名: suite.for

與 describe.each 的區別在於參數中提供陣列案例的方式。 其他非陣列案例(包括模板字串用法)的工作方式完全相同。

ts
// `each` 展開陣列案例
describe.each([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => { 
  test('test', () => {
    expect(a + b).toBe(expected);
  });
});

// `for` 不展開陣列案例
describe.for([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', ([a, b, expected]) => { 
  test('test', () => {
    expect(a + b).toBe(expected);
  });
});

設定與拆卸 ​

這些函數可讓您掛接到測試的生命週期中,以避免重複設定和拆卸程式碼。它們適用於目前上下文:若它們在頂層使用,則為檔案;若它們在 describe 區塊內,則為目前套件。當您將 Vitest 作為類型檢查器執行時,不會呼叫這些掛鉤。

beforeEach ​

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

註冊一個回呼函數,該函數將在目前上下文中的每個測試執行之前被呼叫。 若函數回傳一個 Promise,Vitest 將等待 Promise 解析後再執行測試。

您可以選擇傳遞一個逾時(毫秒),定義在終止之前等待多長時間。預設為 5 秒。

ts
import { beforeEach } from 'vitest';

beforeEach(async () => {
  // 在每次測試執行前清除模擬並添加一些測試資料
  await stopMocking();
  await addUser({ name: 'John' });
});

在這裡,beforeEach 確保在每次測試之前都添加了使用者。

beforeEach 也接受一個可選的清理函數(等同於 afterEach)。

ts
import { beforeEach } from 'vitest';

beforeEach(async () => {
  // 在每次測試執行前呼叫一次
  await prepareSomething();

  // 清理函數,在每次測試執行後呼叫一次
  return async () => {
    await resetSomething();
  };
});

afterEach ​

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

註冊一個回呼函數,該函數將在目前上下文中的每個測試完成後被呼叫。 若函數回傳一個 Promise,Vitest 將等待 Promise 解析後再繼續。

您可以選擇提供一個逾時(毫秒),用於指定在終止之前等待多長時間。預設為 5 秒。

ts
import { afterEach } from 'vitest';

afterEach(async () => {
  await clearTestingData(); // 在每次測試執行後清除測試資料
});

在這裡,afterEach 確保在每次測試執行後清除測試資料。

TIP

Vitest 1.3.0 新增了 onTestFinished 鉤子。您可以在測試執行期間呼叫它,以便在測試完成執行後清理任何狀態。

beforeAll ​

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

註冊一個回呼函數,該函數將在開始執行目前上下文中的所有測試之前被呼叫一次。 若函數回傳一個 Promise,Vitest 將等待 Promise 解析後再執行測試。

您可以選擇提供一個逾時(毫秒),用於指定在終止之前等待多長時間。預設為 5 秒。

ts
import { beforeAll } from 'vitest';

beforeAll(async () => {
  await startMocking(); // 在所有測試執行前呼叫一次
});

在這裡,beforeAll 確保在測試執行前設定模擬資料。

beforeAll 也接受一個可選的清理函數(等同於 afterAll)。

ts
import { beforeAll } from 'vitest';

beforeAll(async () => {
  // 在所有測試執行前呼叫一次
  await startMocking();

  // 清理函數,在所有測試執行後呼叫一次
  return async () => {
    await stopMocking();
  };
});

afterAll ​

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

註冊一個回呼函數,該函數將在目前上下文中的所有測試執行完畢後被呼叫一次。 若函數回傳一個 Promise,Vitest 將等待 Promise 解析後再繼續。

您可以選擇提供一個逾時(毫秒),用於指定在終止之前等待多長時間。預設為 5 秒。

ts
import { afterAll } from 'vitest';

afterAll(async () => {
  await stopMocking(); // 此方法在所有測試執行後呼叫
});

在這裡,afterAll 確保在所有測試執行後呼叫 stopMocking 方法。

測試掛鉤 ​

Vitest 提供了一些掛鉤,您可以在測試執行_期間_呼叫它們,以便在測試完成執行後清理狀態。

WARNING

若在測試主體之外呼叫這些掛鉤,它們將拋出錯誤。

onTestFinished ​

此掛鉤總是在測試完成執行後呼叫。它在 afterEach 掛鉤之後呼叫,因為它們可能會影響測試結果。它接收一個 ExtendedContext 物件,就像 beforeEach 和 afterEach 一樣。

ts
import { onTestFinished, test } from 'vitest';

test('performs a query', () => {
  const db = connectDb();
  onTestFinished(() => db.close());
  db.query('SELECT * FROM users');
});

WARNING

若您正在並行執行測試,您應該始終使用測試上下文中的 onTestFinished 掛鉤,因為 Vitest 不會在全域掛鉤中追蹤並行測試:

ts
import { test } from 'vitest';

test.concurrent('performs a query', ({ onTestFinished }) => {
  const db = connectDb();
  onTestFinished(() => db.close());
  db.query('SELECT * FROM users');
});

此掛鉤在建立可重用邏輯時特別有用:

ts
// 這可以在單獨的檔案中
function getTestDb() {
  const db = connectMockedDb();
  onTestFinished(() => db.close());
  return db;
}

test('performs a user query', async () => {
  const db = getTestDb();
  expect(await db.query('SELECT * from users').perform()).toEqual([]);
});

test('performs an organization query', async () => {
  const db = getTestDb();
  expect(await db.query('SELECT * from organizations').perform()).toEqual([]);
});

TIP

此掛鉤始終以相反順序呼叫,且不受 sequence.hooks 選項的影響。

onTestFailed ​

此掛鉤僅在測試失敗後呼叫。它在 afterEach 掛鉤之後呼叫,因為它們可能會影響測試結果。它接收一個 ExtendedContext 物件,就像 beforeEach 和 afterEach 一樣。此掛鉤對於偵錯很有用。

ts
import { onTestFailed, test } from 'vitest';

test('performs a query', () => {
  const db = connectDb();
  onTestFailed(({ task }) => {
    console.log(task.result.errors);
  });
  db.query('SELECT * FROM users');
});

WARNING

若您正在並行執行測試,您應該始終使用測試上下文中的 onTestFailed 掛鉤,因為 Vitest 不會在全域掛鉤中追蹤並行測試:

ts
import { test } from 'vitest';

test.concurrent('performs a query', ({ onTestFailed }) => {
  const db = connectDb();
  onTestFailed(({ task }) => {
    console.log(task.result.errors);
  });
  db.query('SELECT * FROM users');
});
Pager
上一頁配置參考
下一頁模擬函式

以 MIT 授權條款 發布。

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

https://vitest.dev/api/

以 MIT 授權條款 發布。

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