功能特性
- Vite 的配置、轉換器、解析器和插件。
- 使用與您的應用程式相同的設定來執行測試!
- 智慧且即時的監視模式,如同 HMR 在測試中的運作方式!
- 適用於 Vue、React、Svelte、Lit 等的元件測試
- 開箱即用的 TypeScript / JSX 支援
- 優先使用 ESM,頂層 await
- 透過 Tinypool 實現多線程的 Workers
- 透過 Tinybench 支持基準測試
- 為套件和測試提供篩選、超時、並行設定
- 工作區(Workspace) 支持
- 與 Jest 相容的快照支持
- 內建 Chai 以進行斷言 + 相容於 Jest expect 的 API
- 內建 Tinyspy 用於模擬
- 使用 happy-dom 或 jsdom 進行 DOM 模擬
- 透過 v8 或 istanbul 進行程式碼覆蓋率
- 類似 Rust 的 原始碼內測試
- 透過 expect-type 進行類型測試
在測試、開發和建置之間共享配置
使用 Vite 的配置、轉換器、解析器和插件,以與您的應用程式相同的設定來執行測試。
請參閱 配置 Vitest 以了解更多資訊。
監視模式
$ vitest
當您修改原始碼或測試檔案時,Vitest 會智慧地搜尋模組依賴圖,並僅重新執行相關的測試,如同 Vite 中的 HMR 運作方式!
vitest
預設在開發環境中以 監視模式
啟動,在 CI 環境(當 process.env.CI
存在時)則以 執行模式(run mode)
啟動。您可以使用 vitest watch
或 vitest run
明確指定所需的模式。
開箱即用的常見 Web 習慣用語
開箱即用的 ES Module / TypeScript / JSX 支持 / PostCSS
線程
透過 Tinypool(Piscina 的輕量級分支)實現多線程的 Workers,使測試能夠並行執行。線程在 Vitest 中預設為啟用,可以透過在 CLI 中傳遞 --no-threads
來停用。
Vitest 還會隔離每個檔案的環境,因此一個檔案中的環境變更不會影響其他檔案。可以透過將 --no-isolate
傳遞給 CLI 來停用隔離功能(以執行效能換取正確性)。
測試篩選
Vitest 提供了多種方法來縮小要執行的測試範圍,以加速測試,讓您可以專注於開發。
請參閱 測試篩選 以了解更多資訊。
同時執行測試
在連續的測試中使用 .concurrent
,以並行方式執行。
import { describe, it } from 'vitest';
// 標記為 concurrent 的兩個測試將並行執行
describe('suite', () => {
it('serial test', async () => {
/* ... */
});
it.concurrent('concurrent test 1', async ({ expect }) => {
/* ... */
});
it.concurrent('concurrent test 2', async ({ expect }) => {
/* ... */
});
});
如果您在一個測試套件上使用 .concurrent
,則該套件中的每個測試都將並行執行。
import { describe, it } from 'vitest';
// 此套件中的所有測試都將並行執行
describe.concurrent('suite', () => {
it('concurrent test 1', async ({ expect }) => {
/* ... */
});
it('concurrent test 2', async ({ expect }) => {
/* ... */
});
it.concurrent('concurrent test 3', async ({ expect }) => {
/* ... */
});
});
您也可以將 .skip
、.only
和 .todo
與並行的套件和測試一起使用。請參閱 API 參考 以了解更多資訊。
WARNING
執行並行測試時,快照和斷言必須使用來自本地 測試上下文 的 expect
,以確保能正確偵測到測試。
快照
與 Jest 相容 的快照支持。
import { expect, it } from 'vitest';
it('renders correctly', () => {
const result = render();
expect(result).toMatchSnapshot();
});
請參閱 快照 以了解更多資訊。
Chai 和 Jest expect
相容性
內建 Chai 斷言庫,並提供與 Jest expect
相容的 API。
請注意,如果您正在使用會新增匹配器(matcher)的第三方函式庫,將 test.globals
設定為 true
將能提供更好的相容性。
模擬
內建 Tinyspy 模擬庫,並提供與 jest
相容的 API,可在 vi
物件上使用。
import { expect, vi } from 'vitest';
const fn = vi.fn();
fn('hello', 1);
expect(vi.isMockFunction(fn)).toBe(true);
expect(fn.mock.calls[0]).toEqual(['hello', 1]);
fn.mockImplementation(arg => arg);
fn('world', 2);
expect(fn.mock.results[1].value).toBe('world');
Vitest 支持 happy-dom 或 jsdom 來模擬 DOM 和瀏覽器 API。它們不包含在 Vitest 中,您可能需要安裝。
$ npm i -D happy-dom
# or
$ npm i -D jsdom
接著,變更設定檔中的 environment
選項:
// vite.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'happy-dom', // or 'jsdom', 'node'
},
});
請參閱 模擬 以了解更多資訊。
覆蓋率
Vitest 支援透過 v8
進行原生程式碼覆蓋率分析,以及透過 istanbul
進行檢測程式碼覆蓋率分析。
{
"scripts": {
"test": "vitest",
"coverage": "vitest run --coverage"
}
}
請參閱 覆蓋率 以了解更多資訊。
原始碼內測試
Vitest 還提供了一種在原始碼中與實作程式碼一起執行測試的方法,類似於 Rust 的模組測試。
這使得測試與實作程式碼共享相同的閉包,並且能夠針對私有狀態進行測試,而無需匯出。
同時,它也為開發帶來更緊密的迴圈反饋。
// src/index.ts
// the implementation
export function add(...args: number[]) {
return args.reduce((a, b) => a + b, 0);
}
// in-source test suites
if (import.meta.vitest) {
const { it, expect } = import.meta.vitest;
it('add', () => {
expect(add()).toBe(0);
expect(add(1)).toBe(1);
expect(add(1, 2, 3)).toBe(6);
});
}
請參閱 原始碼內測試 以了解更多資訊。
基準測試 experimental(實驗性)
從 Vitest 0.23.0 開始,您可以使用 bench
函式,透過 Tinybench 執行基準測試,以比較效能結果。
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;
});
});
});
類型測試 experimental(實驗性)
從 Vitest 0.25.0 開始,您可以編寫測試來捕獲類型退化(type regressions)。Vitest 附帶 expect-type
套件,為您提供類似且易於理解的 API。
import { assertType, expectTypeOf } from 'vitest';
import { mount } from './mount.js';
test('my types work properly', () => {
expectTypeOf(mount).toBeFunction();
expectTypeOf(mount).parameter(0).toMatchTypeOf<{ name: string }>();
// @ts-expect-error 預期 name 為字串
assertType(mount({ name: 42 }));
});