Vitest 3.2 출시!
2025년 6월 2일
Vitest 3.2는 브라우저 모드와 TypeScript 지원 개선에 중점을 둡니다. 이번 릴리스에는 몇 가지 유용한 새 메서드와 구성 옵션이 포함되어 있으며, workspace
구성은 projects
로 대체됩니다.
workspace
는 더 이상 사용되지 않습니다
구성 단순화를 위해 Vitest 팀은 별도의 vitest.workspace
파일을 더 이상 사용하지 않고, 루트 구성에서 projects
옵션만 사용할 것을 권장하기로 결정했습니다. 이는 전역 옵션 구성 방식을 단순화하며, 루트 구성이 없을 때 리포터를 추가하는 방법을 추측할 필요가 없게 합니다.
또한, workspace
라는 이름이 PNPM과 같이 이 옵션을 통해 모노레포 지원을 제공하는 다른 도구와 충돌하기 때문에 더 이상 사용하지 않기로 결정했습니다. Vitest는 이러한 프로젝트를 별도의 CWD
로 실행하지 않고, 하위 Vitest처럼 취급합니다. 이는 다른 도구에 영향을 주지 않으면서 모노레포에 대한 더 나은 솔루션을 고안할 수 있는 여지를 제공합니다.
이 옵션은 향후 주요 버전에서 projects
로 완전히 대체될 예정입니다. 그때까지 Vitest는 workspace
기능이 사용되면 경고를 출력합니다.
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
// 'test.workspace'는 이제 'test.projects'로 변경되었습니다.
workspace: [
projects: [
{ test: { name: "Unit" } },
{ test: { name: "Integration" } },
],
},
});
주석 API
새로운 주석 API를 사용하면 사용자 지정 메시지 및 첨부 파일로 모든 테스트에 주석을 달 수 있습니다. 이러한 주석은 UI, HTML, JUnit, TAP 및 GitHub Actions 리포터에서 볼 수 있습니다. Vitest는 테스트가 실패하면 CLI에 관련 주석을 출력합니다.

범위 지정 픽스처
test.extend
픽스처는 이제 scope
옵션(file
또는 worker
)을 지정할 수 있습니다.
const test = baseTest.extend({
db: [
async ({}, use) => {
// ...설정
await use(db);
await db.close();
},
{ scope: 'worker' },
],
});
파일 픽스처는 파일 최상위 레벨에서 beforeAll
및 afterAll
을 사용하는 것과 유사하지만, 해당 픽스처가 어떤 테스트에서도 사용되지 않으면 호출되지 않습니다.
worker
픽스처는 워커당 한 번 시작됩니다. 하지만 기본적으로 Vitest는 모든 테스트에 대해 하나의 워커를 생성하므로, 이 기능을 활용하려면 격리를 비활성화해야 합니다.
사용자 지정 프로젝트 이름 색상
이제 projects
를 사용할 때 사용자 지정 색상을 설정할 수 있습니다.
구성 예시
export default defineConfig({
test: {
projects: [
{
test: {
name: {
label: 'unit',
color: 'red',
},
},
},
{
test: {
name: {
label: 'browser',
color: 'green',
},
browser: {
enabled: true,
provider: 'playwright',
instances: [{ browser: 'chromium' }],
},
},
},
],
},
})

