Skip to content
Vitest 2
Main Navigation 指南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

測試 API 參考文件

模擬函數

Vi

expect

expectTypeOf

assert

assertType

本頁導覽

測試 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
});
ts
import { test } from 'vitest';

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

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 並且也是可擴展的,因此您可以根據需要通過擴展它來組合更多 fixtures 或覆蓋現有的 fixtures。有關更多資訊,請參閱 擴展測試上下文。

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', () => {
  // Test skipped, no error
  assert.equal(Math.sqrt(4), 3);
});

您還可以通過在其 context 上動態調用 skip 來跳過測試:

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

test('skipped test', context => {
  context.skip();
  // Test skipped, no error
  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', () => {
  // this test only runs in production
});

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', () => {
  // this test only runs in development
});

WARNING

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

test.only ​

  • 別名: it.only

使用 test.only 僅運行給定套件中的某些測試。這在調試時很有用。

您可以選擇性地提供一個超時時間(以毫秒為單位),以指定在終止之前等待的時間。預設值為 5 秒,可以使用 testTimeout 進行全域設定。

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

test.only('test', () => {
  // Only this test (and others marked with only) are run
  assert.equal(Math.sqrt(4), 2);
});

有時,僅運行特定文件中的 only 測試非常有用,藉此忽略來自整個測試套件的所有其他測試,避免這些測試影響輸出結果。

為了做到這一點,請使用包含相關測試的特定文件運行 vitest。

# vitest interesting.test.ts

test.concurrent ​

  • 別名: it.concurrent

test.concurrent 標記連續的測試以並行運行。它接收測試名稱、一個包含要收集的測試的異步函數和一個可選的超時時間(以毫秒為單位)。

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

// The two tests marked with concurrent will be run in parallel
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(/* ... */); // or test.concurrent.skip(/* ... */)
test.only.concurrent(/* ... */); // or test.concurrent.only(/* ... */)
test.todo.concurrent(/* ... */); // or 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 來建立稍後要實現的測試樁。報告中將顯示測試的項目,以便您知道還需要實現多少測試。

ts
// An entry will be shown in the report for this test
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: 物件
  • %#: 測試案例的索引
  • %%: 單個百分號 ('%')
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

如果您使用物件作為參數,您也可以使用 . 訪問物件屬性:

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 的區別在於陣列情況在參數中的提供方式。 其他非陣列情況(包括模板字串用法)工作方式完全相同。

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 定義一個基準測試程式(benchmark)。在 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;

  /**
   * 即使 time 選項已完成,任務也應運行的次數
   * @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 來建立稍後要實現的基準測試樁。

ts
import { bench } from 'vitest';

bench.todo('unimplemented test');

describe ​

當你在檔案的最上層使用 test 或 bench 時,它們會被收集為該檔案隱含的測試套件(suite)的一部分。使用 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 ​

  • Alias: 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 ​

  • Alias: suite.skipIf

在某些情況下,你可能會在不同環境中多次運行測試套件,並且某些測試套件可能是環境專屬的。你可以使用 describe.skipIf 來跳過測試套件,只要條件為真值,而不需要用 if 包裹測試套件。

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

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

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

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', () => {
  // this test suite only runs in development
});

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 ​

  • Alias: 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(/* ... */); // or describe.concurrent.skip(/* ... */)
describe.only.concurrent(/* ... */); // or describe.concurrent.only(/* ... */)
describe.todo.concurrent(/* ... */); // or describe.concurrent.todo(/* ... */)

當執行並行測試時,快照(Snapshots)和斷言(Assertions)必須使用來自本地測試環境的 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 ​

  • Alias: suite.sequential

describe.sequential 會將測試套件中的每個測試標記為循序(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 ​

  • Alias: suite.shuffle

Vitest 提供了一種通過 CLI 標誌 --sequence.shuffle 或配置選項 sequence.shuffle 以隨機順序執行所有測試的方法,但如果你只想讓部分測試套件以隨機順序執行,可以使用此標記。

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

describe.shuffle('suite', () => {
  test('random test 1', async () => {
    /* ... */
  });
  test('random test 2', async () => {
    /* ... */
  });
  test('random test 3', async () => {
    /* ... */
  });
});
// 順序取決於配置中的 sequence.seed 選項(預設為 Date.now())

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

WARNING

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

describe.todo ​

  • Alias: suite.todo

使用 describe.todo 來預留稍後要實作的測試套件。報告中會顯示測試項目,方便你了解尚有多少測試需要實作。

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

describe.each ​

  • Alias: suite.each

如果你有多個測試依賴於相同的數據,請使用 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 作為類型檢查器時,你不能使用此語法。

設定與拆卸 (Setup and Teardown) ​

這些函式允許你鉤入測試的生命週期,以避免重複設定和拆卸程式碼。它們適用於目前的上下文:如果在最上層使用它們,則適用於檔案;如果在 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 hook。您可以在測試執行期間呼叫它,以便在測試執行結束後清除任何狀態。

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 鉤子之後呼叫,因為它們可能會影響測試結果。 它接收一個 TaskResult 物件,其中包含目前的測試結果。

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

test('執行查詢', () => {
  const db = connectDb();
  onTestFinished(() => db.close());
  db.query('SELECT * FROM users');
});

WARNING

如果正在並發執行測試,則應始終使用測試內容中的 onTestFinished 鉤子,因為 Vitest 不會在全域鉤子中追蹤並發測試:

ts
import { test } from 'vitest';

test.concurrent('執行查詢', ({ onTestFinished }) => {
  const db = connectDb();
  onTestFinished(() => db.close());
  db.query('SELECT * FROM users');
});

此鉤子在建立可重複使用邏輯時特別有用:

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

test('執行使用者查詢', async () => {
  const db = getTestDb();
  expect(await db.query('SELECT * from users').perform()).toEqual([]);
});

test('執行組織查詢', async () => {
  const db = getTestDb();
  expect(await db.query('SELECT * from organizations').perform()).toEqual([]);
});

TIP

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

onTestFailed ​

此鉤子僅在測試失敗後呼叫。 它在 afterEach 鉤子之後呼叫,因為它們可能會影響測試結果。 它接收一個 TaskResult 物件,其中包含目前的測試結果。 此鉤子對於偵錯很有用。

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

test('執行查詢', () => {
  const db = connectDb();
  onTestFailed(e => {
    console.log(e.result.errors);
  });
  db.query('SELECT * FROM users');
});

WARNING

如果正在並發執行測試,則應始終使用測試內容中的 onTestFailed 鉤子,因為 Vitest 不會在全域鉤子中追蹤並發測試:

ts
import { test from 'vitest'

test.concurrent('執行查詢', ({ onTestFailed }) => {
  const db = connectDb()
  onTestFailed((result) => {
    console.log(result.errors)
  })
  db.query('SELECT * FROM users')
})
Pager
下一頁模擬函數

以 MIT 授權條款 發布。

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

https://v2.vitest.dev/api/

以 MIT 授權條款 發布。

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