Nuxt 如何用 @nuxt/test-utils 配合 vitest 运行带 Nuxt 运行环境的单元测试?
2026/9/9 21:59:17 网站建设 项目流程

Nuxt 如何用 @nuxt/test-utils 配合 vitest 运行带 Nuxt 运行环境的单元测试?

【免费下载链接】nuxtThe full-stack Vue framework.项目地址: https://gitcode.com/GitHub_Trending/nu/nuxt

如果你的测试代码依赖 Nuxt 运行时——自动导入的 composable、#components别名、useRouter()app.vue里定义的插件——把它放进普通 Node 环境的 vitest 里跑不了。@nuxt/test-utils提供了一个nuxt测试环境:测试运行前会在happy-domjsdom环境中初始化一个全局 Nuxt app(包括运行你的插件和app.vue代码)。该环境目前只支持 vitest。

安装依赖

在 Nuxt 项目根目录安装。@nuxt/test-utils带有一系列可选 peer dependencies,可以按需选择:DOM 环境二选一(happy-domjsdom),测试运行器可选vitestcucumberjestplaywright等;playwright-core仅在你想用内置浏览器测试工具且不用@playwright/test时需要。

npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core

配置 vitest.config.ts

按 Testing 文档 的推荐结构,把测试分成三类:test/unit/放普通单元测试(Node 环境,速度快),test/nuxt/放依赖 Nuxt 运行时的测试,test/e2e/放端到端测试(普通 Node 环境)。保持 Nuxt 运行时环境与端到端测试分离对测试稳定性很重要。

创建vitest.config.ts,用@nuxt/test-utils/configdefineVitestProject声明 Nuxt 项目:

import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' export default defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['test/unit/*.{test,spec}.ts'], environment: 'node', }, }, { test: { name: 'e2e', include: ['test/e2e/*.{test,spec}.ts'], environment: 'node', }, }, await defineVitestProject({ test: { name: 'nuxt', include: ['test/nuxt/*.{test,spec}.ts'], environment: 'nuxt', }, }), ], }, })

defineVitestProject只用于 Nuxt 环境的测试;端到端测试应配置为普通test.environment: 'node'的项目。

如果不想按项目拆分、让所有测试默认跑在 Nuxt 环境,可以用更简单的defineVitestConfig

import { defineVitestConfig } from '@nuxt/test-utils/config' import { fileURLToPath } from 'node:url' export default defineVitestConfig({ test: { environment: 'nuxt', // 可选:设置 Nuxt 特定的环境选项 // environmentOptions: { // nuxt: { // rootDir: fileURLToPath(new URL('./playground', import.meta.url)), // domEnvironment: 'happy-dom', // 'happy-dom'(默认)或 'jsdom' // overrides: { // // 你想传入的其他 Nuxt 配置 // } // } // } }, })

配置时有两个前提:

  • 在 vitest 配置里导入@nuxt/test-utils时,package.json需要指定"type": "module",或者把配置文件改名为vitest.config.mts/.mjs
  • 可以用.env.test文件为测试设置环境变量。

可选步骤:在nuxt.config中加入@nuxt/test-utils/module,会给 Nuxt DevTools 增加 Vitest 集成,支持在开发时运行单元测试:

export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module', ], })

编写 test/nuxt/ 下的测试文件

test/nuxt/tests/nuxt/目录下的测试文件默认包含在 Nuxt app TypeScript 上下文中,能识别~/@/#imports等 Nuxt 别名,TypeScript 也能感知 Nuxt app 里的自动导入。

核心 helper 是mountSuspended:在 Nuxt 环境中挂载任意 Vue 组件,支持 async setup 和来自 Nuxt 插件的注入。它底层封装了@vue/test-utilsmount,选项对象接受@vue/test-utils的 mount 选项,另有两个 Nuxt 特有属性:route(初始路由,false表示跳过初始路由变更,默认/)和spy(是否 spy 组件 setup 状态,默认false)。下面的组件挂载示例来自文档,内联快照文本是文档示例输出,不是你项目必须得到的固定值:

import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } import { expect, it } from 'vitest' import { mountSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' it('can mount some component', async () => { const component = await mountSuspended(SomeComponent) expect(component.text()).toMatchInlineSnapshot( '"This is an auto-imported component"', ) })

整个仓库自身就是这样测试的:根目录 vitest.config.ts 用defineVitestProject声明了nuxt-universalnuxtenvironment: 'nuxt'的项目,测试文件如 test/nuxt/announcer.test.ts 中用mountSuspended挂载组合了NuxtRouteAnnouncerNuxtPage的组件,直接使用useRouternavigateTouseAnnouncer这些自动导入的 API 做断言。

其他常用 helper(均从@nuxt/test-utils/runtime导入):

  • renderSuspended:用@testing-library/vue在 Nuxt 环境中渲染组件,需自行安装该库并在 Vitest 配置中开启 testing globals;组件会渲染进<div id="test-wrapper"></div>
  • mockNuxtImport:mock Nuxt 的自动导入功能。注意它每个被 mock 的导入、每个测试文件只能使用一次——它实际是转换为vi.mock的宏,会被提升;需要在不同测试间切换实现时,配合vi.hoisted暴露 mock。
  • mockComponent:mock Nuxt 组件,第一参数是 PascalCase 组件名或相对路径。
  • registerEndpoint:创建返回 mock 数据的 Nitro endpoint,用于测试向 API 请求数据的组件;默认走GET,也可以传{ method, handler }对象指定其他方法。
  • 内置 DOM mock:intersectionObserver(默认true,创建无功能的 dummy class)和indexedDB(默认false,用fake-indexeddb创建可用 mock),在vitest.config.tsenvironmentOptions.nuxt.mock中配置:
import { defineVitestConfig } from '@nuxt/test-utils/config' export default defineVitestConfig({ test: { environmentOptions: { nuxt: { mock: { intersectionObserver: true, indexedDb: true, }, }, }, }, })

如果你的 Nuxt 环境测试文件不在test/nuxt/,可以在nuxt.config.ts中把它们加入 TypeScript 上下文(路径相对于生成的.nuxt/tsconfig.json):

export default defineNuxtConfig({ typescript: { tsConfig: { include: [ // this path is relative to the generated .nuxt/tsconfig.json '../test/other-nuxt-context/**/*', ], }, }, })

