テストランナー
WARNING
これは高度なAPIです。単にテストを実行したいだけであれば、おそらく必要ありません。主にライブラリ開発者が使用します。
設定ファイルの runner
オプションでテストランナーのパスを指定できます。このファイルは、以下のメソッドを実装するクラスをデフォルトエクスポートする必要があります。
export interface VitestRunner {
/**
* テストを実際に収集して実行する前に最初に呼び出されます。
*/
onBeforeCollect?: (paths: string[]) => unknown;
/**
* テストを収集した後、"onBeforeRun" の前に呼び出されます。
*/
onCollected?: (files: File[]) => unknown;
/**
* テストランナーが次のテスト実行をキャンセルすべき場合に呼び出されます。
* ランナーはこのメソッドを監視し、呼び出されたときに "onBeforeRunSuite" および "onBeforeRunTask" でテストとスイートをスキップとしてマークする必要があります。
*/
onCancel?: (reason: CancelReason) => unknown;
/**
* 単一のテストを実行する前に呼び出されます。"result" はまだありません。
*/
onBeforeRunTest?: (test: TaskPopulated) => unknown;
/**
* 実際にテスト関数を実行する前に呼び出されます。"state" と "startTime" を含む "result" がすでに存在します。
*/
onBeforeTryTask?: (
test: TaskPopulated,
options: { retry: number; repeats: number }
) => unknown;
/**
* 結果と状態が設定された後に呼び出されます。
*/
onAfterRunTask?: (test: TaskPopulated) => unknown;
/**
* テスト関数を実行した直後に呼び出されます。新しい状態はまだありません。テスト関数がエラーを投げた場合は呼び出されません。
*/
onAfterTryTask?: (
test: TaskPopulated,
options: { retry: number; repeats: number }
) => unknown;
/**
* 単一のスイートを実行する前に呼び出されます。"result" はまだありません。
*/
onBeforeRunSuite?: (suite: Suite) => unknown;
/**
* 単一のスイートを実行した後に呼び出されます。状態と結果があります。
*/
onAfterRunSuite?: (suite: Suite) => unknown;
/**
* 定義されている場合、通常のVitestスイートの分割と処理の代わりに呼び出されます。
* "before" および "after" フックは無視されません。
*/
runSuite?: (suite: Suite) => Promise<void>;
/**
* 定義されている場合、通常のVitest処理の代わりに呼び出されます。カスタムテスト関数がある場合に便利です。
* "before" および "after" フックは無視されません。
*/
runTask?: (test: TaskPopulated) => Promise<void>;
/**
* タスクが更新されたときに呼び出されます。レポーターの "onTaskUpdate" と同じですが、これはテストと同じスレッドで実行されます。
*/
onTaskUpdate?: (task: [string, TaskResult | undefined][]) => Promise<void>;
/**
* 収集されたパス内のすべてのテストを実行する前に呼び出されます。
*/
onBeforeRunFiles?: (files: File[]) => unknown;
/**
* 収集されたパス内のすべてのテストを実行した直後に呼び出されます。
*/
onAfterRunFiles?: (files: File[]) => unknown;
/**
* テストの新しいコンテキストが定義された際に呼び出されます。コンテキストにカスタムプロパティを追加したい場合に便利です。
* ランナーでカスタムコンテキストを定義するだけの場合は、代わりに "setupFiles" の "beforeAll" を使用することを検討してください。
*
* このメソッドは "test" および "custom" ハンドラーの両方に対して呼び出されます。
*
* @see https://www.getbook.com/en/book/vitest-2/advanced/runner#your-task-function
*/
extendTaskContext?: <T extends Test | Custom>(
context: TaskContext<T>
) => TaskContext<T>;
/**
* 特定のファイルがインポートされたときに呼び出されます。テストを収集するときとセットアップファイルをインポートするときの2つの状況で呼び出されます。
*/
importFile: (filepath: string, source: VitestRunnerImportSource) => unknown;
/**
* 公開されている設定。
*/
config: VitestRunnerConfig;
}
このクラスをインスタンス化する際に、VitestはVitestの設定を渡します。これを config
プロパティとして公開する必要があります。
WARNING
Vitestは ViteNodeRunner
のインスタンスを __vitest_executor
プロパティとして注入します。これを使用して importFile
メソッドでファイルを処理できます(これは TestRunner
と BenchmarkRunner
の既定の動作です)。
ViteNodeRunner
は executeId
メソッドを公開しており、これはViteフレンドリーな環境でテストファイルをインポートするために使用されます。つまり、インポートを解決し、Nodeが理解できるように実行時にファイルコンテンツを変換します。
TIP
スナップショットサポートなどの機能はランナーによって提供されます。これを失いたくない場合は、vitest/runners
からインポートされた VitestTestRunner
からランナーを拡張できます。ベンチマーク機能を拡張したい場合は、BenchmarkNodeRunner
も公開しています。
タスク
スイートとテストは内部的に tasks
と呼ばれます。Vitestランナーは、テストを収集する前に File
タスクを初期化します。これは、いくつかの追加プロパティを持つ Suite
のスーパーセットです。これは、すべてのタスク(File
を含む)で file
プロパティとして利用可能です。
interface File extends Suite {
/**
* ファイルが属するプールの名前。
* @default 'forks'
*/
pool?: string;
/**
* UNIX形式のファイルへのパス。
*/
filepath: string;
/**
* ファイルが属するワークスペースプロジェクトの名前。
*/
projectName: string | undefined;
/**
* ファイル内のすべてのテストを収集するのにかかった時間。
* この時間には、すべてのファイル依存関係のインポートも含まれます。
*/
collectDuration?: number;
/**
* セットアップファイルをインポートするのにかかった時間。
*/
setupDuration?: number;
/**
* テストを実行せずにファイルが初期化されたかどうか。
* これは、Vitestによってサーバー側で状態を埋めるために行われます。
*/
local?: boolean;
}
すべてのスイートには、収集フェーズ中に設定される tasks
プロパティがあります。タスクツリーを上から下に走査するのに便利です。
interface Suite extends TaskBase {
type: 'suite';
/**
* ファイルタスク。ファイルのルートタスクです。
*/
file: File;
/**
* スイートの一部であるタスクの配列。
*/
tasks: Task[];
}
すべてのタスクには、それが配置されているスイートを参照する suite
プロパティがあります。test
または describe
がトップレベルで初期化された場合、suite
プロパティはありません(file
と等しくありません!)。File
も suite
プロパティを持つことはありません。タスクを下から上にたどるのに便利です。
interface Test<ExtraContext = object> extends TaskBase {
type: 'test';
/**
* テスト関数に渡されるテストコンテキスト。
*/
context: TaskContext<Test> & ExtraContext & TestContext;
/**
* ファイルタスク。ファイルのルートタスクです。
*/
file: File;
/**
* `t.skip()` を呼び出すことによってタスクがスキップされたかどうか。
*/
pending?: boolean;
/**
* タスクが失敗した場合に成功と見なされるかどうか。タスクが失敗した場合、合格とマークされます。
*/
fails?: boolean;
/**
* タスクが失敗した場合に実行されるフック。順序は `sequence.hooks` オプションに依存します。
*/
onFailed?: OnTestFailedHandler[];
/**
* タスクが完了した後に実行されるフック。順序は `sequence.hooks` オプションに依存します。
*/
onFinished?: OnTestFinishedHandler[];
/**
* テストを完了する前に待機するプロミス(非同期expectから)を格納します。
*/
promises?: Promise<any>[];
}
すべてのタスクには result
フィールドがあります。スイートは、スイートコールバックまたは beforeAll
/afterAll
コールバック内でスローされたエラーがテストの収集を妨げる場合にのみ、このフィールドを持つことができます。テストは、コールバックが呼び出された後、常にこのフィールドを持ちます。結果に応じて state
および errors
フィールドが存在します。beforeEach
または afterEach
コールバックでエラーが投げられた場合、そのエラーは task.result.errors
に記録されます。
export interface TaskResult {
/**
* タスクの状態。収集中は `task.mode` を継承します。
* タスクが完了すると、`pass` または `fail` に変更されます。
* - **pass**: タスクが正常に実行されました
* - **fail**: タスクが失敗しました
*/
state: TaskState;
/**
* タスク実行中に発生したエラー。
* `expect.soft()` が複数回失敗した場合、複数のエラーが発生する可能性があります。
*/
errors?: ErrorWithDiff[];
/**
* タスクの実行にかかった時間(ミリ秒)。
*/
duration?: number;
/**
* タスクの実行が開始された時間(ミリ秒)。
*/
startTime?: number;
/**
* タスク完了後のヒープサイズ(バイト)。
* `logHeapUsage` オプションが設定されており、`process.memoryUsage` が定義されている場合にのみ利用可能です。
*/
heap?: number;
/**
* このタスクに関連するフックの状態。レポート作成時に便利です。
*/
hooks?: Partial<
Record<'afterAll' | 'beforeAll' | 'beforeEach' | 'afterEach', TaskState>
>;
/**
* タスクが再試行された回数。タスクは失敗した場合かつ `retry` オプションが設定されている場合にのみ再試行されます。
*/
retryCount?: number;
/**
* タスクが繰り返された回数。タスクは `repeats` オプションが設定されている場合にのみリピートされます。この数値には `retryCount` も含まれます。
*/
repeatCount?: number;
}
あなたのタスク関数
Vitestは、組み込みのレポート機能を再利用できる Custom
タスクタイプを公開しています。これは実質的に Test
と同じですが、タイプが 'custom'
です。
タスクはスイートの一部であるオブジェクトです。suite.task
メソッドで現在のスイートに自動追加されます。
// ./utils/custom.js
import { createTaskCollector, getCurrentSuite, setFn } from 'vitest/suite';
export { afterAll, beforeAll, describe } from 'vitest';
// この関数は収集フェーズ中に呼び出されます。
// ここでハンドラ関数を呼び出さず、
// "getCurrentSuite().task()" メソッドを使用してスイートタスクに追加します。
// 注: createTaskCollector は "todo"/"each"/... のサポートを提供します。
export const myCustomTask = createTaskCollector(function (name, fn, timeout) {
getCurrentSuite().task(name, {
...this, // "todo"/"skip"/... が正しく追跡されるように
meta: {
customPropertyToDifferentiateTask: true,
},
handler: fn,
timeout,
});
});
// ./garden/tasks.test.js
import { afterAll, beforeAll, describe, myCustomTask } from '../custom.js';
import { gardener } from './gardener.js';
describe('take care of the garden', () => {
beforeAll(() => {
gardener.putWorkingClothes();
});
myCustomTask('weed the grass', () => {
gardener.weedTheGrass();
});
myCustomTask.todo('mow the lawn', () => {
gardener.mowerTheLawn();
});
myCustomTask('water flowers', () => {
gardener.waterFlowers();
});
afterAll(() => {
gardener.goHome();
});
});
vitest ./garden/tasks.test.js
WARNING
カスタムランナーがない場合、または runTest
メソッドを定義していない場合、Vitestは自動的にタスクを取得します。setFn
で関数を追加しなかった場合、失敗します。