
Detox Expect API 完整指南从元素匹配到状态断言的端到端实战【免费下载链接】DetoxGray box end-to-end testing and automation framework for mobile apps项目地址: https://gitcode.com/gh_mirrors/de/DetoxDetox 的 Expect API 是移动端灰盒gray box端到端测试中的断言层它借助 Matchers 定位 UI 元素再对元素的可见性、存在性、文本、标签、数值等状态进行校验。本文以 Detox 仓库中 APIRef.Expect.md 文档为骨架结合 expectTwo.js 与 NativeExpect.js 的源码实现系统讲解全部断言方法、not取反、withTimeout轮询等待机制以及已废弃方法的迁移路径帮助你写出稳定、可维护的 UI 断言代码。Expect 在 Detox 中的定位Detox 的测试 API 可以划分为三个彼此衔接的环节匹配Matching使用by.id()、by.text()、by.label()等 Matchers 定位 UI 元素参见 APIRef.Matchers.md断言Expectation使用expect(element(...)).toBeVisible()等断言验证元素处于预期状态即本文主题交互Action使用tap()、typeText()、scroll()等模拟用户操作参见 APIRef.ActionsOnElement.md。从源码结构看三者在 expectTwo.js 中由Element、Expect、WaitFor三个类分别承载而expect()、element()、waitFor()三个工厂函数负责将它们串起来。所有断言最终都会序列化为一条 JSON 格式的 invocation调用通过 websocket 发送给运行在模拟器/真机上的测试驱动进程执行。断言方法一览Detox 的 Expect API 共提供 9 个正向断言方法、1 个取反修饰符和 1 个超时控制方法方法作用.toBeVisible()元素至少有 N% 区域可见于屏幕.toExist()元素存在于当前 UI 层级树中.toBeFocused()元素当前处于聚焦状态.toHaveText(text)元素文本等于指定文本.toHaveLabel(label)元素的无障碍标签iOS或内容描述Android匹配.toHaveId(id)元素的无障碍标识符匹配.toHaveValue(value)元素的无障碍数值匹配.toHaveSliderPosition(position, tolerance)Slider 的归一化位置在容差范围内.toHaveToggleValue(value)开关/复选框处于开启或关闭状态.not对后续断言取反.withTimeout(timeout)在指定毫秒内轮询等待断言满足toBeVisible()期望视图在屏幕上至少有 N% 的区域可见。可选参数percent为可见性阈值取值范围 1100 的整数不传时默认 75%。await expect(element(by.id(UniqueId203))).toBeVisible(); await expect(element(by.id(UniqueId204))).toBeVisible(35);使用not取反后期望视图的可见面积小于N%。在 iOS 上可见定义为视图本身或其某个子视图位于该视图激活点activation point在屏幕上的最顶层。参数校验在 expectTwo.js 中完成percent必须是 1100 的安全整数否则抛出percent must be an integer between 1 and 100错误对应测试见 expectTwo.test.js 中toBeVisible() should throw with bad args用例。toExist()期望元素存在于 App 当前的 UI 层级树中常用于校验动态加载的组件是否已挂载await expect(element(by.id(UniqueId205))).toExist();toBeFocused()期望元素是当前聚焦元素典型场景是校验输入框焦点await expect(element(by.id(textFieldId))).toBeFocused();toHaveText(text)期望元素包含指定文本。在 React Native 中通常对应Text组件的文本内容await expect(element(by.id(UniqueId204))).toHaveText(I contain some text);在 expectTwo.js 的toHaveText实现中参数既可以是字符串也可以是正则表达式内部通过isRegExp(text)判断并将正则标记随 invocation 一并下发便于原生侧做正则匹配。toHaveLabel(label)期望元素具有指定的无障碍标签iOS 上为 accessibility labelAndroid 上为 content description。在 React Native 中对应accessibilityLabelpropawait expect(element(by.id(UniqueId204))).toHaveLabel(Done);平台差异注意iOS 与 Android 对 accessibility label 的实现存在不一致——在 iOS 上如果某个 View 没有显式定义accessibilityLabel它会默认使用其子 View 的 accessibilityLabel 拼接结果而在 Android 上同样的 View 将完全没有 accessibilityLabel。编写跨平台测试时需留意这一行为差异。toHaveId(id)期望元素具有指定的无障碍标识符。在 React Native 中对应testIDprop在原生 iOS 中对应accessibilityIdentifierawait expect(element(by.text(I contain some text))).toHaveId(UniqueId204);toHaveValue(value)期望元素具有指定的无障碍数值。在 React Native 中对应accessibilityValueprop。典型场景如校验温度调节旋钮的数值await expect(element(by.id(UniqueId533))).toHaveValue(0);toHaveSliderPosition(normalizedPosition, tolerance)期望 Slider 元素位于指定的归一化位置取值范围 [0, 1]第二个可选参数tolerance用于吸收 iOS 上的浮点舍入误差await expect(element(by.id(slider))).toHaveSliderPosition(0.75); await expect(element(by.id(slider))).toHaveSliderPosition(0.3113, 0.00001);从 expectTwo.js 源码看tolerance的默认值为0对应的 JSON 序列化测试见 expectTwo.test.js 中toHaveSliderPosition用例期望的 invocation 结构包含expectation: toHaveSliderPosition及其参数数组。toHaveToggleValue(value)期望开关类元素如 Switch、CheckBox处于开/勾选或关/取消勾选状态。在 React Native 中对应 Switch 组件await expect(element(by.id(switch))).toHaveToggleValue(true); await expect(element(by.id(checkbox))).toHaveToggleValue(false);在 iOS 实现中toHaveToggleValue会先将参数强制转为数值Number(value)再下发与原生侧布尔表达保持一致。not断言取反not修饰符会对紧随其后的断言取反语义与代码可读性均优于旧式toBeNotXxx系列方法await expect(element(by.id(UniqueId533))).not.toBeVisible();实现上Expect类的notgetter 会把not推入this.modifiers数组expectTwo.js最终随 invocation 的modifiers字段下发Android 侧则由NativeExpect的notgetter 设置_notCondition trueNativeExpect.js。被取反的断言在原生侧执行反向匹配语义——例如not.toBeVisible()期望可见面积小于阈值而非简单地消失。withTimeout()轮询等待withTimeout(timeout)会在指定时间毫秒内持续轮询直到断言满足若超时仍未满足则断言失败await waitFor(element(by.id(UniqueId204))).toBeVisible().withTimeout(2000);关键点withTimeout只能与waitFor()搭配使用不能直接接在expect()之后从 detox.d.ts 的类型注释可见每次waitFor调用都必须通过withTimeout()设置超时否则轮询不会执行任何操作expectTwo.js 中WaitFor类通过InternalExpect先把断言构造成 invocation再由waitForWithTimeout将timeout合并进 invocation 结构{ ...action, ...expectation, timeout }后一次性执行WaitFor还支持whileElement(matcher).scroll(...)这种反复执行滚动直到断言满足的复合用法是处理列表懒加载场景的利器。waitFor属于手动同步手段仅应在 Detox 自动同步无法覆盖的少数场景如等待长时间运行的动画下使用优先依赖 Detox 内建的应用空闲同步机制。已废弃方法及迁移以下三个旧式断言方法已标记为Deprecated新代码应改用not修饰符已废弃方法替代写法.toBeNotVisible().not.toBeVisible().toNotExist().not.toExist().toBeNotFocused().not.toBeFocused()// 旧写法已废弃 await expect(element(by.id(UniqueId205))).toBeNotVisible(); await expect(element(by.id(RandomJunk959))).toNotExist(); await expect(element(by.id(textFieldId))).toBeNotFocused(); // 新写法 await expect(element(by.id(UniqueId205))).not.toBeVisible(); await expect(element(by.id(RandomJunk959))).not.toExist(); await expect(element(by.id(textFieldId))).not.toBeFocused();在 expectTwo.js 中旧方法实现上只是this.not.toXxx()的语法糖detox.d.ts类型定义同样为它们标注了deprecated注释。另需注意旧文档示例中toBeNotFocused()的用法示例存在笔误示例写成了toBeFocused()实际应调用toBeNotFocused()。底层实现断言如何被序列化并执行理解断言底层机制有助于排查断言不生效类问题。以 iOS 侧 expectTwo.js 为例一次断言经历以下链路expect(element)工厂函数校验入参必须是Element实例然后返回Expect对象调用.toBeVisible()等方法后createInvocation()将断言组装为 JSON 结构{ type: expectation, predicate: this.element.matcher.predicate, // 元素匹配器谓词 atIndex: this.element.index, // 可选元素索引 modifiers: [not], // 可选取反标记 expectation: toBeVisible, // 断言名 params: [35] // 可选断言参数 }_executeInvocation()通过traceInvocationCall包装后调用invocationManager.execute(invocation)将 invocation 通过 websocket 下发至设备端执行测试运行期间每个断言都会附带一条 trace description用于失败时的调用栈裁剪与日志输出参见 invocationTraceDescriptions.js。Android 侧实现路径类似但更贴近 EspressoNativeExpect.js 的每个方法都会构造一个对应的原生匹配器如VisibleMatcher、ExistsMatcher、TextMatcher、ToggleMatcher、SliderPositionMatcher、FocusMatcher再交给MatcherAssertionInteraction执行_notCondition控制取反语义。两个平台的断言命名与参数约定保持一致因此同一套测试代码通常可跨平台复用。仓库中还提供了 expectTwo.test.js 与 AndroidExpect.test.js 等单元测试覆盖了断言 JSON 结构、参数校验、not组合、waitFor超时等关键行为是深入理解 Expect API 行为的权威参考。实战建议优先用by.id()定位toHaveId/toExist/toBeVisible组合最稳定避免依赖文本布局变化可见性阈值按需调整元素被遮挡、部分滚动出屏幕时可降低toBeVisible阈值如35来容忍局部可见列表加载用waitForwithTimeout懒加载列表断言先waitFor(...).toExist().withTimeout(5000)必要时配合whileElement(...).scroll()迁移旧 API在代码库中全局替换toBeNotVisible、toNotExist、toBeNotFocused为not写法避免触发弃用警告。【免费下载链接】DetoxGray box end-to-end testing and automation framework for mobile apps项目地址: https://gitcode.com/gh_mirrors/de/Detox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考