news 2026/9/20 13:36:31

Enzyme ShallowWrapper `.first()` 方法详解:将匹配节点集合缩减为第一个节点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Enzyme ShallowWrapper `.first()` 方法详解:将匹配节点集合缩减为第一个节点
  • 测试
  • 前端

【免费下载链接】enzyme

JavaScript Testing utilities for React

项目地址:https://gitcode.com/gh_mirrors/en/enzyme
点击查看免费下载

导读

.first()是 EnzymeShallowWrapper提供的高频便捷方法,用于将当前包装器所匹配的节点集合缩减为集合中的第一个节点,其行为等价于.at(0)。在浅渲染测试中,当你通过find得到一组匹配节点、却只需要断言或操作其中第一个时,.first()是最简洁的写法。读完本文,你将掌握.first()的返回语义、与.at(0)/.last()/.get(0)的等价关系、底层实现原理,以及配套的共享测试用例,从而在 enzyme 项目中写出更精炼、可读性更高的断言。

.first()方法签名与返回值

根据 docs/api/ShallowWrapper/first.md 的官方定义:

  • 签名.first() => ShallowWrapper
  • 语义:将匹配节点集合缩减为集合中的第一个节点,等价于.at(0)
  • 返回值:返回一个新的ShallowWrapper,它包装了当前节点集合中的第一个节点

.at(index)需要显式传入下标不同,.first()无需任何参数,直接作用于当前包装器内部持有的节点数组,适合在链式调用中直观表达"取第一个"的意图。

基本用法示例

原文档给出的示例非常简洁,适用于shallow渲染:

const wrapper = shallow(<MyComponent />); expect(wrapper.find(Foo).first().props().foo).to.equal('bar');

这里的关键点在于:wrapper.find(Foo)可能匹配到多个<Foo />节点,而.first()将结果缩减为第一个匹配的Foo,随后即可安全地调用.props()读取其 props 并断言。在 docs/api/ShallowWrapper/first.md 中,这一示例的核心链条为find → first → props

同样的方法在ReactWrappermount渲染)上也存在,见 docs/api/ReactWrapper/first.md:

const wrapper = mount(<MyComponent />); expect(wrapper.find(Foo).first().props().foo).to.equal('bar');

可见.first()ShallowWrapperReactWrapper两个包装器上行为一致,仅返回的包装器类型不同(ShallowWrapper/ReactWrapper)。

结合类选择器的多节点缩减

当同一选择器匹配多个节点时,.first()的"缩减"语义体现得最明显。仓库的共享测试 packages/enzyme-test-suite/test/shared/methods/first.jsx 给出了一个完整可运行的用例:

import React from 'react'; import { expect } from 'chai'; export default function describeFirst({ Wrap }) { describe('.first()', () => { it('returns the first node in the current set', () => { const wrapper = Wrap(( <div> <div className="bar baz" /> <div className="bar" /> <div className="bar" /> <div className="bar" /> </div> )); expect(wrapper.find('.bar').first().hasClass('baz')).to.equal(true); }); }); }

该测试通过Wrap抽象同时适配shallowmountWrap在 packages/enzyme-test-suite/test/_helpers/index.jsx 中按渲染方式注入)。渲染结构中有 4 个.bar节点,其中第一个同时带有baz类名。wrapper.find('.bar').first()返回包装第一个.bar节点的新包装器,因此.hasClass('baz')true。这个用例从行为层面验证了"缩减到第一个"的定义:即使后续三个节点都不含baz.first()也能准确命中集合首项。

底层实现:.first().at(0)

在源码层面,.first()的实现非常直观,见 packages/enzyme/src/ShallowWrapper.js#L1599-L1606:

/** * Returns a wrapper around the first node of the current wrapper. * * @returns {ShallowWrapper} */ first() { return this.at(0); }

其内部直接委托给.at(0)。而.at(index)的实现见 packages/enzyme/src/ShallowWrapper.js#L1585-L1597:

at(index) { const nodes = this.getNodesInternal(); if (index < nodes.length) { return this.wrap(nodes[index]); } return this.wrap([]); }

完整的调用链可以概括为:

  1. getNodesInternal()取出当前包装器内部维护的节点数组;
  2. 判断index(此处为 0)是否小于节点数组长度;
  3. 若存在,调用wrap(nodes[index])返回一个只包含该节点的新包装器;
  4. 若集合为空(index >= nodes.length),则返回包装空数组的ShallowWrapper

