enzyme ReactWrapper 的.length属性:统计包裹的 React 节点数量
【免费下载链接】enzymeJavaScript Testing utilities for React项目地址: https://gitcode.com/gh_mirrors/en/enzyme
.length是 enzyme 中ReactWrapper(以及ShallowWrapper)提供的一个只读属性,用于返回当前 wrapper 所包裹的 React 节点数量。在断言查询结果、判断元素是否存在、控制循环遍历范围等场景中,它是测试代码里最常用的基础能力之一。读完本文,你将掌握.length的语义、源码实现原理,以及它在 enzyme 测试套件中的典型用法。
属性签名
.length => numberlength是 wrapper 对象上的一个**属性(property)**而非方法,因此直接读取即可,不需要调用括号。
返回值
返回类型为Number,即当前 wrapper 内部节点列表(node list)中节点的总数。
| 场景 | 返回值 |
|---|---|
| 空 wrapper(未匹配到任何节点) | 0 |
| 包裹单个节点(最常见的根 wrapper 情况) | 1 |
通过find/children等匹配到多个节点 | 匹配到的节点数量 |
基本示例
根据 docs/api/ReactWrapper/length.md 中的官方示例:
const wrapper = mount(<div />); expect(wrapper.length).to.equal(1);mount(<div />)只渲染了一个根节点,因此wrapper.length为1。类似地,docs/api/ShallowWrapper/length.md 对shallow渲染也定义了完全相同的语义:
const wrapper = shallow(<div />); expect(wrapper.length).to.equal(1);源码实现:length 从何而来
length的值在 wrapper 创建或更新内部节点列表时被同步设置,核心逻辑位于两个 wrapper 的实现文件中。
以ReactWrapper为例,packages/enzyme/src/ReactWrapper.js#L84-L96 中的privateSetNodes函数负责统一管理内部节点数组,并在最后写入length:
function privateSetNodes(wrapper, nodes) { if (!nodes) { privateSet(wrapper, NODE, null); privateSet(wrapper, NODES, []); } else if (!Array.isArray(nodes)) { privateSet(wrapper, NODE, nodes); privateSet(wrapper, NODES, [nodes]); } else { privateSet(wrapper, NODE, nodes[0]); privateSet(wrapper, NODES, nodes); } privateSet(wrapper, 'length', wrapper[NODES].length); }可以看到:
- 当传入的
nodes为数组时,NODES保存整个数组,NODE指向第一个节点; - 当传入单个节点时,会被包装成
[nodes]单元素数组; - 无论哪种情况,
length始终等于内部节点数组NODES的长度,即length本质上是节点数组大小的镜像。
ShallowWrapper在 packages/enzyme/src/ShallowWrapper.js#L180-L189 中实现了同样的逻辑,因此两种渲染模式下.length的行为保持一致。
由于find、filter、children、parents等查询方法都会通过wrap()生成一个包裹了新的节点子集的新 wrapper(内部同样走privateSetNodes),所以这些查询结果的.length能准确反映匹配数量。
核心应用场景
1. 断言查询匹配数量
这是.length最典型的用途——验证find等选择器命中了预期的节点数。在 enzyme 官方测试套件中可以找到大量印证,例如 packages/enzyme-test-suite/test/shared/methods/find.jsx:
expect(wrapper.find('input')).to.have.lengthOf(2); expect(wrapper.find('button')).to.have.lengthOf(1); expect(wrapper.find(Foo)).to.have.lengthOf(2);packages/enzyme-test-suite/test/shared/methods/children.jsx 中也大量使用lengthOf校验children()的结果数量:
expect(wrapper).to.have.lengthOf(3); expect(wrapper.children()).to.have.lengthOf(1); expect(wrapper.children()).to.have.lengthOf(0);在 Chai 断言库中,既可以直接比较:
expect(wrapper.find('.foo').length).to.equal(3);也可以使用更语义化的lengthOf或length属性链:
expect(wrapper.find('.foo')).to.have.lengthOf(3);2. 判断元素是否存在
exists()方法的底层实现就基于length。在 packages/enzyme/src/ReactWrapper.js#L1156 中:
return arguments.length > 0 ? this.find(selector).exists() : this.length > 0;即无参调用时,exists()等价于判断length > 0。官方测试 packages/enzyme-test-suite/test/shared/methods/exists.jsx 也验证了这一点:
expect(wrapper.find('.bar').exists()).to.equal(false); expect(wrapper.find('.foo').exists()).to.equal(true);因此,以下两种写法在语义上等价:
// 写法一:直接读 length if (wrapper.find('.foo').length > 0) { ... } // 写法二:exists() if (wrapper.find('.foo').exists()) { ... }3. 约束单节点操作
不少依赖"单一节点"语义的 API 会检查length !== 1并抛出异常。例如 packages/enzyme/src/ReactWrapper.js#L1170-L1171 的single工具:
if (this.length !== 1) { throw new Error(`Method “${fnName}” is meant to be run on 1 node. ${this.length} found instead.`); }这意味着当你对find('.foo')(可能匹配 0 个或多个节点)的结果直接调用prop()、text()、getNode()(见 packages/enzyme/src/ReactWrapper.js#L162-L165)等单节点方法时,enzyme 会利用length提前给出明确报错。这也提醒我们:在调用这类方法前,可以先断言.length === 1。
4. 驱动遍历与聚合
map、forEach、reduce、some、every、at、slice等方法的遍历范围都以内部节点数组(即length对应的数组)为准,例如at(index)实现中的越界保护(packages/enzyme/src/ReactWrapper.js#L1113)与last()直接使用this.length - 1(packages/enzyme/src/ReactWrapper.js#L1134):
return this.at(this.length - 1);mount 与 shallow 下 length 的差异
两种渲染模式下.length的语义一致(都是"wrapper 包裹的节点数"),但根 wrapper 的典型取值可能不同:
mount(<Component />):真实挂载后,根 wrapper 包裹渲染出的根节点,通常为1;shallow(<Component />):浅渲染只渲染一层,根 wrapper 包裹组件本身对应的元素,通常也是1。
而无论哪种模式,一旦通过find、children、filter等产生多节点 wrapper,length即为实际匹配数。空匹配(如wrapper.find('.not-exist'))的length为0。
相关 API 与进一步阅读
- docs/api/ReactWrapper/find.md:选择器查询,结果 wrapper 的
length反映匹配数 - docs/api/ReactWrapper/children.md、docs/api/ReactWrapper/parents.md:遍历子节点/祖先,同样可用
length断言数量 - docs/api/ReactWrapper/exists.md:基于
length > 0的快捷判断 - docs/api/ReactWrapper/isEmpty.md:空 wrapper 判断
- docs/api/ReactWrapper/at.md、docs/api/ReactWrapper/last.md:依赖
length的索引访问 - docs/api/ShallowWrapper/length.md:浅渲染模式下语义相同的属性说明
小结
.length是 enzyme wrapper 最基础也最常用的只读属性,它直接镜像内部节点数组的长度,源码层面由privateSetNodes在节点更新时同步维护(packages/enzyme/src/ReactWrapper.js#L84-L96)。在编写测试时,用expect(wrapper.find(selector)).to.have.lengthOf(n)断言查询结果、用length > 0判断存在性,是既简洁又可靠的最佳实践。
【免费下载链接】enzymeJavaScript Testing utilities for React项目地址: https://gitcode.com/gh_mirrors/en/enzyme
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考