리포터 확장하기
vitest/reporters
에서 리포터를 가져와 확장하여 사용자 정의 리포터를 만들 수 있습니다.
내장 리포터 확장하기
일반적으로 리포터를 처음부터 만들 필요는 없습니다. vitest
는 확장할 수 있는 몇 가지 기본 리포터를 제공합니다.
import { DefaultReporter } from 'vitest/reporters';
export default class MyDefaultReporter extends DefaultReporter {
// 필요한 작업을 수행합니다.
}
물론 리포터를 처음부터 만들 수도 있습니다. BaseReporter
클래스를 확장하고 필요한 메서드를 구현하기만 하면 됩니다.
다음은 사용자 정의 리포터의 예입니다.
// ./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
인터페이스를 구현합니다.
// ./custom-reporter.js
import { Reporter } from 'vitest/reporters';
export default class CustomReporter implements Reporter {
onCollected() {
// 결과를 출력합니다.
}
}
그런 다음 vitest.config.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에 접근할 수 있습니다.
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) {
// 이전 작업 구현은 "module" 대신 "file"을 사용했음에 유의하세요.
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
는 단일 테스트를 나타냅니다.
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;
/**
* 테스트 실행에 걸리는 시간(ms)
*/
duration: number;
/**
* 테스트가 시작된 시간(ms)
*/
startTime: number;
/**
* 테스트가 재시도된 횟수
*/
retryCount: number;
/**
* `repeats` 옵션에 따라 테스트가 반복된 횟수
* 이 값은 반복 중에 테스트가 실패하고 `retry`가 구성되지 않은 경우 더 낮을 수 있습니다.
*/
repeatCount: number;
/**
* 두 번째 재시도에서 테스트가 통과했는지 여부
*/
flaky: boolean;
}
TestSuite
TestSuite
는 테스트 및 다른 스위트를 포함하는 단일 스위트를 나타냅니다.
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
은 스위트 및 테스트를 포함하는 단일 파일을 나타냅니다.
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
은 스위트 및 테스트 모음을 나타냅니다. 또한 자체를 반복하는 데 유용한 메서드를 제공합니다.
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()
를 호출하여 모듈 내의 모든 테스트를 반복할 수 있습니다.
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
는 모듈과 관련된 프로젝트입니다. 해당 모듈 내의 모든 테스트 및 스위트는 동일한 프로젝트를 참조합니다.
프로젝트는 구성 또는 제공된 컨텍스트를 가져오는 데 유용합니다.
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