迁移指南
从 Vitest 0.34.6 迁移
最低要求
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.isolatetest.maxThreads现在是test.poolOptions.<pool-name>.maxThreadstest.minThreads现在是test.poolOptions.<pool-name>.minThreadstest.useAtomics现在是test.poolOptions.<pool-name>.useAtomicstest.poolMatchGlobs.child_process现在是test.poolMatchGlobs.forkstest.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() 不再自动 mock process.nextTick。 仍然可以通过显式地使用 vi.useFakeTimers({ toFake: ['nextTick'] }) 来 mock process.nextTick。
但是,当使用 --pool=forks 时,无法 mock process.nextTick。如果需要 mock process.nextTick,请使用不同的 --pool 选项。
从 Jest 迁移
Vitest 被设计为拥有与 Jest 兼容的 API,以便尽可能简化从 Jest 的迁移。尽管做出了这些努力,您仍然可能会遇到以下差异:
默认全局变量
Jest 默认启用其 全局 API。Vitest 则不是。您可以通过 globals 配置设置 启用全局变量,或者更新您的代码以使用从 vitest 模块导入的替代方案。
如果您决定禁用全局变量,请注意,像 testing-library 这样的常用库将不会运行自动 DOM 清理。
模块模拟
在 Jest 中 mock 一个模块时,工厂函数的返回值是默认导出。在 Vitest 中,工厂函数必须返回一个对象,该对象显式地定义了每个导出。例如,以下 jest.mock 必须按如下方式更新:
jest.mock('./some-path', () => 'hello');
vi.mock('./some-path', () => ({
default: 'hello',
})); 有关更多详细信息,请参阅 vi.mock api 部分。
自动模拟行为
与 Jest 不同,除非 vi.mock() 被调用,否则 <root>/__mocks__ 中的 mock 模块不会被加载。如果您需要在每个测试中都 mock 它们,就像在 Jest 中一样,您可以在 setupFiles 中 mock 它们。
导入 Mock 包的原始版本
如果你只是部分 mock 一个包,你可能之前使用过 Jest 的 requireActual 函数。在 Vitest 中,您应该将这些调用替换为 vi.importActual。
const { cloneDeep } = jest.requireActual('lodash/cloneDeep');
const { cloneDeep } = await vi.importActual('lodash/cloneDeep'); 将模拟扩展到外部库
Jest 默认会这样做。当 mock 一个模块并希望将此 mock 扩展到使用同一模块的其他外部库时,你应该明确指定要 mock 的第三方库,以便外部库成为你源代码的一部分。这可以通过使用 server.deps.inline 来实现。
server.deps.inline: ["lib-name"]访问模拟 Promise 的返回值
Jest 和 Vitest 都会将所有 mock 调用的结果存储在 mock.results 数组中,每个调用的返回值存储在该数组的 value 属性中。 但是,当 mock 或 spy 一个 promise (例如,使用 mockResolvedValue) 时,在 Jest 中,value 属性会是一个 promise,而在 Vitest 中,当 promise 被 resolve 时,它会是一个已 resolve 的值。
await expect(spy.mock.results[0].value).resolves.toBe(123);
expect(spy.mock.results[0].value).toBe(123); 环境变量相关
与 Jest 一样,如果之前未设置,Vitest 会将 NODE_ENV 设置为 test。Vitest 还有一个与 JEST_WORKER_ID 对应的环境变量 VITEST_POOL_ID (始终小于或等于 maxThreads)。如果你依赖 JEST_WORKER_ID,请不要忘记将其重命名为 VITEST_POOL_ID。Vitest 还公开了 VITEST_WORKER_ID,它是正在运行的 worker 的唯一 ID - 此数字不受 maxThreads 的影响,并且会随着每个创建的 worker 而增加。
替换属性
如果你想修改对象,在 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()
})
})) 钩子函数
因此,如果你的钩子返回除了 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<string, [string]>;
import type { Mock } from 'vitest';
let fn: Mock<[string], string>; 此外,正如你在 diff 中所见,Vitest 使用 Args 类型作为第一个参数,而不是 Returns。
定时器相关
Vitest 不支持 Jest 的遗留定时器。
超时设置
如果您使用过 jest.setTimeout,则需要迁移到 vi.setConfig:
jest.setTimeout(5_000);
vi.setConfig({ testTimeout: 5_000 }); Vue 快照相关
这不是 Jest 特有的功能。但如果你之前将 Jest 与 vue-cli 预设一起使用,你需要安装 jest-serializer-vue 包,并在 setupFiles 中使用它。
vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
test: {
setupFiles: ['./tests/unit/setup.js'],
},
});tests/unit/setup.js
import vueSnapshotSerializer from 'jest-serializer-vue';
expect.addSnapshotSerializer(vueSnapshotSerializer);否则,您的快照将包含大量转义的 " 字符。