사용자 지정 브라우저 로케이터 API
내장 로케이터만으로는 애플리케이션의 모든 요구 사항을 표현하기에 충분하지 않을 수 있습니다. CSS로 되돌아가면서 Vitest의 로케이터 API가 제공하는 재시도 보호 기능을 포기하는 대신, 이제 새로운 locators.extend
API를 사용하여 로케이터를 확장하는 것을 권장합니다.
import { locators } from '@vitest/browser/context';
locators.extend({
getByCommentsCount(count: number) {
return `.comments :text("${count} comments")`;
},
});
새 로케이터를 구성하려면 Playwright 로케이터 문자열을 반환합니다. 이 메서드에서 반환된 문자열은 상위 로케이터가 있는 경우 해당 상위 로케이터에 범위가 지정됩니다.
이제 page
또는 다른 로케이터에서 getByCommentsCount
를 직접 호출할 수 있습니다.
await expect.element(page.getByCommentsCount(1)).toBeVisible();
await expect
.element(
page.getByRole('article', { name: 'Hello World' }).getByCommentsCount(1)
)
.toBeVisible();
이 메서드가 문자열을 반환하면 해당 값이 로케이터로 변환되어 체이닝이 가능합니다.
page
.getByRole('article', { name: 'Hello World' })
.getByCommentsCount(1)
.getByText('comments');
이 메서드는 현재 로케이터 컨텍스트에 액세스할 수 있습니다. (메서드가 page
에서 호출되면 컨텍스트는 page
를 참조합니다.) 따라서 모든 로케이터 메서드를 내부에 연결할 수 있습니다.
import { locators } from '@vitest/browser/context';
import type { Locator } from '@vitest/browser/context';
locators.extend({
getByCommentsCount(this: Locator, count: number) {
return this.getByRole('comment').and(this.getByText(`${count} comments`));
},
});
컨텍스트에 접근하면 로케이터의 일반 메서드를 호출해 커스텀 사용자 이벤트를 정의할 수도 있습니다.
import { locators, page } from '@vitest/browser/context';
import type { Locator } from '@vitest/browser/context';
locators.extend({
clickAndFill(this: Locator, text: string) {
await this.click();
await this.fill(text);
},
});
await page.getByRole('textbox').clickAndFill('Hello World');
자세한 내용은 locators.extend
API를 참조하십시오.
vi.spyOn
및 vi.fn
의 명시적 리소스 관리
명시적 리소스 관리를 지원하는 환경에서는 const
대신 using
을 사용하여 포함 블록이 종료될 때 모든 모의 함수에서 mockRestore
를 자동으로 호출할 수 있습니다. 이는 스파이된 메서드에 특히 유용합니다.
it('calls console.log', () => {
using spy = vi.spyOn(console, 'log').mockImplementation(() => {})
debug('message')
expect(spy).toHaveBeenCalled()
})
// console.log는 여기서 복원됩니다.
테스트 signal
API
Vitest는 이제 테스트 본문에 AbortSignal
객체를 제공합니다. 이 웹 API를 지원하는 모든 리소스를 중지하는 데 사용할 수 있습니다.
신호는 테스트 시간이 초과되거나, 다른 테스트가 실패하고 --bail
플래그가 0이 아닌 값으로 설정되거나, 사용자가 터미널에서 Ctrl+C를 누를 때 중단됩니다.
예를 들어, 테스트가 중단될 때 fetch
요청을 중지할 수 있습니다.
it('stop request when test times out', async ({ signal }) => {
await fetch('/heavy-resource', { signal });
}, 2000);
Coverage V8 AST 인식 재매핑
Vitest는 이제 Vitest 관리자 중 한 명인 AriPerkkio가 개발한 ast-v8-to-istanbul
패키지를 사용하고 있습니다. 이는 v8 커버리지 보고서를 Istanbul과 일치시키면서도 더 나은 성능을 제공합니다! coverage.experimentalAstAwareRemapping
을 true
로 설정하여 이 기능을 활성화하십시오.
다음 주요 버전에서 이를 기본 재매핑 모드로 만들 계획입니다. 이전 v8-to-istanbul
은 완전히 제거될 예정입니다. https://github.com/vitest-dev/vitest/issues/7928 에서 토론에 참여해 주십시오.
watchTriggerPatterns
옵션
파일을 편집할 때 Vitest는 해당 파일을 가져오는 테스트만 다시 실행할 수 있습니다. 불행히도 Vitest의 정적 분석은 정적 및 동적 import
문만 인식합니다. 파일을 읽거나 별도의 프로세스를 시작하는 경우 Vitest는 관련 파일의 변경 사항을 무시합니다.
watchTriggerPatterns
옵션을 사용하면 변경된 파일에 따라 어떤 테스트를 다시 실행할지 구성할 수 있습니다. 예를 들어, 템플릿이 변경될 때 mailers
테스트를 항상 다시 실행하려면 트리거 패턴을 추가하십시오.
export default defineConfig({
test: {
watchTriggerPatterns: [
{
pattern: /^src\/templates\/(.*)\.(ts|html|txt)$/,
testsToRun: (file, match) => {
return `api/tests/mailers/${match[2]}.test.ts`;
},
},
],
},
});
새로운 다목적 Matchers
타입
Vitest는 이제 모든 사용자 지정 매처에 대한 타입 지원을 한 곳에서 추가할 수 있도록 확장 가능한 Matchers
타입을 제공합니다. 이 타입은 다음 모든 사용 사례에 영향을 미칩니다.
expect().to*
expect.to*
expect.extend({ to* })
예를 들어, 타입 안전한 toBeFoo
매처를 가지려면 다음과 같이 작성할 수 있습니다.
import { expect } from 'vitest';
interface CustomMatchers<R = unknown> {
toBeFoo: (arg: string) => R;
}
declare module 'vitest' {
interface Matchers<T = any> extends CustomMatchers<T> {}
}
expect.extend({
toBeFoo(actual, arg) {
// ^?
// ... 구현
return {
pass: true,
message: () => '',
};
},
});
expect('foo').toBeFoo('foo');
expect.toBeFoo('foo');
sequence.groupOrder
새로운 sequence.groupOrder
옵션은 여러 프로젝트를 사용할 때 프로젝트가 테스트를 실행하는 순서를 제어합니다.
- 동일한 그룹 순서 번호를 가진 프로젝트는 함께 실행되며, 그룹은 낮은 번호부터 높은 번호 순으로 실행됩니다.
- 이 옵션을 설정하지 않으면 모든 프로젝트가 병렬로 실행됩니다.
- 여러 프로젝트가 동일한 그룹 순서를 사용하면 동시에 실행됩니다.
예시
다음 예시를 고려하십시오.
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
projects: [
{
test: {
name: 'slow',
sequence: {
groupOrder: 0,
},
},
},
{
test: {
name: 'fast',
sequence: {
groupOrder: 0,
},
},
},
{
test: {
name: 'flaky',
sequence: {
groupOrder: 1,
},
},
},
],
},
});
이러한 프로젝트의 테스트는 다음 순서로 실행됩니다.
0. slow |
|> 함께 실행됨
0. fast |
1. flaky |> slow 및 fast 실행 후 단독으로 실행됨
전체 변경 사항 목록은 Vitest 3.2 변경 로그에서 확인할 수 있습니다.