使用 WebdriverIO 为 Vue 3 + Vite 项目编写组件测试:vite-vue-example 实战指南
【免费下载链接】webdriverioNext-gen browser and mobile automation test framework for Node.js项目地址: https://gitcode.com/GitHub_Trending/we/webdriverio
本文基于仓库内examples/wdio/vite-vue-example示例工程,讲解如何用 WebdriverIO 的 Browser Runner 为 Vue 3 + TypeScript + Vite 应用编写并运行组件级测试。通过阅读本文,你将掌握示例工程的目录结构与配置方式、runner: ['browser', ...]与 Vite 的整合原理、利用@testing-library/vue渲染组件并配合 WebdriverIO 原生命令断言交互的完整流程,以及为.vue文件提供 TypeScript 类型支持(Volar)的工程化做法。
示例工程概览
examples/wdio/vite-vue-example是一个"开箱即测"的 Vue 3 应用模板:它本身是标准的 Vite + Vue 3 + TypeScript 项目(使用<script setup>单文件组件),同时又内置了完整的 WebdriverIO 组件测试配置与用例。整个工程的结构如下:
examples/wdio/vite-vue-example/ ├── index.html ├── package.json ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts ├── wdio.conf.ts └── src/ ├── App.vue ├── main.ts ├── style.css ├── vite-env.d.ts ├── assets/vue.svg └── components/ ├── HelloWorld.vue └── HelloWorld.test.ts工程的package.json(examples/wdio/vite-vue-example/package.json)声明了"type": "module",即整个示例以 ESM 方式运行,其中 Vue 运行时依赖为vue: ^3.4.15,测试侧依赖则包括:
@testing-library/vue: ^8.0.1—— 在测试中渲染 Vue 组件的 Testing Library 适配层;@testing-library/jest-dom: ^6.2.0—— 提供 DOM 断言匹配器(toHaveText等);expect-webdriverio: ^6.0.9—— WebdriverIO 的扩展断言;mocha: ^10.8.2与@types/mocha—— 测试框架;@vitejs/plugin-vue: ^5.0.3与vite: ^6.4.3—— Vite + Vue 编译链路;typescript: ^5.3.3与vue-tsc: ^2.0.17—— 类型检查。
工程定义了三个 npm script:
"scripts": { "dev": "vite", "build": "vue-tsc && vite build", "preview": "vite preview", "wdio": "wdio run ./wdio.conf.ts" }其中build先用vue-tsc做全量类型检查再执行vite build,而wdio脚本直接指向wdio.conf.ts,即运行 WebdriverIO 测试的唯一入口命令:
npm run wdio用 Browser Runner 把 Vite 接进 WebdriverIO
示例的核心配置位于 examples/wdio/vite-vue-example/wdio.conf.ts。其中最关键的差异点在于runner配置不再是local,而是启用了 WebdriverIO 面向单元/组件测试的 Browser Runner:
import url from 'node:url' import viteConfig from './vite.config.js' const __dirname = url.fileURLToPath(new URL('.', import.meta.url)) export const config: WebdriverIO.Config = { specs: [ './src/**/*.test.ts' ], runner: ['browser', { viteConfig, rootDir: __dirname }], // ... }specs使用通配符./src/**/*.test.ts,约定测试文件与被测组件放在同一目录下、以.test.ts结尾;runner以数组形式传入选项对象:viteConfig复用工程根目录下的 vite.config.ts(内容就是标准的defineConfig({ plugins: [vue()] })),rootDir指向示例目录本身;- 由于工程是 ESM,配置里用
node:url的url.fileURLToPath计算__dirname,这是 ESM 下替代 CJS__dirname的惯用法。
从实现上看,Browser Runner 由 packages/wdio-browser-runner/src/index.ts 中的BrowserRunner类实现,它继承自@wdio/local-runner的LocalRunner。其构造器在检测到config.framework !== 'mocha'时会直接抛出FRAMEWORK_SUPPORT_ERROR——也就是说,Browser Runner 当前只支持 Mocha 框架,这也是本示例在framework: 'mocha'的原因。每次run()都会启动一个ViteServer,把测试文件以页面形式托管起来,并将服务地址写入runArgs.args.baseUrl(源码见 index.ts),浏览器随后加载该地址执行测试。
为了让测试在浏览器环境中跑起来,Browser Runner 会在 Vite 上叠加一层默认配置(见 packages/wdio-browser-runner/src/vite/constants.ts),例如:
configFile: false,避免默认加载项目 Vite 配置从而与用户传入的viteConfig冲突;server.host固定为localhost;- 开启
topLevelAwait插件,使测试文件里可以使用顶层 await; - 通过
optimizeDeps预先构建一批 CJS 依赖(如expect、ws、css-value、lodash.*等)以兼容浏览器端 ESM; - 对
@testing-library/vue使用 esbuild CommonJS 插件做转换。
这正是viteConfig与rootDir之外的隐式行为:用户提供的 Vite 配置负责"编译被测的 Vue 应用",Runner 的默认配置负责"让 WebdriverIO 与测试生态跑在浏览器里",两者合并后由 Vite 提供服务。
另外,types.ts 定义了BrowserRunnerOptions,除了示例中已用的viteConfig与rootDir外还支持:
preset:'react' | 'preact' | 'vue' | 'svelte' | 'lit' | 'solid' | 'stencil'框架预设,示例中没有使用预设而是显式传入viteConfig(源码中vue预设对应的依赖正是@vitejs/plugin-vue,见 vite/constants.ts);headless:是否以无头模式运行,默认在 CI 环境下自动为true;host:当浏览器跑在远端 Grid 时用于指定承载测试文件的机器地址,默认http://0.0.0.0;coverage:代码覆盖率相关设置;automock/automockDir:自动 mock 机制与 mock 目录,默认目录为./__mocks__。
其余 WebdriverIO 配置项
示例wdio.conf.ts的其余配置与常规 E2E 工程基本一致,值得逐项说明:
maxInstances: 10,全局最大并发实例数;而capabilities中又单独为每个 capability 覆写了maxInstances: 5,用于在 Selenium Grid 资源受限时限制同 capability 的并发数量;capabilities: [{ browserName: 'chrome' }],示例默认在 Chrome 中运行;注释里还演示了如何用excludeDriverLogs过滤 driver 会话日志;logLevel: 'info',日志级别可选trace | debug | info | warn | error | silent,也可通过logLevels按 logger 细粒度设置(如webdriver、@wdio/appium-service等);bail: 0,默认不因部分用例失败而中断整个运行;baseUrl: '',留空以便由 Runner 动态注入 Vite 服务地址;waitforTimeout: 10000,所有waitFor*命令的默认等待时间;connectionRetryTimeout: 120000与connectionRetryCount: 3,浏览器驱动/Grid 无响应时的重连超时与重试次数;services: [],本示例无需额外服务;framework: 'mocha',Mocha 是 Browser Runner 当前唯一支持的框架;reporters: ['spec'],使用 spec 报告器输出人类可读的进度与结果;mochaOpts: { ui: 'bdd', timeout: 60000 },采用 BDD 风格 API,单个用例超时 60 秒。
配置中还完整保留了 WebdriverIO 的钩子位点(onPrepare、onWorkerStart、beforeSession、before、beforeSuite、beforeTest、afterTest、afterSuite、afterCommand、onComplete、onReload等),均以注释形式给出参数签名,方便在此工程基础上扩展自定义服务与钩子逻辑。
组件测试用例:从渲染到交互断言
测试用例位于与组件同目录的 examples/wdio/vite-vue-example/src/components/HelloWorld.test.ts,它演示了"Testing Library 渲染组件 + WebdriverIO 原生命令交互 + jest-dom 断言"的组合模式:
import { expect, $ } from '@wdio/globals' import { render } from '@testing-library/vue' import * as matchers from '@testing-library/jest-dom/matchers' expect.extend(matchers as any) import Component from './HelloWorld.vue' describe('Vue Component Tests', () => { it('should do something cool', async () => { const { getByText } = render(Component) getByText('count is 0') const button = await $(getByText('count is 0')) await button.click() await button.click() getByText('count is 2') await expect(button).toHaveText('count is 2') }) })这段用例的执行链路非常清晰:
render(Component)通过@testing-library/vue把HelloWorld.vue挂载到测试环境的 DOM 中,返回查询工具集(此处只用getByText);getByText在找不到或找到多个匹配节点时都会抛错,起到校验作用;$(getByText('count is 0'))用 WebdriverIO 的全局选择器$把按钮包装成可交互的元素句柄——这里传入的既不是 CSS 选择器也不是 XPath,而是一个现成的 DOM 节点,WebdriverIO 会直接基于该节点创建元素对象;- 连续两次
await button.click()派发原生点击事件,触发 Vue 的响应式更新; getByText('count is 2')验证界面文本已随点击次数更新,再用@testing-library/jest-dom的toHaveText匹配器对按钮文本做断言。
对应的被测组件 src/components/HelloWorld.vue 是一个标准 Vue 3<script setup>SFC:通过defineProps<{ msg: string }>()声明msg属性,用ref(0)维护计数状态,按钮的@click="count++"每点击一次计数加一,从而让上述"点击两次后文本变为 count is 2"的断言成立。
这种"组件与测试同目录 +.test.ts命名"的组织方式配合specs: ['./src/**/*.test.ts'],使得新增一个组件时只需照抄该模式即可自动被测试框架发现,无需再维护单独的测试清单。
Vue 工程自身的构建与类型配置
除了测试配置,示例工程还展示了 Vue 3 + Vite 工程自身的两个要点。
其一,Vite 插件装配。vite.config.ts 只做了一件事:加载@vitejs/plugin-vue,保证.vue单文件组件能被 Vite 正确编译。这份配置同时被开发服务器(vite)、生产构建(vue-tsc && vite build)以及 WebdriverIO 的 Browser Runner 复用,实现了"一份构建配置,多处消费"。
其二,.vue导入的 TypeScript 支持。TypeScript 本身无法理解.vue单文件组件的类型信息,因此示例通过 src/vite-env.d.ts 做了一个 shim:
/// <reference types="vite/client" /> declare module '*.vue' { import type { DefineComponent } from 'vue' const component: DefineComponent<{}, {}, any> export default component }即所有*.vue导入默认被当作一个泛化的DefineComponent,从而在.ts/.test.ts文件中import Component from './HelloWorld.vue'不会报"找不到模块"的类型错误。与此同时 tsconfig.json 也把"*.vue"纳入了include列表("include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]),配合vue-tsc在build阶段做类型检查。
关于 Volar 的 Take Over 模式。原 README 中特别说明:如果你希望.vue导入能获得真实的组件 props 类型(例如在手动调用h(...)时得到 props 校验),可以启用 Volar 的 Take Over 模式——即在 VS Code 命令面板执行Extensions: Show Built-in Extensions,找到TypeScript and JavaScript Language Features并右键选择Disable (Workspace),然后通过Developer: Reload Window重载窗口。当默认 TypeScript 扩展被禁用后,Take Over 模式会自动启用。这是编辑器层面的类型增强手段,与上述vite-env.d.ts的运行时无关、只影响 IDE 体验;如果仅需要在编译层面让.vue导入不报错,保留 shim 声明即可。
运行测试与结果验证
在示例目录下执行:
npm install # 安装依赖(含 vue、vite、webdriverio 相关包) npm run wdio # 运行 wdio.conf.ts 中的配置WebdriverIO 会:按specs匹配到src/components/HelloWorld.test.ts→ 通过 Browser Runner 启动 Vite 服务、把测试文件编译成浏览器可执行的模块 → 拉起 Chrome 会话加载页面执行用例 → 以 spec reporter 输出结果。通过时控制台会显示用例should do something cool通过,同时afterTest/onComplete等钩子与expect-webdriverio断言会共同保证任何一次getByText('count is 2')或toHaveText失败都能让进程以非零码退出。
需要留意的是,Browser Runner 目前仅支持 Mocha 框架(见 packages/wdio-browser-runner/src/index.ts 对非 Mocha 框架的直接报错),且浏览器会话依赖本机的 Chrome/驱动环境;若在 CI 中运行,headless选项会默认启用。
从示例到自有项目:三步迁移
对照本示例,把一个普通 Vue 3 + Vite 项目接入 WebdriverIO 组件测试只需三步:
- 补依赖:安装
@testing-library/vue、@testing-library/jest-dom、expect-webdriverio、mocha、@types/mocha,并在 package.json 中增加"wdio": "wdio run ./wdio.conf.ts"脚本; - 写配置:参照示例创建
wdio.conf.ts,核心是runner: ['browser', { viteConfig, rootDir }]+framework: 'mocha'+specs: ['./src/**/*.test.ts']; - 加用例:在与组件同目录新建
*.test.ts,用render渲染组件、$定位交互节点、expect(...).toHaveText(...)断言结果。
由此获得的组件测试无需额外启动被测应用、无需维护繁琐的定位器,即可在真实浏览器中对 Vue 组件的渲染结果与交互行为做端到端验证,且天然复用了工程既有的 Vite 构建配置。
【免费下载链接】webdriverioNext-gen browser and mobile automation test framework for Node.js项目地址: https://gitcode.com/GitHub_Trending/we/webdriverio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考