运行与验证

项目配置就位后,用--project参数挑选要跑的测试套件:

# Run all tests npx vitest # Run only unit tests npx vitest --project unit # Run only Nuxt tests npx vitest --project nuxt # Run tests in watch mode npx vitest --watch

nuxt 项目的测试跑在happy-domjsdom环境里。验证方式就是 vitest 的断言结果:测试文件里的expect断言通过即表示 Nuxt 环境初始化成功、被测组件/composable 行为符合预期。

限制与注意事项

  • Nuxt 测试环境目前只支持 vitest,其他运行时暂不可用。
  • 测试运行前已初始化全局 Nuxt app(包括插件和app.vue代码),因此要小心不要修改全局状态;如果必须修改,测后记得重置。
  • @nuxt/test-utils/runtime@nuxt/test-utils/e2e需要运行在不同测试环境中,不能用在同一个文件里。两者都要用时,把测试拆到不同文件:用// @vitest-environment nuxt注释按文件指定环境,或把运行时单元测试文件命名为.nuxt.spec.ts扩展名。
  • 使用defineVitestConfig(默认environment: 'nuxt')时,个别文件可以用// @vitest-environment node退出 Nuxt 环境,但文档明确不推荐这种混合环境:Nuxt 的 Vite 插件会运行,而 Nuxt 入口和nuxtApp未初始化,可能导致难以调试的错误。
  • 单元测试本身不应依赖 Nuxt 运行时特性(自动导入、composable);只有当单元测试导入源码(如~/utils/helpers)时才为它们添加 TypeScript 路径别名支持,不要为了 Nuxt 特有功能而加。

如果后续要升级到对真实构建产物和浏览器做端到端测试,同一篇 Testing 文档的 End-To-End Testing 章节描述了@nuxt/test-utils/e2esetup()配置(rootDirsetupTimeouthost等)与$fetchcreatePage等 API,支持 Vitest、Jest、Cucumber 和 Playwright 四种运行器。

【免费下载链接】nuxtThe full-stack Vue framework.项目地址: https://gitcode.com/GitHub_Trending/nu/nuxt

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询