機能
- Vite の設定、トランスフォーマー、リゾルバー、プラグインを継承
- アプリケーションと同じ設定でテストを実行可能
- テスト用のHMRのような、スマートで即時性の高いウォッチモード
- Vue、React、Svelte、Lit、Marko などのコンポーネントテストに対応
- TypeScript / JSX のサポートをすぐに利用可能
- ESM ファースト、トップレベル await に対応
- Tinypool によるワーカーマルチスレッド実行
- Tinybench によるベンチマークサポート
- スイートとテストのフィルタリング、タイムアウト設定、並行実行
- プロジェクトのサポート
- Jest 互換のスナップショット機能
- アサーション用に Chai を内蔵 + Jest expect 互換 API
- モックのための Tinyspy を内蔵
- DOM モックのための happy-dom または jsdom に対応
- ブラウザでコンポーネントテストを実行するためのブラウザモード
- v8 または istanbul によるコードカバレッジ
- Rust ライクなインソーステスト
- expect-type による型テスト
- シャーディングのサポート
- 未捕捉エラーの報告
テスト、開発、ビルド間の共有設定
Vite の設定、トランスフォーマー、リゾルバー、プラグインを共有し、アプリケーションと同じセットアップでテストを実行できます。
詳細については、Vitest の設定を参照してください。
ウォッチモード
$ vitest
ソースコードやテストファイルを変更すると、Vitest はモジュールグラフをスマートに検索し、関連するテストのみを再実行します。これは Vite の HMR と同様に機能します。
vitest
は、開発環境ではデフォルトで watch mode
で起動し、CI 環境 ( process.env.CI
が存在する場合) では自動的に run mode
で起動します。vitest watch
または vitest run
を使用して、目的のモードを明示的に指定できます。
--standalone
フラグを付けて Vitest を起動すると、バックグラウンドで実行され続けます。テストが変更されるまで実行されません。ソースコードが変更されても、そのソースをインポートするテストが実行されるまで、Vitest はテストを実行しません。
一般的な Web イディオムをすぐに利用可能
ES Module / TypeScript / JSX サポート / PostCSS をすぐに利用可能です。
スレッド
デフォルトでは、Vitest は Tinypool (Piscina の軽量フォーク) を介して node:child_process
を使用し、複数のプロセスでテストファイルを実行することで、テストを同時に実行できるようにします。テストスイートをさらに高速化したい場合は、node:worker_threads
を使用してテストを実行するために --pool=threads
を有効にすることを検討してください (この設定では一部のパッケージが動作しない可能性があることに注意してください)。
単一のスレッドまたはプロセスでテストを実行するには、poolOptions
を参照してください。
Vitest はまた、各ファイルの環境を分離するため、あるファイルでの環境の変更が他のファイルに影響を与えません。分離は、CLI に --no-isolate
を渡すことで無効にできます(正確性を犠牲にして実行パフォーマンスを向上させます)。
テストフィルタリング
Vitest は、テストの実行を絞り込むための多くの方法を提供し、テストを高速化して開発に集中できるようにします。
詳細については、テストフィルタリングを参照してください。
テストの並行実行
連続するテストで .concurrent
を使用すると、並行して実行されます。
import { describe, it } from 'vitest';
// concurrent とマークされた 2 つのテストは並行して開始されます
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
も concurrent スイートとテストで使用できます。詳細については、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 を使用したアサーションのために組み込まれています。
サードパーティライブラリがマッチャーを追加している場合、test.globals
を true
に設定すると、より良い互換性が得られることに注意してください。
モック
Tinyspy は、vi
オブジェクト上の jest
互換 API を使用したモックのために組み込まれています。
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: string) => arg);
fn('world', 2);
expect(fn.mock.results[1].value).toBe('world');
Vitest は、DOM やブラウザ API のモックに、happy-dom または jsdom の両方をサポートしています。これらはVitestに同梱されていないため、別途インストールが必要です。
$ npm i -D happy-dom
$ npm i -D jsdom
その後、設定ファイルの environment
オプションを変更します。
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 のモジュールテストと同様に、実装とともにソースコード内でテストを実行する方法も提供します。
これにより、テストは実装と同じスコープを共有し、エクスポートせずにプライベートな状態をテストできます。同時に、開発のためのフィードバックループも高速化されます。
// 実装
export function add(...args: number[]): number {
return args.reduce((a, b) => a + b, 0);
}
// インソーステストスイート
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);
});
}
詳細については、インソーステストを参照してください。
ベンチマーク 実験的
Tinybench を介して bench
関数を使用してベンチマークテストを実行し、パフォーマンス結果を比較できます。
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;
});
});
});
型テスト 実験的
型の回帰を検出するためにテストを記述できます。Vitest には、同様で理解しやすい API を提供するために expect-type
パッケージが付属しています。
import { assertType, expectTypeOf, test } 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 }));
});
シャーディング
--shard
および --reporter=blob
フラグを使用して、異なるマシンでテストを実行します。 すべてのテストとカバレッジの結果は、--merge-reports
コマンドを使用して CI パイプラインの最後にマージできます。
vitest --shard=1/2 --reporter=blob --coverage
vitest --shard=2/2 --reporter=blob --coverage
vitest --merge-reports --reporter=junit --coverage
詳細については、パフォーマンスの向上 | シャーディング
を参照してください。
環境変数
Vitest は、フロントエンド関連のテストとの互換性を維持するために、Vite の確立された規則に従い、.env
ファイルから VITE_
で始まる環境変数のみを自動ロードします。.env
ファイルからすべての環境変数をロードするには、vite
からインポートされた loadEnv
メソッドを使用できます。
import { loadEnv } from 'vite';
import { defineConfig } from 'vitest/config';
export default defineConfig(({ mode }) => ({
test: {
// mode は、存在する場合にどの ".env.{mode}" ファイルを選択するかを定義します
env: loadEnv(mode, process.cwd(), ''),
},
}));
未処理のエラー
デフォルトでは、Vitest はすべての未処理の拒否、未捕捉の例外 (Node.js の場合)、およびエラーイベント (ブラウザの場合) を捕捉し、報告します。
これらを手動でキャッチすることで、この動作を無効にできます。Vitest はコールバックがあなたによって処理されたとみなし、エラーを報告しません。
// Node.js の場合
process.on('unhandledRejection', () => {
// あなた自身のハンドラ
});
process.on('uncaughtException', () => {
// あなた自身のハンドラ
});
// ブラウザの場合
window.addEventListener('error', () => {
// あなた自身のハンドラ
});
window.addEventListener('unhandledrejection', () => {
// あなた自身のハンドラ
});
あるいは、dangerouslyIgnoreUnhandledErrors
オプションで報告されたエラーを無視することもできます。Vitest はエラーを報告しますが、テスト結果には影響しません(終了コードは変更されません)。
エラーが捕捉されなかったことをテストする必要がある場合は、次のようなテストを作成できます。
test('my function throws uncaught error', async ({ onTestFinished }) => {
onTestFinished(() => {
// テスト中にイベントが発生しなかった場合、
// 次のテストが開始される前に削除されていることを確認してください
process.removeAllListeners('unhandledrejection');
});
return new Promise((resolve, reject) => {
process.once('unhandledrejection', error => {
try {
expect(error.message).toBe('my error');
resolve();
} catch (error) {
reject(error);
}
});
callMyFunctionThatRejectsError();
});
});