
Vitest 高级 Node.js API 完全指南从 createVitest 到测试编排的每个细节【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitestVitest 不仅仅是一个命令行测试运行器它还暴露了一整套面向 Node.js 的编程式 API允许你在自己的脚本、自定义报告器、IDE 插件或 CI 工具链中直接驱动测试生命周期。本文基于 Vitest API 官方文档结合仓库内 核心实现 的源码系统讲解Vitest实例的每一个属性与方法——从全局配置、项目管理、测试收集与运行到快照更新、覆盖率控制、报告写入与服务生命周期管理。读完本文你将能够用createVitest编写自己的测试编排脚本、自定义 watcher 逻辑并为第三方集成如自定义报告器接入 Vitest 的完整能力。从入口说起createVitest 与 Vitest 实例高级 API 的入口是vitest/node导出的createVitest函数。它返回一个Vitest实例本文所有内容都围绕该实例展开import { createVitest } from vitest/node const vitest await createVitest(test, { watch: false, })在仓库中Vitest类定义于 packages/vitest/src/node/core.ts它聚合了日志器logger、包安装器packageInstaller、项目列表projects、watcher 处理器、VCS 提供者默认使用 Git 检测--changed文件以及全局配置等核心状态。全局属性mode、config、vite、statemode自 Vitest 5 起vitest.mode恒等于test。早期版本它曾用于区分test、benchmark等模式如今该属性被保留但不再有实际分支意义。configvitest.config是根全局配置即用户配置中test属性被解析后的结果。如果定义了 projects那么各个项目会把这份配置引用为globalConfig。::: warningvitest.config是Vitest 配置并不包含 Vite 配置的扩展内容——它只持有test属性的解析值。完整的 Vite 配置请通过vitest.viteConfig解析后的 Vite 配置与vitest.viteVite 开发服务器获取。 :::从 core.ts 可以看到config、viteConfig、vite、state、snapshot、cache等属性都在配置解析完成后被赋值。vitevitest.vite是全局的ViteDevServer实例。所有测试文件、全局 setup、自定义报告器都经由它转换模块。state实验性vitest.state是全局测试状态管理器存储当前测试的相关信息。其默认实现基于内部可序列化的 Task API见 packages/vitest/src/node/state.ts 中的idMap: Mapstring, Task。官方推荐使用Reported Tasks API而非直接操作 Taskconst task vitest.state.idMap.get(taskId) // 旧 API const testCase vitest.state.getReportedEntity(task) // 新 APIgetReportedEntity在源码中实现为this.reportedTasksMap.get(task)返回TestModule | TestCase | TestSuite之一state.ts并配套提供了getReportedEntityById。未来旧 API 将不再对外暴露。::: warningstate是实验性 APIvitest.state.getReportedEntity除外。实验性 API 的破坏性变更可能不遵循 SemVer使用时应固定 Vitest 版本。 :::snapshot、cache 与 watchersnapshotvitest.snapshot是全局快照管理器。Vitest 通过snapshot.add方法追踪所有快照最新汇总可通过vitest.snapshot.summary属性获取。cachevitest.cache是缓存管理器存储最新测试结果与测试文件统计信息。在 Vitest 内部它主要被默认 sequencer 用来对测试排序——例如让上次失败的测试优先运行。watcher4.0.0vitest.watcher是 Vitest watcher 的处理器实例提供跟踪文件变更并重跑测试的方法。注意watcher本身不是文件系统监听器而是暴露了处理变更文件的方法。如果内建 watcher 被禁用你可以用自己的 watcher 并调用onFileChange、onFileDelete、onFileCreate来复刻 Vitest 的行为。项目管理projects、getRootProject 与 getProjectByNameprojectsvitest.projects是归属于用户项目的 TestProject 数组。如果用户没有显式定义 projects该数组只包含根项目。Vitest 保证数组中始终至少有一个项目如果用户指定了不存在的--project名称会在该数组被定义之前直接抛出错误。getRootProjectfunction getRootProject(): TestProject返回根测试项目。根项目通常不运行任何测试也不出现在vitest.projects中——除非用户显式把根配置纳入 projects或者根本没有定义 projects。根项目的主要职责是承载全局配置。事实上存在如下恒等式见 core.ts 附近的实现rootProject.config rootProject.globalConfig rootProject.vitest.config即rootProject.config直接引用rootProject.globalConfig与vitest.config。getProjectByNamefunction getProjectByName(name: string): TestProject按名称返回项目等价于调用vitest.projects.find(p p.name name)。::: warning 若项目不存在此方法会返回根项目而非undefined——请务必再次核对返回的项目名称。另外如果用户没有自定义项目名Vitest 会分配空字符串作为名称。 :::matchesProjectFilter3.1.0function matchesProjectFilter(name: string): boolean检查名称是否匹配当前的--project项目过滤器见 CLI 文档。如果没有设置项目过滤器恒返回true。需要注意--projectCLI 选项无法以编程方式修改。跨进程传值provide 与 getProvidedContextprovidefunction provideT extends keyof ProvidedContext string( key: T, value: ProvidedContext[T], ): voidvitest.provide是vitest.getRootProject().provide的简写用于把主线程的值传递到测试中。所有值在存储前都会经过structuredClone校验但值本身不会被克隆。在测试文件中通过vitest入口导入inject接收值import { inject } from vitest const port inject(wsPort) // 3000为了获得更好的类型安全建议扩充ProvidedContext的类型import { createVitest } from vitest/node const vitest await createVitest(test, { watch: false, }) vitest.provide(wsPort, 3000) declare module vitest { export interface ProvidedContext { wsPort: number } }从 core.ts 可以看到provide的实现就是this.getRootProject().provide(key, value)。::: warning 严格来说provide是TestProject的方法因此受限于具体项目。但所有项目都继承根项目的值这使得vitest.provide成为向测试传值的通用方式。 :::getProvidedContextfunction getProvidedContext(): ProvidedContext返回根上下文对象是vitest.getRootProject().getProvidedContext的简写core.ts。测试规格TestSpecification收集、缓存与运行Vitest 5 的编程式 API 围绕TestSpecification测试规格展开——它描述了一个可运行/可收集的测试单元。规格相关方法在 core.ts 之后集中实现底层委托给this.specifications。globTestSpecificationsfunction globTestSpecifications( filters?: string[], ): PromiseTestSpecification[]通过在每个项目上调用project.globTestFiles收集所有测试构造新的 test specifications。filters用于匹配测试文件与 CLI 支持的过滤器 相同const specifications await vitest.globTestSpecifications([my-filter]) // [TestSpecification{ moduleId: /tests/my-filter.test.ts }] console.log(specifications)该方法会自动缓存所有测试规格。之后调用getModuleSpecifications会返回同样的规格除非先调用了clearSpecificationsCache。::: warning 在 Vitest 3 中如果poolMatchGlob配置了多个 pool或启用了typecheck同一个模块 ID文件路径可能对应多个测试规格。该可能性将在 Vitest 4 中被移除。 :::getRelevantTestSpecificationsfunction getRelevantTestSpecifications( filters?: string[], ): PromiseTestSpecification[]通过调用project.globTestFiles解析每个测试规格支持同样的 CLI 过滤器。如果指定了--changed标志列表会过滤为仅包含发生变更的文件。该方法不会运行任何测试文件。::: warning 该方法可能很慢因为它需要处理--changed标志的过滤。如果只是要一个测试文件列表不要用它已知测试文件想获取规格列表 → 用getModuleSpecifications想获取所有可能的测试文件 → 用globTestSpecifications。 :::getModuleSpecificationsfunction getModuleSpecifications(moduleId: string): TestSpecification[]返回与模块 ID 相关的测试规格列表。moduleId应为已解析的绝对文件路径。如果该 ID 不匹配include或includeSource模式返回空数组。该方法可能基于moduleId与pool返回已缓存的规格。但注意project.createSpecification总是返回新实例且不会自动缓存不过当调用runTestSpecifications时规格会被自动缓存。::: warning 自 Vitest 3 起该方法使用缓存判断文件是否为测试文件。为确保缓存非空请至少调用一次globTestSpecifications。 :::clearSpecificationsCachefunction clearSpecificationsCache(moduleId?: string): void当调用globTestSpecifications或runTestSpecifications时Vitest 会自动为每个文件缓存测试规格。此方法根据第一个参数清除指定文件的缓存或清除全部缓存。runTestSpecificationsfunction runTestSpecifications( specifications: TestSpecification[], allTestsRun false, ): PromiseTestRunResult根据传入的规格运行每个测试。第二个参数allTestsRun供覆盖率提供者判断报告是否需要包含未被覆盖的文件。::: warning 此方法不会触发onWatcherRerun、onWatcherStart和onTestsRerun回调。如果基于文件变更重跑测试请改用rerunTestSpecifications。 :::rerunTestSpecificationsfunction rerunTestSpecifications( specifications: TestSpecification[], allTestsRun false, ): PromiseTestRunResult先触发reporter.onWatcherRerun与onTestsRerun事件再通过runTestSpecifications运行测试。如果主进程没有错误随后触发reporter.onWatcherStart事件core.ts。runTestFiles4.1.0function runTestFiles( filepaths: string[], allTestsRun false, ): PromiseTestRunResult基于文件路径过滤器自动创建规格并运行。它与start不同不创建覆盖率提供者、不触发onInit与onWatcherStart事件且在没有可运行文件时不会抛错此时返回空数组而不触发测试运行。接受与start及 CLI 相同的过滤器。测试收集collect、collectTests 与静态解析collectfunction collect( filters?: string[], options?: { staticParse?: boolean staticParseConcurrency?: number }, ): PromiseTestRunResult根据staticParse决定收集方式默认对测试文件进行静态分析来收集或运行代码但不执行测试回调。collect返回未处理错误与 test modules 数组接受 CLI 过滤器。规格解析基于配置中的include、exclude、includeSource值详见project.globTestFiles。若指定--changed列表将过滤为仅包含变更文件。::: warning 自 Vitest 5 起默认通过静态分析收集测试。若通过第二个参数禁用Vitest 会像运行普通测试一样在隔离环境中运行每个测试文件——这会非常慢除非在收集前手动关闭隔离。 :::collectTestsfunction collectTests( specifications: TestSpecification[], ): PromiseTestRunResult执行测试文件但不运行测试回调返回未处理错误与 test modules 数组。其工作方式与collect完全一致区别在于规格需要你自己提供。::: warningcollectTests不使用静态分析Vitest 会像运行普通测试一样在隔离环境中运行每个测试文件因此非常慢——除非在收集前关闭隔离。 :::experimental_parseSpecification4.0.0实验性function experimental_parseSpecification( specification: TestSpecification, ): PromiseTestModule不运行文件即可收集文件内所有测试。它在 Vite 的ssrTransform之上使用 rollup 的parseAst函数对文件进行静态分析core.ts。::: warning若 Vitest 无法分析出测试名称会为测试或套件注入dynamic: true属性id也会追加-dynamic后缀以免与正常收集的测试冲突。带有for或each修饰符的测试、以及动态命名如hello ${property}或hello property的测试总会注入该属性。Vitest 仍会为其分配名称但该名称不能用于过滤测试。动态测试无法被过滤但你可以用escapeTestName函数把for/each测试转成名称模式import { escapeTestName } from vitest/node // 转为 /hello, .?/ const escapedPattern new RegExp(escapeTestName(hello, %s, true))Vitest 只收集文件中定义的测试绝不会跟随 import 进入其他文件。即使it、test、suite、describe并非从vitest入口导入Vitest 也会收集它们。 :::parseSpecifications5.0.0function parseSpecifications( specifications: TestSpecification[], options?: { concurrency?: number }, ): PromiseTestModule[]从规格数组中收集测试行为同上。默认情况下Vitest 一次只并行处理os.availableParallelism()个规格以降低性能损耗可通过第二个参数指定不同并发数。运行入口start、standalone 与生命周期startfunction start(filters?: string[]): PromiseTestRunResult初始化报告器与覆盖率提供者然后运行测试。接受 CLI 过滤器。::: warning 若同时调用了vitest.standalone()则不应调用此方法。Vitest 初始化后需要运行测试时请改用runTestSpecifications或rerunTestSpecifications。 :::当config.mergeReports与config.standalone均未设置时startVitest会自动调用start。standalone4.1.1实验性function standalone(): Promisevoid别名init已弃用初始化报告器与覆盖率提供者但不运行任何测试。如果提供了--watch标志即使未调用此方法Vitest 仍会运行变更的测试。内部仅在启用--standalone标志时调用见 CLI 文档。与start互斥当config.standalone设置时startVitest会自动调用它。waitForTestRunEnd4.0.0function waitForTestRunEnd(): Promisevoid如果当前有测试运行返回一个在测试运行结束时 resolve 的 Promise。取消与模式控制cancelCurrentRunfunction cancelCurrentRun(reason: CancelReason): Promisevoid优雅地取消所有进行中的测试停止正在运行的测试且不运行已调度但尚未开始的测试。setGlobalTestNamePattern / getGlobalTestNamePattern / resetGlobalTestNamePatternfunction setGlobalTestNamePattern(pattern: string | RegExp): void function getGlobalTestNamePattern(): RegExp | undefined // 4.0.0 function resetGlobalTestNamePattern(): void覆盖/读取/重置全局 test name pattern。resetGlobalTestNamePattern意味着 Vitest 不再跳过任何测试。::: warning 这些方法不会启动测试。要用更新后的模式运行测试请调用runTestSpecifications。 :::快照更新updateSnapshot、enableSnapshotUpdate、resetSnapshotUpdatefunction updateSnapshot(files?: string[]): PromiseTestRunResult更新指定文件中的快照。若不提供文件则更新存在失败测试的文件与过时快照。function enableSnapshotUpdate(): void function resetSnapshotUpdate(): voidenableSnapshotUpdate开启更新快照模式此后运行的每个测试都会更新快照resetSnapshotUpdate用于关闭该模式。二者同样不会启动任何测试。文件失效与模块导入invalidateFile 与 importinvalidateFilefunction invalidateFile(filepath: string): void使文件在所有项目的缓存中失效。当你依赖自己的 watcher 时尤其有用因为 Vite 的缓存常驻内存。::: danger 如果禁用了 Vitest 的 watcher 但让 Vitest 保持运行务必手动调用此方法清理缓存——缓存无法被关闭。该方法同时会使文件的 importers 失效。 :::importfunction importT(moduleId: string): PromiseT使用 Vite 模块运行器导入文件完整签名见 import-example.md。文件会经全局配置由 Vite 转换并在独立上下文中执行。注意moduleId相对于config.root。::: dangerproject.import复用 Vite 的模块图因此用普通 import 与用vitest.import导入同一模块会得到不同的模块实例import * as staticExample from ./example.js const dynamicExample await vitest.import(./example.js) dynamicExample ! staticExample // ✅:::::: info 内部实现上Vitest 用该方法导入全局 setup、自定义覆盖率提供者与自定义报告器——只要它们属于同一个 Vite 服务器就共享同一模块图实现见 core.ts。 :::合并报告与文件系统报告mergeReports 与 createReportmergeReportsfunction mergeReports(directory?: string): PromiseTestRunResult合并位于指定目录中多次运行的报告未指定时使用--merge-reports的值。该值也可在config.mergeReports上设置默认读取.vitest/blob/目录。directory始终相对于工作目录解析。当config.mergeReports设置时startVitest会自动调用此方法core.ts。createReport5.0.0function createReport(scope: string): Report创建限定于给定scope的报告。Report遵循 Vitest 关于 在文件系统上存储产物 的规则为第三方集成如自定义报告器提供写入测试结果、临时文件及其他产物的工具集合。Report的所有操作都限制在给定scope内一个报告不会干扰其他报告。内部 Vitest 创建.vitest目录每个scope在其中创建自己的子目录——这一约定减少了用户需要在.gitignore中声明的条目数量。import type { Report } from vitest/node const scope example-yaml-reporter // 自动创建 project-root/.vitest/example-yaml-reporter/ // 目录如果尚不存在 const report: Report vitest.createReport(scope)Report提供以下成员对应实现见 core.ts成员签名说明rootstring该 scope 的根目录如project-root/.vitest/my-json-reporterclean() Promisevoid清空该 scope 的报告目录writeFile(filename, content, encoding?) Promisevoid写入文件默认 UTF-8 编码文件名相对 scope 目录readFile(filename, encoding?) Promisestring读取文件readdir() Promisestring[]列出报告目录内容delete(filename) Promisevoid删除文件const report vitest.createReport(my-json-reporter) // 写入 .vitest/my-json-reporter/test-report.json await report.writeFile(test-report.json, JSON.stringify(results)) // 读取 const content: string await report.readFile(test-report.json) // 列出内容 const filenames: string[] await report.readdir() // 删除 await report.delete(test-report.json) // 清空整个目录 await report.clean()覆盖率控制createCoverageProvider、enableCoverage、disableCoveragefunction createCoverageProvider(): PromiseCoverageProvider | null // 4.0.0 function enableCoverage(): Promisevoid // 4.0.0 function disableCoverage(): void // 4.0.0createCoverageProvider若配置中启用了coverage则创建覆盖率提供者。使用start或standalone运行测试时会自动完成。 ::: warning 如果coverage.clean未设为false此方法还会清除之前的所有报告见 coverage 配置。 :::enableCoverage为此后运行的测试启用覆盖率收集不运行任何测试仅设置 Vitest 收集覆盖率。若提供者尚不存在会创建新的。disableCoverage禁用此后测试的覆盖率收集。随机种子与其他工具getSeed4.0.0function getSeed(): number | null若测试以随机顺序运行返回随机种子否则返回null。clearCache5.0.0function clearCache(): Promisevoid删除所有 Vitest 缓存包括 fsModuleCache。在 Vitest 4.0.11 中它以实验性方法experimental_clearCache提供。experimental_getSourceModuleDiagnostic4.0.15实验性export function experimental_getSourceModuleDiagnostic( moduleId: string, testModule?: TestModule, ): PromiseSourceModuleDiagnostic返回模块的诊断信息。若未提供testModuleselfTime与totalTime会聚合到上次运行的所有测试。如果模块从未被转换或执行诊断为空。返回结构包括modules带ModuleDefinitionDurationsDiagnostic与untrackedModules两部分export interface SourceModuleDiagnostic { modules: ModuleDefinitionDurationsDiagnostic[] untrackedModules: UntrackedModuleDefinitionDiagnostic[] }每个诊断项包含start/end行列定位、startIndex/endIndex、url、resolvedId带时长的项还包含selfTime、totalTime与可选的external。UI 中的模块图、导入耗时分析即依赖这类数据。::: warning 目前不支持 browser 模式 下的模块诊断。 :::生命周期钩子onServerRestart、onCancel、onClose、onTestsRerun、onFilterWatchedSpecificationVitest 提供一组事件注册方法供集成方感知服务器与测试运行的状态变化实现集中在 core.ts 附近function onServerRestart(fn: OnServerRestartHandler): void function onCancel(fn: (reason: CancelReason) Awaitablevoid): () void function onClose(fn: () Awaitablevoid): void function onTestsRerun(fn: OnTestsRerunHandler): void function onFilterWatchedSpecification( fn: (specification: TestSpecification) boolean, ): voidonServerRestart服务器因配置变更而重启时调用。onCancel测试运行被cancelCurrentRun取消时调用。自 4.0.10 起onCancel实验性返回一个移除监听器的 teardown 函数4.1.0 起该行为视为稳定。onClose服务器关闭时调用。onTestsRerun测试重跑时调用。触发场景包括手动调用rerunTestSpecifications或文件变更后内建 watcher 调度重跑。onFilterWatchedSpecification文件变更时调用返回boolean表示该测试文件是否需要重跑。借此可以接入默认 watcher 逻辑延迟或丢弃用户当前不想跟踪的测试const continuesTests: string[] [] myCustomWrapper.onContinuesRunEnabled(testItem continuesTests.push(item.fsPath) ) vitest.onFilterWatchedSpecification(specification continuesTests.includes(specification.moduleId) )::: warning Vitest 可能针对同一文件基于pool或locations选项创建不同规格因此不要依赖引用相等性。vitest.getModuleSpecifications可能返回基于moduleId与pool的缓存规格而project.createSpecification总是返回新实例。 :::关闭与退出close、exit、shouldKeepServerfunction close(): Promisevoid function exit(force false): Promisevoid function shouldKeepServer(): booleanclose关闭所有项目及其关联资源。只能调用一次关闭 Promise 会被缓存直到服务器重启。exit关闭所有项目并退出进程。若force为true在关闭项目后立即退出进程。此外若在config.teardownTimeout毫秒后进程仍存活该方法会强制调用process.exit()。shouldKeepServer测试完成后服务器是否应保持运行通常意味着启用了watch模式。实战一个完整的编程式测试编排脚本综合以上 API一个典型的集成脚本如下——创建实例、提供上下文值、收集规格、运行测试并在结束时妥善关闭import { createVitest } from vitest/node const vitest await createVitest(test, { watch: false, // 关闭隔离可显著加快 collectTests/collect 的非静态收集 isolate: false, }) // 向测试注入上下文值 vitest.provide(wsPort, 3000) // 收集所有测试规格同时填充规格缓存 const specifications await vitest.globTestSpecifications([src/**]) // 运行它们 const result await vitest.runTestSpecifications(specifications, true) // 更新失败/过时的快照可选 // await vitest.updateSnapshot() await vitest.exit()小结Vitest类把测试框架拆解为一组可编程的能力单元projects与getRootProject管理项目拓扑provide/getProvidedContext打通主线程与测试进程的数据通道globTestSpecifications系列方法实现测试发现与缓存start/standalone/runTestSpecifications控制执行createReport为报告器提供隔离的文件系统空间而onServerRestart、onCancel、onFilterWatchedSpecification等钩子让第三方工具能无缝嵌入 Vitest 的事件流。无论是编写自定义报告器、构建 CI 编排脚本还是为编辑器实现持续运行的测试体验这份 API 都是 Vitest 编程式集成的核心契约。【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考