擴充報告器
您可以從 vitest/reporters
匯入報告器並擴充它們來建立自訂報告器。
擴充內建報告器
通常,您不需要從頭開始建立報告器。vitest
隨附了幾個預設的報告器,您可以擴充它們。
ts
import { DefaultReporter } from 'vitest/reporters';
export default class MyDefaultReporter extends DefaultReporter {
// 執行某些操作
}
當然,您可以從頭開始建立報告器。只需擴充 BaseReporter
類別並實作您需要的方法即可。
以下是一個自訂報告器的範例:
ts
// ./custom-reporter.js
import { BaseReporter } from 'vitest/reporters';
export default class CustomReporter extends BaseReporter {
onCollected() {
const files = this.ctx.state.getFiles(this.watchFilters);
this.reportTestSummary(files);
}
}
或者實作 Reporter
介面:
ts
// ./custom-reporter.js
import { Reporter } from 'vitest/reporters';
export default class CustomReporter implements Reporter {
onCollected() {
// 輸出一些內容
}
}
然後您可以在 vitest.config.ts
檔案中使用您的自訂報告器:
ts
import { defineConfig } from 'vitest/config';
import CustomReporter from './custom-reporter.js';
export default defineConfig({
test: {
reporters: [new CustomReporter()],
},
});
已報告的任務
WARNING
這是一個實驗性 API。重大變更可能不遵循語義版本控制(SemVer)。使用時請固定 Vitest 的版本。
您可以透過呼叫 vitest.state.getReportedEntity(runnerTask)
來存取此 API:
ts
import type { Vitest } from 'vitest/node';
import type { RunnerTestFile } from 'vitest';
import type { Reporter, TestModule } from 'vitest/reporters';
class MyReporter implements Reporter {
ctx!: Vitest;
onInit(ctx: Vitest) {
this.ctx = ctx;
}
onFinished(files: RunnerTestFile[]) {
for (const fileTask of files) {
// 請注意,舊的任務實作使用 "file" 而非 "module"。
const testModule = this.ctx.state.getReportedEntity(
fileTask
) as TestModule;
for (const task of testModule.children) {
// ^?
console.log('finished', task.type, task.fullName);
}
}
}
}
我們計劃在 Vitest 2.1 中穩定此 API。
TestCase
TestCase
代表一個單一的測試。
ts
declare class TestCase {
readonly type = 'test' | 'custom';
/**
* 任務實例。
* @experimental 公共任務 API 是實驗性的,不遵循 semver。
*/
readonly task: RunnerTestCase | RunnerCustomCase;
/**
* 與測試相關聯的專案。
*/
readonly project: TestProject;
/**
* 直接參考定義測試的測試模組。
*/
readonly module: TestModule;
/**
* 測試名稱。
*/
readonly name: string;
/**
* 測試的完整名稱,包含所有父套件,以 `>` 分隔。
*/
readonly fullName: string;
/**
* 唯一識別碼。
* 此 ID 是確定性的,在多次執行中對於相同的測試將保持不變。
* 此 ID 基於專案名稱、模組 ID 和測試位置。
*/
readonly id: string;
/**
* 在模組中定義測試的位置。
* 只有在設定中啟用 `includeTaskLocation` 時才會收集位置。
*/
readonly location: { line: number; column: number } | undefined;
/**
* 父套件。如果測試直接在模組內部呼叫,則父級將是模組本身。
*/
readonly parent: TestSuite | TestModule;
/**
* 測試啟動時的選項。
*/
readonly options: TaskOptions;
/**
* 檢查測試是否未使套件失敗。
* 如果測試尚未完成或已跳過,則會傳回 `true`。
*/
ok(): boolean;
/**
* 在執行期間附加到測試的自訂元資料。
*/
meta(): TaskMeta;
/**
* 測試結果。如果測試尚未完成或剛收集,則為 `undefined`。
*/
result(): TestResult | undefined;
/**
* 有關測試的有用資訊,例如持續時間、記憶體使用等。
*/
diagnostic(): TestDiagnostic | undefined;
}
export type TestResult =
| TestResultPassed
| TestResultFailed
| TestResultSkipped;
export interface TestResultPassed {
/**
* 測試成功。
*/
state: 'passed';
/**
* 測試執行期間拋出的錯誤。
*
* **注意**:如果測試成功重試,錯誤仍會被報告。
*/
errors: TestError[] | undefined;
}
export interface TestResultFailed {
/**
* 測試失敗。
*/
state: 'failed';
/**
* 測試執行期間拋出的錯誤。
*/
errors: TestError[];
}
export interface TestResultSkipped {
/**
* 測試已使用 `only`、`skip` 或 `todo` 標記跳過。
* 您可以在 `mode` 選項中查看使用了哪個標記。
*/
state: 'skipped';
/**
* 跳過的測試不會有錯誤。
*/
errors: undefined;
}
export interface TestDiagnostic {
/**
* 如果測試的持續時間超過 `slowTestThreshold` 時。
*/
slow: boolean;
/**
* 測試使用的記憶體量(字節)。
* 此值僅在測試使用 `logHeapUsage` 標誌執行時可用。
*/
heap: number | undefined;
/**
* 執行測試所需的時間(毫秒)。
*/
duration: number;
/**
* 測試開始的時間(毫秒)。
*/
startTime: number;
/**
* 測試重試次數。
*/
retryCount: number;
/**
* 根據 `repeats` 選項配置的測試重複次數。
* 如果測試在重複期間失敗且未配置 `retry`,則此值可能較低。
*/
repeatCount: number;
/**
* 如果測試在第二次重試時成功。
*/
flaky: boolean;
}
TestSuite
TestSuite
代表一個包含測試和其他套件的單一測試套件。
ts
declare class TestSuite {
readonly type = 'suite';
/**
* 任務實例。
* @experimental 公共任務 API 是實驗性的,不遵循 semver。
*/
readonly task: RunnerTestSuite;
/**
* 與測試相關聯的專案。
*/
readonly project: TestProject;
/**
* 直接參考定義套件的測試模組。
*/
readonly module: TestModule;
/**
* 套件名稱。
*/
readonly name: string;
/**
* 套件的完整名稱,包含所有父套件,以 `>` 分隔。
*/
readonly fullName: string;
/**
* 唯一識別碼。
* 此 ID 是確定性的,在多次執行中對於相同的測試將保持不變。
* 此 ID 基於專案名稱、模組 ID 和測試位置。
*/
readonly id: string;
/**
* 在模組中定義套件的位置。
* 只有在設定中啟用 `includeTaskLocation` 時才會收集位置。
*/
readonly location: { line: number; column: number } | undefined;
/**
* 屬於此套件的測試和套件集合。
*/
readonly children: TaskCollection;
/**
* 套件啟動時的選項。
*/
readonly options: TaskOptions;
}
TestModule
TestModule
代表一個包含套件和測試的單一檔案。
ts
declare class TestModule extends SuiteImplementation {
readonly type = 'module';
/**
* 任務實例。
* @experimental 公共任務 API 是實驗性的,不遵循 semver。
*/
readonly task: RunnerTestFile;
/**
* 屬於此模組的套件和測試集合。
*/
readonly children: TestCollection;
/**
* 這通常是絕對的 Unix 檔案路徑。
* 如果檔案不在磁碟上,則可以是虛擬 ID。
* 此值對應於 Vite 的 `ModuleGraph` ID。
*/
readonly moduleId: string;
/**
* 有關模組的有用資訊,例如持續時間、記憶體使用量等。
* 如果模組尚未執行,所有診斷值將傳回 `0`。
*/
diagnostic(): ModuleDiagnostic;
}
export interface ModuleDiagnostic {
/**
* 匯入和啟動環境所需的時間。
*/
environmentSetupDuration: number;
/**
* Vitest 設定測試工具(執行器、模擬等)所需的時間。
*/
prepareDuration: number;
/**
* 匯入測試模組所需的時間。
* 這包括匯入模組中的所有內容並執行套件回呼。
*/
collectDuration: number;
/**
* 匯入設定模組所需的時間。
*/
setupDuration: number;
/**
* 模組中所有測試和鉤子的累積持續時間。
*/
duration: number;
}
TestCollection
TestCollection
代表套件和測試的集合。它還提供了用於迭代自身的有用方法。
ts
declare class TestCollection {
/**
* 傳回陣列中特定索引處的測試或套件。
*/
at(index: number): TestCase | TestSuite | undefined;
/**
* 集合中測試和套件的數量。
*/
size: number;
/**
* 以陣列形式傳回集合,以便於操作。
*/
array(): (TestCase | TestSuite)[];
/**
* 過濾屬於此集合及其子集合的所有套件。
*/
allSuites(): IterableIterator<TestSuite>;
/**
* 過濾屬於此集合及其子集合的所有測試。
*/
allTests(state?: TestResult['state'] | 'running'): IterableIterator<TestCase>;
/**
* 僅過濾屬於此集合的測試。
*/
tests(state?: TestResult['state'] | 'running'): IterableIterator<TestCase>;
/**
* 僅過濾屬於此集合的套件。
*/
suites(): IterableIterator<TestSuite>;
[Symbol.iterator](): IterableIterator<TestSuite | TestCase>;
}
例如,您可以透過呼叫 testModule.children.allTests()
來迭代模組內的所有測試:
ts
function onFileCollected(testModule: TestModule): void {
console.log('collecting tests in', testModule.moduleId);
// 迭代模組中的所有測試和套件
for (const task of testModule.children.allTests()) {
console.log('collected', task.type, task.fullName);
}
}
TestProject
TestProject
是與模組相關聯的專案。該模組內部的每個測試和套件都將參考相同的專案。
專案對於獲取配置或提供上下文非常有用。
ts
declare class TestProject {
/**
* 全域 Vitest 實例。
* @experimental 公共 Vitest API 是實驗性的,不遵循 semver。
*/
readonly vitest: Vitest;
/**
* 與此測試專案相關的工作區專案。
* @experimental 公共 Vitest API 是實驗性的,不遵循 semver。
*/
readonly workspaceProject: WorkspaceProject;
/**
* Vite 的開發伺服器實例。每個工作區專案都有自己的伺服器。
*/
readonly vite: ViteDevServer;
/**
* 已解析的專案設定。
*/
readonly config: ResolvedProjectConfig;
/**
* 已解析的全域配置。如果沒有工作區專案,此配置將與 `config` 相同。
*/
readonly globalConfig: ResolvedConfig;
/**
* 序列化的專案設定。這是測試接收的設定。
*/
get serializedConfig(): SerializedConfig;
/**
* 專案的名稱,若未設定則為空字串。
*/
name(): string;
/**
* 提供給專案的自訂內容。
*/
context(): ProvidedContext;
/**
* 為專案提供自訂的可序列化內容。此上下文在測試執行時將可用。
*/
provide<T extends keyof ProvidedContext & string>(
key: T,
value: ProvidedContext[T]
): void;
}
匯出的報告器
vitest
隨附了一些您可以直接使用的內建報告器。
內建報告器:
BasicReporter
DefaultReporter
DotReporter
JsonReporter
VerboseReporter
TapReporter
JUnitReporter
TapFlatReporter
HangingProcessReporter
基礎抽象報告器:
BaseReporter
介面報告器:
Reporter