其中wrap的实现在 packages/enzyme/src/ShallowWrapper.js#L1663-L1668:若传入节点已是ShallowWrapper实例则原样返回,否则以当前包装器的ROOT为根新建ShallowWrapper。这意味着.first()返回的新包装器共享原包装器的根节点,后续的.props().hasClass().simulate()等操作都作用于这唯一的首节点。

ReactWrapper侧的实现完全一致,见 packages/enzyme/src/ReactWrapper.js#L1119-L1126,其first()同样返回this.at(0)

边界情况与链式调用建议

  • 空集合:当.find()未匹配到任何节点时,nodes.length === 0at(0)返回包装空数组的新包装器(this.wrap([]))。此时.first()返回的包装器length === 0,后续若直接调用.props()可能取到undefined。因此建议结合.exists()先判断是否存在匹配节点:

    const firstBar = wrapper.find('.bar').first(); if (firstBar.exists()) { // 安全读取 props }
  • .at(index)的等价关系:原文档明确指出.first()"just like.at(0)",二者在结果上完全等价,只是.first()在语义上更自解释。相关方法矩阵参见 docs/api/ShallowWrapper/at.md 与 docs/api/ShallowWrapper/last.md:

    方法等价调用返回内容
    .first().at(0)包装集合首节点的新ShallowWrapper
    .last().at(length - 1)包装集合末节点的新ShallowWrapper
    .at(index).first()/.last()的通用形式包装指定下标节点的新ShallowWrapper
    .get(index).at(index)相似直接返回 React 节点本身,而非包装器
  • 链式调用建议.first()常与findfindWhere等返回多节点的 API 配合,也可作为everyWheresomeWhere之外获取单节点的高频入口。由于它返回的是新包装器而非原包装器,链式操作不会污染原始结果,天然支持"取首个 → 断言 → 取下一个"的流程。

小结

.first()是 EnzymeShallowWrapper中"按位置缩减节点集合"最常用的便捷方法:无需参数即可取集合首节点,源码上直接委托.at(0)(ShallowWrapper.js),并通过wrap生成与当前包装器共享根节点的全新包装器。无论是配合find(Foo).first().props()读取首个匹配组件的属性,还是结合findWhere缩小查询范围后取首项断言,它都能显著提升测试链的可读性。结合本文引用的共享测试用例 first.jsx,你可以在自己的浅渲染测试中放心使用这一模式。

  • 测试
  • 前端

【免费下载链接】enzyme

JavaScript Testing utilities for React

项目地址:https://gitcode.com/gh_mirrors/en/enzyme
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 13:34:43

DMA技术与DMA控制器原理详解:从STM32实战到双缓冲与调试

简介&#xff1a;面向计算机组成原理、微机接口技术等课程学习者&#xff0c;DMA技术PPT课件系统梳理了直接内存访问的完整知识体系。内容涵盖DMA传送方式特点与操作过程&#xff0c;详细讲解DMAC的基本功能、内部结构、三种工作方式&#xff0c;并深入剖析8237A可编程DMA控制器…

作者头像 李华
网站建设 2026/9/20 13:33:52

Podman 构建加速指南:全面解析 `podman build --jobs` 并行阶段控制

Podman 构建加速指南&#xff1a;全面解析 podman build --jobs 并行阶段控制 【免费下载链接】podman Podman: A tool for managing OCI containers and pods. 项目地址: https://gitcode.com/gh_mirrors/po/podman --jobs 是 Podman 镜像构建与 Farm 构建中用于控制并…

作者头像 李华
网站建设 2026/9/20 13:30:24

抖音无水印批量下载:3 种任务的完整操作指南

抖音无水印批量下载&#xff1a;3 种任务的完整操作指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. 抖音批…

作者头像 李华
网站建设 2026/9/20 13:28:32

企业第一次报名戈壁挑战赛材料清单?四步走不踩坑

行政第一次接戈壁团建报名&#xff0c;最容易在材料上反复返工。玄奘文旅集团把报名流程跑成了标准动作&#xff0c;照着走就不踩坑。理想、坚持、超越、重生&#xff0c;是集团给每支队伍的精神坐标。二十多年保障经验、约60家执行分院、单日最高可执行交付约30000人、2019到2…

作者头像 李华
网站建设 2026/9/20 13:27:02

2026开发效率革命:6类AI工具实测盘点与选型指南

“2026年开发者必备6款AI工具&#xff0c;告别低效编码&#xff0c;全方位提升开发效率”——说实话&#xff0c;这种标题我平时是不太敢信的。过了三十岁之后&#xff0c;我对“十大神器”“必备清单”这类词天然过敏&#xff0c;因为大半都是拿了厂商预算是来收割流量的。但上…

作者头像 李华