- 测试
- 前端
【免费下载链接】enzyme
JavaScript Testing utilities for React
.someWhere(predicate)是 Enzyme 为ReactWrapper提供的集合级断言方法,它接收一个谓词函数,遍历当前 wrapper 中包装的所有节点,只要至少有一个节点满足条件即返回true。本文以 someWhere 官方文档 为骨架,结合仓库源码 ReactWrapper.js 与共享测试 someWhere.jsx 的实现细节,帮助你掌握这一方法的参数语义、返回值、典型用法以及它与some、every、everyWhere三个兄弟方法之间的区别与配合方式。
方法签名与语义
.someWhere(fn) => BooleansomeWhere与内置数组方法Array.prototype.some语义一致:对 wrapper 中的每一个节点逐一执行谓词函数,只要其中任意一个节点的谓词返回真值,someWhere就返回true;只有所有节点都未通过谓词时才返回false。它回答的核心问题是:“当前这批节点里,是否存在满足某某条件的节点?”
从 ReactWrapper.js 的实现可以清晰看到这一点:
someWhere(predicate) { return this.getNodesInternal().some((n, i) => predicate.call(this, this.wrap(n), i)); }getNodesInternal()返回 wrapper 内部保存的节点数组(见 getNodesInternal 定义,即this[NODES]);- 数组的
.some()负责短路求值:一旦某个节点命中即停止遍历并返回true; - 每个原始节点
n会先经this.wrap(n)重新包装成ReactWrapper后再交给谓词,因此你在谓词里拿到的是完整的 ReactWrapper 实例,可以继续调用.hasClass()、.prop()、.text()等任意 API。wrap方法定义见 ReactWrapper.js,若节点已是ReactWrapper则直接复用,否则新建实例。
参数说明
someWhere仅接受一个参数:
| 参数 | 类型 | 说明 |
|---|---|---|
predicate | ReactWrapper => Boolean | 谓词函数,接收被包装后的单个节点(ReactWrapper)作为第一个参数,索引i作为第二个参数,返回布尔值(真值亦可) |
谓词内部的this指向调用someWhere的 wrapper 本身(源码中通过predicate.call(this, ...)绑定),这一点与forEach、map、reduce等方法保持一致,便于在需要时在谓词中访问外层 wrapper 的上下文。
返回值
- 返回
Boolean; true:当前 wrapper 中至少一个节点通过谓词;false:没有任何节点通过谓词,或当前 wrapper 不包含任何节点(空 wrapper 的.some()恒为false)。
使用示例
官方文档给出了一个直接可运行的断言示例,其中wrapper.find('.foo')得到包含 3 个<div>节点的 wrapper,再用.someWhere对这批节点逐一进行hasClass判断:
const wrapper = mount(( <div> <div className="foo qoo" /> <div className="foo boo" /> <div className="foo hoo" /> </div> )); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('qoo'))).to.equal(true); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('foo'))).to.equal(true); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('bar'))).to.equal(false);执行逻辑推演:
wrapper.find('.foo')命中 3 个节点(foo qoo、foo boo、foo hoo);(n) => n.hasClass('qoo'):只有第一个节点命中,.some()短路返回true;(n) => n.hasClass('foo'):所有节点都含foo类,任意一个即返回true;(n) => n.hasClass('bar'):没有任何节点含bar类,返回false。
这三个断言用例与仓库共享测试 someWhere.jsx 中的用例完全一致,该测试同时被ReactWrapper-spec与ShallowWrapper-spec复用,验证了两种 wrapper 上的行为一致性。
谓词的组合用法
由于谓词拿到的是完整ReactWrapper,你可以用逻辑运算符组合出更复杂的条件,例如同时满足多个特征、或满足任一特征:
// 是否存在同时含 active 且被禁用的按钮 expect(wrapper.find('button').someWhere((n) => n.hasClass('active') && n.prop('disabled'))).to.equal(true); // 是否存在处于 loading 或 error 状态的区域 expect(wrapper.find('.panel').someWhere((n) => n.hasClass('loading') || n.hasClass('error'))).to.equal(true);结合索引参数i还可以做位置相关的判断,例如“是否存在第一个元素恰好是标题”:
expect(wrapper.find('li').someWhere((n, i) => i === 0 && n.text() === 'Title')).to.equal(true);与 some / every / everyWhere 的关系
官方文档在 “Related Methods” 中列出了三个关联方法,它们的核心差异在于判定依据是选择器还是谓词,以及判定粒度是“存在任一”还是“全部满足”:
| 方法 | 判定依据 | 语义 | 典型返回true的条件 |
|---|---|---|---|
.some(selector) | EnzymeSelector选择器 | 任一节点匹配选择器 | 至少一个节点匹配 |
.someWhere(predicate) | 谓词函数 | 任一节点通过谓词 | 至少一个节点通过 |
.every(selector) | EnzymeSelector选择器 | 所有节点匹配选择器 | 全部节点匹配 |
.everyWhere(predicate) | 谓词函数 | 所有节点通过谓词 | 全部节点通过 |
选择器版 vs 谓词版:some(selector)/every(selector)内部通过buildPredicate(selector)把选择器编译为谓词再交给数组方法(见 some 实现),适合规则简单的类名、标签、属性匹配;someWhere/everyWhere则直接接收函数,能够表达选择器难以覆盖的逻辑判断(跨 prop 条件组合、文本内容匹配、索引判断等),灵活性更高。两种方式在空 wrapper 上的语义也一致:some/someWhere返回false,every/everyWhere返回true(空集的全称量词)。
someWhere vs everyWhere:二者源码结构完全相同(.some与.every互换),是“存在量词”与“全称量词”的一对互补方法:
everyWhere(predicate) { return this.getNodesInternal().every((n, i) => predicate.call(this, this.wrap(n), i)); }见 everyWhere 实现。实际测试中,“至少一个失败”等价于“everyWhere(取反条件)为false”,但直接使用someWhere表达意图更直白。
注意:与
some(selector)在根节点上调用会抛出ReactWrapper::some() can not be called on the root错误不同,someWhere没有这一限制,对根节点调用同样是合法的,因为它以谓词函数而非选择器为判定依据。
ShallowWrapper 上的等价用法
someWhere同样存在于ShallowWrapper(浅渲染),其文档见 ShallowWrapper.someWhere,唯一区别是谓词参数类型为ShallowWrapper => Boolean,示例中只需把mount换成shallow:
const wrapper = shallow(( <div> <div className="foo qoo" /> <div className="foo boo" /> <div className="foo hoo" /> </div> )); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('qoo'))).to.equal(true); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('foo'))).to.equal(true); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('bar'))).to.equal(false);从 ShallowWrapper.js 可以看到,其实现与ReactWrapper完全同构。因此,无论在mount(完整渲染,适用于与 DOM 交互的集成测试)还是shallow(浅渲染,适用于组件单元测试)场景下,someWhere的 API 形态和断言语义保持一致,可以无缝切换。若需要了解mount与shallow各自的适用场景,可参考 api/mount 与 api/shallow。
小结
.someWhere(predicate)是 Enzyme 断言体系中“存在性 + 自定义逻辑”的组合:它借力原生数组的.some()实现短路求值,把每个节点包装回ReactWrapper交给谓词,因此可以自由组合hasClass、prop、text、索引等多种判断维度。搭配.everyWhere可以覆盖“任一”与“全部”两类集合断言需求;当判断规则足够简单时,some(selector)则是更轻量的选择。掌握这组方法,就能用简洁、可读的断言表达对多节点渲染结果的各种预期。
- 测试
- 前端
【免费下载链接】enzyme
JavaScript Testing utilities for React
相关推荐
es-toolkit/compat overSome:把多个条件函数合成一个"任一满足"谓词的 Lodash 兼容指南
es toolkit/compat overSome:把多个条件函数合成一个"任一满足"谓词的 Lodash 兼容指南 本篇技术指南围绕 es toolkit
前端后端lo 库 CountBy 函数详解:基于 Go 泛型谓词的条件计数
lo 库 CountBy 函数详解:基于 Go 泛型谓词的条件计数 CountBy 是 samber/lo(一个基于 Go 1.18+ 泛型的 Lodash 风
后端TBOOX/TBOX谓词函数:条件判断与过滤的逻辑封装
TBOOX/TBOX谓词函数:条件判断与过滤的逻辑封装 概述 在C语言开发中,条件判断和元素过滤是日常编程中频繁遇到的需求。TBOX作为一款跨平台的C语言基础库
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考