마이그레이션 가이드
Vitest 3.0으로의 마이그레이션
test
옵션을 세 번째 인수로 전달
Vitest 3.0부터 test
또는 describe
함수에 세 번째 인수로 객체를 전달하면 경고가 발생합니다.
test('validation works', () => {
// ...
}, { retry: 3 });
test('validation works', { retry: 3 }, () => {
// ...
});
다음 주요 버전에서는 세 번째 인수가 객체일 경우 오류가 발생할 예정입니다. 타임아웃 숫자를 전달하는 것은 여전히 유효합니다.
test('validation works', () => {
// ...
}, 1000); // Ok ✅
browser.name
및 browser.providerOptions
사용 중단
browser.name
및 browser.providerOptions
는 Vitest 4에서 제거될 예정입니다. 대신 새로운 browser.instances
옵션을 사용하세요.
export default defineConfig({
test: {
browser: {
name: 'chromium',
providerOptions: {
launch: { devtools: true },
},
instances: [
{
browser: 'chromium',
launch: { devtools: true },
},
],
},
},
})
새로운 browser.instances
필드를 사용하면 여러 브라우저 구성을 지정할 수도 있습니다.
spy.mockReset
이 이제 원본 구현을 복원합니다.
이전에는 스파이를 다시 적용하지 않고는 스파이를 원본 구현으로 재설정할 좋은 방법이 없었습니다. 이제 spy.mockReset
은 구현 함수를 가짜 noop 대신 원본으로 재설정합니다.
const foo = {
bar: () => 'Hello, world!',
};
vi.spyOn(foo, 'bar').mockImplementation(() => 'Hello, mock!');
foo.bar(); // 'Hello, mock!'
foo.bar.mockReset();
foo.bar(); // undefined
foo.bar(); // 'Hello, world!'
vi.spyOn
은 메서드가 이미 모의된 경우 모의를 재사용합니다.
이전에는 Vitest가 객체를 스파이할 때 항상 새로운 스파이를 할당했습니다. 이로 인해 mockRestore
에서 오류가 발생했습니다. (Vitest가) 원본 함수 대신 이전 스파이로 복원했기 때문입니다.
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
vi.restoreAllMocks();
vi.isMockFunction(fooService.foo); // true
vi.isMockFunction(fooService.foo); // false
가짜 타이머의 기본값
Vitest는 기본적으로 fakeTimers.toFake
옵션을 더 이상 제공하지 않습니다. 이제 Vitest는 사용 가능한 모든 타이머 관련 API를 모의 처리합니다(nextTick
제외). 즉, vi.useFakeTimers
가 호출될 때 performance.now()
가 이제 모의됩니다.
vi.useFakeTimers();
performance.now(); // original
performance.now(); // fake
vi.useFakeTimers
를 호출할 때 또는 전역 구성에서 타이머를 지정하여 이전 동작으로 되돌릴 수 있습니다.
export default defineConfig({
test: {
fakeTimers: {
toFake: [
'setTimeout',
'clearTimeout',
'setInterval',
'clearInterval',
'setImmediate',
'clearImmediate',
'Date',
]
},
},
})
더 엄격한 오류 동등성
Vitest는 이제 toEqual
또는 toThrowError
를 통해 오류를 비교할 때 더 많은 속성을 확인합니다. Vitest는 이제 name
, message
, cause
, 그리고 AggregateError.errors
를 비교합니다. Error.cause
의 경우 비교는 비대칭적으로 이루어집니다.
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi')); // ✅
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' })); // ❌
더 많은 속성 확인 외에도, Vitest는 이제 오류 프로토타입을 비교합니다. 예를 들어, TypeError
가 발생한 경우 동등성 확인은 Error
가 아닌 TypeError
를 참조해야 합니다.
expect(() => {
throw new TypeError('type error');
})
.toThrowError(new Error('type error'))
.toThrowError(new TypeError('type error'));
자세한 내용은 PR을 참조하세요: #5876.
Vite 6에서 module
조건 내보내기가 기본적으로 해결되지 않습니다.
Vite 6는 더 유연한 resolve.conditions
옵션을 허용하며, Vitest는 기본적으로 module
조건부 내보내기를 제외하도록 구성됩니다. Vite 측 변경 사항에 대한 자세한 내용은 Vite 6 마이그레이션 가이드도 참조하세요.
Custom
타입 사용 중단 API
Custom
타입은 이제 Test
타입의 별칭입니다. Vitest는 2.1에서 공개 타입을 업데이트하여 내보낸 이름을 RunnerCustomCase
및 RunnerTestCase
로 변경했습니다.
import {
RunnerCustomCase,
RunnerTestCase,
} from 'vitest';
getCurrentSuite().custom()
을 사용하는 경우 반환된 작업의 type
은 이제 'test'
와 같습니다. Custom
타입은 Vitest 4에서 제거될 예정입니다.
WorkspaceSpec
타입 사용 중단
공개 API에서 이 타입은 이전에 사용자 정의 시퀀서에 사용되었습니다. 대신 TestSpecification
으로 마이그레이션하세요.
onTestFinished
및 onTestFailed
가 이제 컨텍스트를 받습니다.
이전에는 onTestFinished
및 onTestFailed
훅이 첫 번째 인수로 테스트 결과를 받았습니다. 이제 beforeEach
및 afterEach
와 같이 테스트 컨텍스트를 받습니다.
스냅샷 API 변경 사항 API
@vitest/snapshot
의 공개 스냅샷 API는 단일 실행 내에서 여러 상태를 지원하도록 변경되었습니다. 자세한 내용은 PR을 참조하세요: #6817
이 변경 사항은 스냅샷 API를 직접 사용하는 개발자에게만 영향을 줍니다. .toMatchSnapshot
API에는 변경 사항이 없습니다.
resolveConfig
타입 시그니처 변경 사항 API
이제 resolveConfig
는 더 유용해졌습니다. 이미 해결된 Vite 구성을 받는 대신, 사용자 구성을 받아 해결된 구성을 반환합니다.
이 함수는 내부적으로 사용되지 않으며, 오직 공개 API로만 노출됩니다.
vitest/reporters
타입 정리 API
vitest/reporters
진입점은 이제 리포터 구현과 옵션 타입만 내보냅니다. TestCase
/TestSuite
및 기타 작업 관련 타입에 액세스해야 한다면, vitest/node
에서 추가로 가져오세요.
coverage.excludes
를 덮어써도 커버리지는 테스트 파일을 무시합니다.
coverage.excludes
를 덮어쓰더라도 테스트 파일을 커버리지 보고서에 포함하는 것은 더 이상 불가능합니다. 테스트 파일은 이제 항상 제외됩니다.
Vitest 2.0으로 마이그레이션
기본 풀은 forks
입니다.
Vitest 2.0은 더 나은 안정성을 위해 pool
의 기본 설정을 'forks'
로 변경합니다. PR에서 전체 동기를 읽을 수 있습니다.
pool
을 지정하지 않고 poolOptions
를 사용했다면, 설정을 업데이트해야 할 수 있습니다.
export default defineConfig({
test: {
poolOptions: {
threads: {
singleThread: true,
},
forks: {
singleFork: true,
},
}
}
})
훅이 스택에서 실행됩니다.
Vitest 2.0 이전에는 모든 훅이 병렬로 실행되었습니다. 2.0에서는 모든 훅이 직렬로 실행됩니다. 또한 afterAll
/afterEach
훅은 역순으로 실행됩니다.
훅의 병렬 실행으로 되돌리려면, sequence.hooks
를 'parallel'
로 변경하세요.
export default defineConfig({
test: {
sequence: {
hooks: 'parallel',
},
},
})
suite.concurrent
는 모든 테스트를 동시에 실행합니다.
이전에는 스위트에서 concurrent
를 지정하면 동시 테스트가 스위트별로 그룹화되어 순차적으로 실행되었습니다. 이제 Jest의 동작을 따라 모든 테스트가 동시에 실행됩니다(maxConcurrency
제한에 따름).
V8 Coverage의 coverage.ignoreEmptyLines
가 기본적으로 활성화됩니다.
coverage.ignoreEmptyLines
의 기본값은 이제 true입니다. 이 중요한 변경 사항은 코드 커버리지 보고서에 영향을 미칠 수 있으며, 일부 프로젝트에서는 커버리지 임계값을 조정해야 할 수도 있습니다. 이 조정은 coverage.provider
가 'v8'
일 때의 기본 설정에만 영향을 줍니다.
watchExclude
옵션 제거
Vitest는 Vite의 watcher를 사용합니다. server.watch.ignored
에 추가하여 파일 또는 디렉토리를 제외할 수 있습니다.
export default defineConfig({
server: {
watch: {
ignored: ['!node_modules/examplejs']
}
}
})
--segfault-retry
제거됨
기본 풀 변경으로 인해 이 옵션은 더 이상 필요하지 않습니다. 세그먼트 오류가 발생하면 'forks'
풀로 전환해 보십시오. 문제가 지속되면 재현과 함께 새 이슈를 열어주십시오.
스위트 작업에서 빈 작업 제거됨
이것은 고급 작업 API의 변경 사항입니다. 이전에는 .suite
를 순회하면 결국 파일 작업 대신 사용되던 빈 내부 스위트로 이어졌습니다.
이로 인해 .suite
는 선택 사항이 됩니다. 작업이 최상위 수준에서 정의된 경우 스위트가 없습니다. 이제 모든 작업(파일 작업 자체 포함)에 존재하는 .file
속성으로 대체할 수 있습니다. (따라서 무한 재귀에 빠지지 않도록 주의하십시오.)
이 변경 사항은 또한 expect.getState().currentTestName
에서 파일을 제거하고 expect.getState().testPath
를 필수로 만듭니다.
task.meta
가 JSON 리포터에 추가됩니다.
JSON 리포터는 이제 모든 어설션 결과에 task.meta
를 출력합니다.
모의 함수의 일반 타입 단순화 (예: vi.fn<T>
, Mock<T>
)
이전에는 vi.fn<TArgs, TReturn>
이 인수와 반환 값에 대해 두 개의 제네릭 타입을 각각 허용했습니다. 이는 사용을 단순화하기 위해 함수 타입 vi.fn<T>
를 직접 허용하도록 변경되었습니다.
import { vi } from 'vitest';
import type { Mock } from 'vitest';
const add = (x: number, y: number): number => x + y;
// using vi.fn<T>
const mockAdd = vi.fn<Parameters<typeof add>, ReturnType<typeof add>>();
const mockAdd = vi.fn<typeof add>();
// using Mock<T>
const mockAdd: Mock<Parameters<typeof add>, ReturnType<typeof add>> = vi.fn();
const mockAdd: Mock<typeof add> = vi.fn();
해결된 mock.results
에 액세스
이전에는 함수가 Promise를 반환하면 Vitest가 mock.results
값을 해결했습니다. 이제 반환된 Promise가 해결되거나 거부될 때만 채워지는 별도의 mock.settledResults
속성이 있습니다.
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
const result = fn.mock.results[0]; // 'result'
const result = fn.mock.results[0]; // 'Promise<result>'
const settledResult = fn.mock.settledResults[0]; // 'result'
이 변경으로 인해, 이전에 toHaveReturned
를 사용했다면 마이그레이션을 더 쉽게 하기 위해 toHaveReturned
와 유사한 새로운 toHaveResolved*
매처도 도입됩니다.
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
expect(fn).toHaveReturned('result');
expect(fn).toHaveResolved('result');
브라우저 모드
Vitest 브라우저 모드는 베타 주기 동안 많은 변경 사항이 있었습니다. 브라우저 모드에 대한 우리의 철학은 GitHub 토론 페이지에서 확인할 수 있습니다.
대부분의 변경 사항은 추가적이었지만, 몇 가지 작은 호환성 문제가 있었습니다.
none
프로바이더가preview
로 이름이 변경되었습니다 #5842preview
프로바이더가 이제 기본값입니다 #5842indexScripts
가orchestratorScripts
로 이름이 변경되었습니다 #5842
더 이상 사용되지 않는 옵션 제거됨
일부 더 이상 사용되지 않는 옵션이 제거되었습니다.
vitest typecheck
명령 - 대신vitest --typecheck
사용VITEST_JUNIT_CLASSNAME
및VITEST_JUNIT_SUITE_NAME
환경 변수 (대신 리포터 옵션 사용)c8
커버리지 확인 (대신 coverage-v8 사용)vitest
에서SnapshotEnvironment
내보내기 - 대신vitest/snapshot
에서 가져오기SpyInstance
는MockInstance
를 선호하여 제거되었습니다.
Vitest 1.0으로 마이그레이션
최소 요구 사항
Vitest 1.0은 Vite 5.0과 Node.js 18 이상을 필요로 합니다.
모든 @vitest/*
하위 패키지는 Vitest 버전 1.0을 필요로 합니다.
스냅샷 업데이트 #3961
스냅샷의 따옴표는 더 이상 이스케이프되지 않으며, 문자열이 한 줄이더라도 모든 스냅샷은 백틱 따옴표(`
)를 사용합니다.
- 따옴표는 더 이상 이스케이프되지 않습니다.
expect({ foo: 'bar' }).toMatchInlineSnapshot(`
Object {
- \\"foo\\": \\"bar\\",
+ "foo": "bar",
}
`)
- 한 줄 스냅샷은 이제 ':' 대신 "`" 따옴표를 사용합니다.
- expect('some string').toMatchInlineSnapshot('"some string"')
+ expect('some string').toMatchInlineSnapshot(`"some string"`)
@vitest/snapshot
패키지에도 변경 사항이 있었습니다. 직접 사용하지 않는다면 아무것도 변경할 필요가 없습니다.
equalityCheck
메서드를 재정의하기 위해 더 이상SnapshotClient
를 확장할 필요가 없습니다. 인스턴스를 초기화할 때isEqual
로 전달하기만 하면 됩니다.client.setTest
가client.startCurrentRun
으로 이름이 변경되었습니다.client.resetCurrent
가client.finishCurrentRun
으로 이름이 변경되었습니다.
풀이 표준화되었습니다 #4172
러너를 필요에 맞게 쉽게 구성할 수 있도록 많은 설정 옵션을 제거했습니다. --threads
또는 기타 관련 플래그에 의존한다면, 마이그레이션 예제를 살펴보십시오.
--threads
는 이제--pool=threads
입니다.--no-threads
는 이제--pool=forks
입니다.--single-thread
는 이제--poolOptions.threads.singleThread
입니다.--experimental-vm-threads
는 이제--pool=vmThreads
입니다.--experimental-vm-worker-memory-limit
는 이제--poolOptions.vmThreads.memoryLimit
입니다.--isolate
는 이제--poolOptions.<pool-name>.isolate
및browser.isolate
입니다.test.maxThreads
는 이제test.poolOptions.<pool-name>.maxThreads
입니다.test.minThreads
는 이제test.poolOptions.<pool-name>.minThreads
입니다.test.useAtomics
는 이제test.poolOptions.<pool-name>.useAtomics
입니다.test.poolMatchGlobs.child_process
는 이제test.poolMatchGlobs.forks
입니다.test.poolMatchGlobs.experimentalVmThreads
는 이제test.poolMatchGlobs.vmThreads
입니다.
{
scripts: {
- "test": "vitest --no-threads"
// For identical behaviour:
+ "test": "vitest --pool forks --poolOptions.forks.singleFork"
// Or multi parallel forks:
+ "test": "vitest --pool forks"
}
}
{
scripts: {
- "test": "vitest --experimental-vm-threads"
+ "test": "vitest --pool vmThreads"
}
}
{
scripts: {
- "test": "vitest --isolate false"
+ "test": "vitest --poolOptions.threads.isolate false"
}
}
{
scripts: {
- "test": "vitest --no-threads --isolate false"
+ "test": "vitest --pool forks --poolOptions.forks.isolate false"
}
}
커버리지 변경 사항 #4265, #4442
coverage.all
옵션이 이제 기본적으로 활성화됩니다. 이는 coverage.include
패턴과 일치하는 모든 프로젝트 파일이 실행되지 않더라도 처리됨을 의미합니다.
커버리지 임계값 API의 형태가 변경되었으며, 이제 glob 패턴을 사용하여 특정 파일에 대한 임계값을 지정할 수 있습니다.
export default defineConfig({
test: {
coverage: {
- perFile: true,
- thresholdAutoUpdate: true,
- 100: true,
- lines: 100,
- functions: 100,
- branches: 100,
- statements: 100,
+ thresholds: {
+ perFile: true,
+ autoUpdate: true,
+ 100: true,
+ lines: 100,
+ functions: 100,
+ branches: 100,
+ statements: 100,
+ }
}
}
})
모의 타입 #4400
Jest 스타일 "Mock" 명명법을 선호하여 몇 가지 타입이 제거되었습니다.
- import { EnhancedSpy, SpyInstance } from 'vitest'
+ import { MockInstance } from 'vitest'
WARNING
SpyInstance
는 MockInstance
를 선호하여 더 이상 사용되지 않으며 다음 주요 릴리스에서 제거될 예정입니다.
타이머 모의 #3925
vi.useFakeTimers()
는 더 이상 process.nextTick
을 자동으로 모의하지 않습니다. vi.useFakeTimers({ toFake: ['nextTick'] })
을 사용하여 명시적으로 지정하면 process.nextTick
을 모의하는 것이 여전히 가능합니다.
그러나 --pool=forks
를 사용할 때는 process.nextTick
모의가 불가능합니다. process.nextTick
모의가 필요하다면 다른 --pool
옵션을 사용하십시오.
Jest에서 마이그레이션
Vitest는 Jest 호환 API로 설계되어 Jest에서 마이그레이션하는 것을 가능한 한 간단하게 만들었습니다. 이러한 노력에도 불구하고 다음과 같은 차이점에 직면할 수 있습니다.
기본값으로서의 전역
Jest는 기본적으로 전역 API를 활성화합니다. Vitest는 그렇지 않습니다. globals
설정을 통해 전역을 활성화하거나 vitest
모듈에서 가져오기를 사용하도록 코드를 업데이트할 수 있습니다.
전역을 비활성화하기로 결정했다면, testing-library
와 같은 일반적인 라이브러리가 자동 DOM 정리를 실행하지 않는다는 점에 유의하십시오.
spy.mockReset
Jest의 mockReset
은 모의 구현을 undefined
를 반환하는 빈 함수로 대체합니다.
Vitest의 mockReset
은 모의 구현을 원본으로 재설정합니다. 즉, vi.fn(impl)
로 생성된 모의를 재설정하면 모의 구현이 impl
로 재설정됩니다.
모듈 모의
Jest에서 모듈을 모의할 때 팩토리 인수의 반환 값은 기본 내보내기입니다. Vitest에서는 팩토리 인수가 각 내보내기가 명시적으로 정의된 객체를 반환해야 합니다. 예를 들어, 다음 jest.mock
은 다음과 같이 업데이트해야 합니다.
jest.mock('./some-path', () => 'hello')
vi.mock('./some-path', () => ({
default: 'hello',
}))
자세한 내용은 vi.mock
API 섹션을 참조하십시오.
자동 모의 동작
Jest와 달리 <root>/__mocks__
에 모의된 모듈은 vi.mock()
이 호출되지 않으면 로드되지 않습니다. Jest처럼 모든 테스트에서 모의되어야 한다면, setupFiles
내에서 모의할 수 있습니다.
모의된 패키지의 원본 가져오기
패키지를 부분적으로만 모의하는 경우 이전에 Jest의 requireActual
함수를 사용했을 수 있습니다. Vitest에서는 이러한 호출을 vi.importActual
로 대체해야 합니다.
const { cloneDeep } = jest.requireActual('lodash/cloneDeep');
const { cloneDeep } = await vi.importActual('lodash/cloneDeep');
외부 라이브러리로 모의 확장
Jest는 기본적으로 이를 수행하지만, 모듈을 모의하고 이 모의를 동일한 모듈을 사용하는 다른 외부 라이브러리로 확장하려면, server.deps.inline
을 사용하여 외부 라이브러리가 소스 코드의 일부가 되도록 어떤 타사 라이브러리를 모의할지 명시적으로 지정해야 합니다.
server.deps.inline: ["lib-name"]
expect.getState().currentTestName
Vitest의 test
이름은 >
기호로 연결되어 스위트와 테스트를 쉽게 구별할 수 있도록 하는 반면, Jest는 공백()을 사용합니다.
- `${describeTitle} ${testTitle}`
+ `${describeTitle} > ${testTitle}`
환경 변수
Jest와 마찬가지로 Vitest는 NODE_ENV
가 이전에 설정되지 않았다면 test
로 설정합니다. Vitest는 또한 JEST_WORKER_ID
에 해당하는 VITEST_POOL_ID
를 가지고 있으므로(maxThreads
보다 항상 작거나 같음), 이에 의존한다면 이름을 변경하는 것을 잊지 마십시오. Vitest는 또한 실행 중인 워커의 고유 ID인 VITEST_WORKER_ID
를 노출합니다. 이 숫자는 maxThreads
의 영향을 받지 않으며, 생성되는 각 워커에 따라 증가합니다.
속성 교체
객체를 수정하려면 Jest에서 replaceProperty API를 사용합니다. Vitest에서도 동일하게 vi.stubEnv
또는 vi.spyOn
을 사용할 수 있습니다.
완료 콜백
Vitest v0.10.0부터 테스트를 선언하는 콜백 스타일은 더 이상 사용되지 않습니다. 이들을 async
/await
함수를 사용하도록 다시 작성하거나, Promise를 사용하여 콜백 스타일을 모방할 수 있습니다.
it('should work', (done) => {
it('should work', () => new Promise(done => {
// ...
done()
})
}))
훅
beforeAll
/beforeEach
훅은 Vitest에서 정리 함수를 반환할 수 있습니다. 이 때문에 undefined
또는 null
이외의 것을 반환한다면 훅 선언을 다시 작성해야 할 수 있습니다.
beforeEach(() => setActivePinia(createTestingPinia()))
beforeEach(() => { setActivePinia(createTestingPinia()) })
Jest에서는 훅이 순차적으로(하나씩) 호출됩니다. 기본적으로 Vitest는 훅을 병렬로 실행합니다. Jest의 동작을 사용하려면 sequence.hooks
옵션을 업데이트하십시오.
export default defineConfig({
test: {
sequence: {
hooks: 'list',
}
}
})
타입
Vitest는 jest
네임스페이스와 동등한 것이 없으므로, vitest
에서 직접 타입을 가져와야 합니다.
let fn: jest.Mock<(name: string) => number>;
import type { Mock } from 'vitest';
let fn: Mock<(name: string) => number>;
타이머
Vitest는 Jest의 레거시 타이머를 지원하지 않습니다.
타임아웃
jest.setTimeout
을 사용했다면 vi.setConfig
로 마이그레이션해야 합니다.
jest.setTimeout(5_000);
vi.setConfig({ testTimeout: 5_000 });
Vue 스냅샷
이것은 Jest 특정 기능은 아니지만, 이전에 vue-cli 프리셋과 함께 Jest를 사용했다면 jest-serializer-vue
패키지를 설치하고 setupFiles 내에서 사용해야 합니다.
import { defineConfig } from 'vite';
export default defineConfig({
test: {
setupFiles: ['./tests/unit/setup.js'],
},
});
import vueSnapshotSerializer from 'jest-serializer-vue';
expect.addSnapshotSerializer(vueSnapshotSerializer);
그렇지 않으면 스냅샷에 이스케이프된 "
문자가 많이 포함될 것입니다.