react-native-windows 端到端测试实战:基于 WinAppDriver + WebDriverIO + Jest 的 e2e-test-app 体系
【免费下载链接】react-native-windowsA framework for building native Windows apps with React.项目地址: https://gitcode.com/gh_mirrors/re/react-native-windows
端到端测试是验证 react-native-windows 原生视图组件、交互行为与视觉渲染正确性的关键手段。本文基于仓库内 docs/e2e-testing.md 展开,围绕packages/e2e-test-app-fabric测试工程,完整讲解环境准备、测试运行、用例编写、快照测试与 CI 调试,并结合@react-native-windows/automation、automation-commands等源码包揭示底层运行机制。读完本文,你将掌握如何在本仓库中构建测试应用、编写针对 RNTester 示例页的 E2E 用例、进行视觉树与像素级快照比对,并在本地或 CI 中定位失败。
e2e-test-app 工程结构
E2E 测试应用、测试库与测试用例统一位于packages/e2e-test-app-fabric(对应仓库docs/e2e-testing.md中所称的 e2e-test-app),目录组织如下:
test—— 基于 Jest 与 WebDriverIO 编写的端到端测试用例,全部测试文件均以*.test.ts/*.test.js命名,例如 visitAllPages.test.ts、ViewComponentTest.test.ts;windows—— UWP/WinAppSDK 原生应用工程(RNTesterApp-Fabric),包含.sln、.vcxproj、.appxmanifest等原生工程文件;- jest.config.js —— Jest 与 WebDriverIO 的统一配置入口,
testEnvironment指向自定义环境@react-native-windows/automation。
测试用例所依赖的辅助包包括:自定义 Jest 测试环境 @react-native-windows/automation(负责拉起 WinAppDriver、启动应用、建立 WebDriver 会话与 RPC 通道)、测试命令库 @react-native-windows/automation-commands(提供dumpVisualTree、createScreenshot等命令)、以及 Windows 版 RNTester 页面集 @react-native-windows/tester。
环境准备与运行测试
安装 WinAppDriver v1.2.1
E2E 测试依赖 WinAppDriver v1.2.1。若使用仓库提供的依赖脚本 vnext/Scripts/rnw-dependencies.ps1 并以rnwDev为参数执行,WinAppDriver 会被自动安装。
测试默认假设 WinAppDriver 安装在默认位置:
C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe若安装到其他路径,必须在 jest.config.js 的testEnvironmentOptions中显式指定winAppDriverBin:
module.exports = { // ... testEnvironmentOptions: { // ... winAppDriverBin: 'D:\\Program Files (x86)\\Windows Application Driver\\WinAppDriver.exe', }, };从 AutomationEnvironment.ts 的源码可见,环境构造时优先读取winAppDriverBin,否则回退到PROGRAMFILES(X86)环境变量下的默认路径;若该路径不存在会直接抛出Could not find WinAppDriver at searched location错误,因此路径配置错误会在测试启动阶段立即暴露。
构建原生测试应用
C:\repo\react-native-windows> cd packages\e2e-test-app-fabric C:\repo\react-native-windows\packages\e2e-test-app-fabric> yarn windows --no-launchyarn windows对应 package.json 中的"windows": "npx @react-native-community/cli run-windows",--no-launch表示仅构建不启动应用。此外还可使用yarn bundle:debug生成调试用的 JS bundle(输出到windows/x64/Debug/RNTesterApp-Fabric/Bundle)。
运行全部测试
C:\repo\react-native-windows\packages\e2e-test-app-fabric> yarn start C:\repo\react-native-windows\packages\e2e-test-app-fabric> yarn e2etestyarn start启动 Metro 打包服务(对应脚本"start": "npx @react-native-community/cli rnx-start");yarn e2etest实际执行npx @react-native-community/cli rnx-test --platform windows,即以 Windows 平台运行 Jest 测试。
运行单个测试
C:\repo\react-native-windows\packages\e2e-test-app-fabric> yarn start⚠ 只传入测试文件名(不含其余路径部分)。
C:\repo\react-native-windows\packages\e2e-test-app-fabric> yarn e2etest visitAllPages.test.ts单个测试文件通过testRegex(见 jest.config.js 中的'.*\\.test\\.ts$'、'.*\\.test\\.js$')匹配,因此直接传文件名即可筛选。
应用启动时中断(Break on start)
C:\repo\react-native-windows\packages\e2e-test-app-fabric> yarn start C:\repo\react-native-windows\packages\e2e-test-app-fabric> yarn e2etest:debug visitAllPages.test.tsyarn e2etest:debug对应脚本"e2etest:debug": "npx @react-native-community/cli rnx-test --platform windows --config ./jest.debug.config.js"。查看 jest.debug.config.js 可知,它只是在基础配置上设置了testEnvironmentOptions.breakOnStart = true;结合 AutomationEnvironment.ts 的实现,测试环境在建立 WebDriver 会话、应用窗口就绪后会以readlineSync.question阻塞并提示Breaking before tests start / Press Enter to resume...,方便你在此刻手动检查应用状态或附加调试器。
测试配置项详解
以下配置来自 jest.config.js,并对应 AutomationEnvironment.ts 中EnvironmentOptions的字段定义:
| 配置项 | 当前值 | 含义与取值范围 |
|---|---|---|
app | 'RNTesterApp-Fabric' | 要启动的应用,可为 exe 路径或包标识名;源码要求必填,否则环境构造直接抛错 |
useRootSession | true | 使用 Root(Desktop)会话再搜索应用窗口,打包的 WinAppSDK 应用必须开启 |
rootLaunchApp | true | 使用 Root 会话时是否仍由环境负责启动/关闭应用,设为false可挂接到已运行的实例 |
enableAutomationChannel | true | 是否启用自动化 RPC 通道(默认端口 8603,可用automationChannelPort修改),用于ListErrors等命令 |
winAppDriverBin | 未设置 | WinAppDriver 可执行文件路径,默认C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe |
breakOnStart | false | 测试开始前是否中断等待回车,调试时由jest.debug.config.js开启 |
webdriverOptions | 注释掉 | 透传给 WebDriverIO 的RemoteOptions,例如logLevel |
appArguments/appWorkingDir | 未设置 | 启动应用时附加的命令行参数与工作目录 |
环境中的其他关键默认值(源码 AutomationEnvironment.ts):WebDriver 服务地址为127.0.0.1:4723,waitforTimeout默认 30 秒,connectionRetryTimeout默认 30 秒,connectionRetryCount默认 5 次;会话能力会附加ms:experimental-webdriver: true。同时 jest.config.js 中maxWorkers: 1保证串行执行,testTimeout: 70000(70 秒)作为单测例超时。
CI 中的测试调试
提高日志详细程度
默认情况下,测试只打印 WinAppDriver 返回的错误与断言失败信息。若想看到逐条 WebDriver wire 命令,可编辑 jest.config.js 的testEnvironmentOptions.webdriverOptions:
module.exports = { // ... testEnvironmentOptions: { // ... webdriverOptions: { // Level of logging verbosity: trace | debug | info | warn | error logLevel: 'error', // ... }, }, };logLevel支持trace | debug | info | warn | error五档,trace最详细。该配置最终通过Object.assign合并进 WebDriverIO 的RemoteOptions(见 AutomationEnvironment.ts),因此也可以在webdriverOptions中覆盖waitforTimeout、connectionRetryTimeout等行为。
测试产物(Artifacts)
在 AzureDevOps 流水线中可获取以下构建产物用于排查崩溃与失败:
- 测试失败时应用的错误截图(error screenshots);
- test run XML—— 包含失败的 wdio 测试名与 JS 堆栈信息;
- 树转储输出(tree dump outputs)—— 可将失败分支的输出与主干(main)分支对比,定位导致测试失败的差异;
- e2e 测试应用(RNTesterApp)的崩溃转储(crash dumps)。
在 PR 对应的 AzureDevOps 运行中点击 artifacts 链接即可访问:
架构:三层协作
E2E 测试体系由三个组件协作完成,职责清晰:
WinAppDriver
WinAppDriver 使用 Windows UI Automation(UIA)来检查和操作被测应用,并对外暴露 W3C WebDriver 协议,使任意 WebDriver 客户端都能与之通信。测试过程中由 AutomationEnvironment.ts 负责将其作为子进程拉起(监听标准输出中的Press ENTER to exit.判定就绪),结束后以SIGINT关闭。
WebDriverIO
WebDriverIO 是 JavaScript 库,通过 WebDriver 协议连接 WinAppDriver。它提供查询应用 UI 树的全局 API(选择器)以及全局browser对象用于操作被测应用。测试环境中这些全局量被显式绑定到当前浏览器会话:this.global.browser = this.browser、this.global.$ = this.browser.$.bind(...)等(见 AutomationEnvironment.ts)。
Jest
Jest 是端到端测试的测试运行器,负责断言库、用例选择(testRegex)、超时与快照管理等。WebDriverIO 的设置由自定义环境 @react-native-windows/automation 提供(testEnvironment: '@react-native-windows/automation')。环境在setup()阶段依次完成:启动 WinAppDriver → 建立 Root 会话并轮询应用窗口(超时 5 分钟)→ 用真实窗口句柄替换appTopLevelWindow→ 建立 WebDriver 会话 →(可选)建立 automation channel RPC 连接;teardown()阶段则关闭 RPC 客户端、关闭窗口并结束会话。
编写测试用例
测试使用 Jest + WebDriverIO 编写,针对运行着RNTester的测试应用执行;RNTester示例页被作为测试 UI,由 Jest 测试逐一检查。测试应优先复用已有的RNTester页面,仓库中也存在只被 e2e-test-app-fabric 使用的 "Legacy" 自定义页面(见 test 目录 下的LegacyControlStyleTest.test.ts、LegacyImageTest.test.ts等)。
针对 RNTester 示例页编写测试
// LegacyControlStyleTestPage.test.ts describe('FancyWidget', () => { beforeAll(async () => { await goToComponentExample('FancyWidget'); }); test('FancyWidget is populated with placeholder', async () => { // Query for an element with accessibilityId of "foo" (see "locators" below) const field = await app.findElementByTestID('foo'); expect(await field.getText()).toBe('placeholder'); }); });其中goToComponentExample来自 RNTesterNavigation.ts:点击components-tab切换到 Components 标签页,在搜索框(explorer_search)输入示例名过滤列表后点击目标示例。源码特别处理了 WinAppDriver 对自定义 RN TextInput 输入时可能追加而非替换文本的问题——每次重试前先clearValue()再setValue()并校验输入内容(见 RNTesterNavigation.ts)。
app对象来自 AutomationClient.ts,该文件同时定义了常用的定位器(locators):
| 方法 | 底层选择器 | 用途 |
|---|---|---|
findElementByTestID(id) | $(`~${id}`) | 按testID/ AccessibilityId 查找 |
findElementByAutomationID(id) | $(`~${id}`) | 按 AutomationId 查找 |
findElementByClassName(className) | $(className) | 按控件类名查找(如ListViewItem) |
findElementByControlType(type) | $(`<${type} />`) | 按 ControlType 查找(如Button、CheckBox) |
findElementByXPath(xpath) | $(xpath) | 按 WinAppDriver 兼容 XPath 查找 |
此外app还提供窗口级操作:setWindowSize/setWindowPosition/getWindowSize/getWindowPosition、switchWindow以及通用等待waitUntil。返回的AutomationElement是对 WebDriverIO Element 的类型投影,包含click、getText、setValue、waitForDisplayed、isDisplayed、saveScreenshot等常用方法。
实际测试中常将窗口固定到固定位置与尺寸以避免元素不可点击(例如 visitAllPages.test.ts 中的setWindowPosition(0,0)与setWindowSize(1000,1250)),并在每个用例后用verifyNoErrorLogs()(见 Helpers.ts)通过 automation channel 调用ListErrors检查 JS 侧错误日志,实现“每页可访问 + 无红屏错误”的冒烟保障。
添加自定义 RNTester 页面
在新增自定义页面之前,请先评估能否直接修改已有的 RNTester 页面并向上游提交。如确需新增示例,可将其集成进 Windows 版 RNTester 分支 @react-native-windows/tester。文档推荐使用 Hooks 编写测试页面:
// ControlStyleTestPage.tsx export const title = 'LegacyControlStyleTest'; export const description = 'Legacy e2e test for Control Styles'; export const examples = [ { render: function(): JSX.Element { return <ControlStyleTestPage />; }, }, ];// RNTesterList.windows.js ... { key: 'LegacyControlStyleTest', module: require('../examples-win/LegacyTests/ControlStyleTestPage'), }, ...页面通过title/description/examples描述结构注册进 RNTester 列表;visitAllPages.test.ts会从@react-native-windows/tester/js/utils/RNTesterList动态读取全部 Components 示例并逐页生成用例(当前跳过Flyout、XAML、SwipeableCard三个已知不稳定页面,API 标签页用例被临时注释)。
快照测试(Snapshot Tests)
E2E 测试使用 Jest 的快照测试机制检测非预期的视觉变化。与针对 React 树做快照不同,e2e-test-app-fabric 比较的是完整渲染后的 composition 树,从而验证 ViewComponent 的渲染正确性:
import {dumpVisualTree} from '@react-native-windows/automation-commands'; test('Example test', async () => { const dump = await dumpVisualTree('test-id-here'); expect(dump).toMatchSnapshot(); });dumpVisualTree由 @react-native-windows/automation-commands 提供(实现见 dumpVisualTree.ts)。快照文件保存在 test/__snapshots__ 目录下,例如ViewComponentTest.test.ts.snap。
除了 composition 树快照,仓库还结合createScreenshot与jest-image-snapshot做了像素级截图对比:Helpers.ts 中的verifyElementVisualSnapshot先取元素位置与尺寸,再调用createScreenshot(见 screenshot.ts)截图到临时目录,最后toMatchImageSnapshot以failureThreshold: 0.01(1% 像素差异容忍度)比对;截图基线存于 test/__image_snapshots__,例如view-component-test-test-ts-view-tests-visual-snapshot-of-views-with-shadows-2-snap.png。ViewComponentTest.test.ts中即同时使用dumpVisualTree与verifyElementVisualSnapshot对阴影、边框、圆角、轮廓等样式进行双重校验。
更新快照有两种方式:
- 本地运行
jest --updateSnapshot(对应脚本yarn e2etest:updateSnapshots,即rnx-test --platform windows -u); - 从失败的 PR 上传的 "snapshots" 产物中复制新快照。
常见问题与排障要点
- 找不到 WinAppDriver:确认已安装 v1.2.1 且路径与
winAppDriverBin一致,环境构造阶段即会报错(AutomationEnvironment.ts)。 - 找不到应用窗口:打包的 WinAppSDK 应用需开启
useRootSession: true;环境会以 2 秒间隔轮询最多 5 分钟寻找Name === app的窗口,超时抛出Unable to find window(AutomationEnvironment.ts)。 - 元素点击不稳定:将窗口固定到屏幕内并设置固定尺寸(
setWindowPosition(0,0)、setWindowSize(1000,1250));列表过长时先用搜索框过滤,避免元素在可视区域外。 - 单测超时:默认
testTimeout为 70 秒,冷启动或慢机器上可适当调大。 - 快照大面积失败:先对比 tree dump 产物与主干分支的输出,定位差异来源后再决定是否更新快照。
以上全部内容均可在仓库中直接复现:环境与定位器实现见 packages/@react-native-windows/automation/src,测试命令与工具见 packages/@react-native-windows/automation-commands/src,完整用例见 packages/e2e-test-app-fabric/test。按“构建 → 启动 Metro → e2etest”三步即可在本仓库跑通整套 E2E 体系,为原生组件与渲染行为的回归验证提供可靠保障。
【免费下载链接】react-native-windowsA framework for building native Windows apps with React.项目地址: https://gitcode.com/gh_mirrors/re/react-native-windows
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考