十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AVA 快照报告文件(test.js.md)深度解析:报告格式、跳过测试时的快照保留与更新机制

AVA 快照报告文件(test.js.md)深度解析:报告格式、跳过测试时的快照保留与更新机制 AVA 快照报告文件test.js.md深度解析报告格式、跳过测试时的快照保留与更新机制【免费下载链接】avaNode.js test runner that lets you develop with confidence 项目地址: https://gitcode.com/gh_mirrors/ava/ava快照报告snapshot report是 AVA 快照测试体系中被大多数人忽略、却最有信息量的产物它是一份人类可读的.md文件忠实记录每个测试断言过的快照内容也是官方文档建议提交到版本库、用于 diff 审查的变更可视化层。本文以仓库中 test/snapshot-workflow/fixtures/skipping-test/test.js.md 这份真实的快照报告文件为骨架逐段拆解其格式规范并结合 lib/snapshot-manager.js 的源码与 test/snapshot-workflow/selection.js 的测试用例讲透当测试被test.skip跳过时--update-snapshots为什么不会破坏它的旧快照这一关键机制让你既能读懂报告文件也能安全地维护自己的快照测试。一、快照报告文件是什么AVA 双文件快照机制的人读层在 AVA 中一次快照断言会产出两个文件详见官方文档 docs/04-snapshot-testing.md*.snap实际快照数据文件供后续运行对比二进制格式机器可读*.md快照报告文件把快照内容以易读形式呈现在更新快照时重新生成。官方文档的原文是这样描述的The first file contains the actual snapshot and is required for future comparisons. The second file contains yoursnapshot report. Its regenerated when you update your snapshots. If you commit it to source control you can diff it to see the changes to your snapshot.也就是说.md报告的价值在于可提交进版本库通过 git diff 直观审查快照内容的变化。.snap负责能不能对上.md负责改了什么、长什么样。存储位置遵循如下规则若测试文件位于test/tests目录快照存放于同级snapshots目录若位于__tests__目录则存放于__snapshots__目录。例如测试文件~/project/test/main.js会生成~/project/test/snapshots/main.js.snap与~/project/test/snapshots/main.js.md两个文件。快照目录也可通过配置项snapshotDir固定指定见 docs/06-configuration.md。二、逐段拆解 test.js.md快照报告的完整格式本次关联文档 test/snapshot-workflow/fixtures/skipping-test/test.js.md 是仓库中一个跳过测试场景 fixture 的快照报告内容如下# Snapshot report for test.js The actual snapshot is saved in test.js.snap. Generated by AVA. ## foo Snapshot 1 { foo: one, } ## bar Snapshot 1 { bar: one, }这份报告虽然只有 20 行却完整覆盖了报告格式的全部要素元素示例含义一级标题# Snapshot report for \test.js| 声明该报告对应的测试文件test.js说明行The actual snapshot is saved in \test.js.snap.| 指明实际快照数据存放于同名.snap 文件生成标记Generated by AVA.报告由 AVA 自动生成测试块标题## foo、## bar按测试标题title分组每个测试一个二级标题块快照序号 Snapshot 1该测试下第 N 个快照断言从 1 开始快照内容4 空格缩进的序列化值即t.snapshot(...)断言的具体值把这份格式与源码对照可以确认每一行都是由 lib/snapshot-manager.js 中的generateReport()与combineEntries()生成的generateReport()约 L124-L134负责拼接头部# Snapshot report for \{relFile}、The actual snapshot is saved in{snapFile}. 、Generated by AVA. 三行然后追加各测试块的条目combineEntries()约 L105-L122按测试标题输出\n\n## {title}\n\n再为块内每个快照调用formatEntry()输出 Snapshot {index}与缩进后的值块与块之间用空行分隔报告文件命名在determineSnapshotPaths()约 L458-L463中确定reportFile \${name}.md、snapFile ${name}.snap其中name 是测试文件相对项目根目录的 basename。因此只要看到## 测试标题 Snapshot N 缩进值的三段式结构就能确定这是一份标准 AVA v3 快照报告。三、快照本体test.js.snap 的二进制格式报告文件说The actual snapshot is saved intest.js.snap那么.snap里到底是什么test/snapshot-workflow/fixtures/skipping-test/test.js.snap 是一个二进制文件其文件头以 ASCII 明文写着AVA Snapshot v3紧接着是压缩数据。对应源码lib/snapshot-manager.js版本常量const VERSION 3;L23注释明确编码布局或 Concordance 序列化版本变化时递增旧版 AVA 无法解码新版本生成的缓冲区因此该值变更意味着 AVA 需要主版本号提升可读前缀const READABLE_PREFIX Buffer.from(\AVA Snapshot v${VERSION}\n, ascii);[L29](https://link.gitcode.com/i/ce5d96c944ada79915224a42c02ccfcb#L29)解码器以换行字节0x0A 定位版本偏移版本号以 16 位无符号小端整数编码VERSION_HEADERL25-L26。encodeSnapshots()约 L205-L225展示了完整的编码流水线用 Concordance 对每个快照值做描述describe与序列化用cbor2编码器打包为二进制 CBOR 数据zlib.gzipSync()压缩并将 GZip 头部的操作系统字节强制覆盖为0x03Linux保证跨平台产出字节一致对压缩数据计算 SHA-256 摘要32 字节依次拼接可读前缀 2 字节版本头 32 字节 SHA-256 校验和 压缩数据。对应的extractCompressedSnapshot()约 L227-L252负责解码查找换行字节定位版本 → 校验版本号不匹配抛VersionMismatchError见 L50-L57→ 切片出压缩数据。此外还有对旧版 Jest 快照头的兼容检测// Jest Snapshot v1L66-L69遇到遗留格式会抛出LegacyError。写入时使用write-file-atomic原子写L411-L412避免半写文件损坏快照。测试侧对这份格式也有直接验证test/snapshot-workflow/helpers/macros.js 中的readSnapshots()调用extractCompressedSnapshot()取出压缩数据再用gunzipSync()解压并与.md报告一同参与断言比较——这正是.snap与.md双文件格式在真实测试中的用法。四、fixture 实战test.skip 跳过的测试如何保住旧快照现在回到这份报告的来源。test/snapshot-workflow/fixtures/skipping-test/test.js 的内容是const {default: test} await import(process.env.TEST_AVA_IMPORT_FROM); (process.env.TEMPLATE ? test : test.skip)(foo, t { t.snapshot({foo: one}); }); test(bar, t { t.snapshot({bar: one}); });这个 fixture 的精妙之处在于双模式运行当环境变量TEMPLATEtrue时foo以正常test声明执行用于初始化快照——即先生成包含foo、bar两个块的报告与快照当普通运行不设TEMPLATE时foo变成test.skipbar仍是正常测试——模拟用户把某个测试跳过的真实场景。test/snapshot-workflow/README.md 的 Invariants 一节对此有约定所有使用 fixture 的测试都必须以同一方式初始化等价于在 fixture 目录执行TEMPLATEtrue npx ava --update-snapshots否则会互相覆盖预期的初始状态。核心机制在快照管理器的skipBlock()中lib/snapshot-manager.js#L360-L366skipBlock(title) { const block this.oldBlocksByTitle.get(title); if (block) { this.newBlocksByTitle.set(title, block); } }逻辑非常直接当某个测试被跳过时AVA 会把旧快照块oldBlocksByTitle中该测试标题对应的块原封不动地放回新块集合newBlocksByTitle而不是丢弃。这样即使使用--update-snapshots被跳过测试的既有快照数据也会被完整保留。skipBlock的调用点位于 lib/runner.js 的start()中约 L406-L451覆盖三类情况未被选中的测试如--match过滤掉、.only排除的、被标记为skipped的测试均调用this.snapshots.skipBlock(task.title, task.metadata.taskIndex)后直接continue。此外还有skipSnapshot()lib/snapshot-manager.js#L368-L383用于单条t.snapshot.skip()场景它会从旧块中取出对应序号的快照并保留原 label注释明确不要假设 skip 参数格式良好。五、端到端验证selection.js 如何断言数据被保留上面的机制不是靠文档承诺而是被 test/snapshot-workflow/selection.js 中的集成测试锁定的test.serial( With --update-snapshots, skipping tests preserves their data, beforeAndAfter, { cwd: cwd(skipping-test), cli: [--update-snapshots], expectChanged: false, }, );注意expectChanged: false在--update-snapshots下运行这个 fixture断言.md报告与.snap快照均未发生变化——被跳过的foo保留了旧快照正常的bar的快照与旧值一致也没有改写。执行流程由 test/snapshot-workflow/helpers/macros.js 的beforeAndAfter宏驱动若测试以--update-fixture-snapshots参数运行则先以TEMPLATEtrue--update-snapshots在 fixture 目录执行一次生成/刷新初始快照状态readSnapshots()读取并解析.snap解压与.md得到 before 状态test/helpers/with-temporary-fixture.js 把 fixture 目录递归复制到临时目录保证每次测试互不污染在临时目录中以指定 CLI 参数这里是--update-snapshots运行 AVA再次读取 after 状态若expectChanged为真则断言两份文件都变化、并用cleanStringDiff()生成报告 diff 快照为假则断言两份文件与 before 完全一致。对照组 test/snapshot-workflow/fixtures/skipping-test-update/ 的 fixture 则把foo、bar的快照值都改成新值[something new]对应测试With --update snapshots and test.skip(), other tests\ snapshots are updated断言expectChanged: true——被跳过的foo数据依旧保留而正常测试bar的快照被正常更新。两个用例一正一反恰好框定了行为边界跳过只保护被跳过者的旧数据不影响其他测试的更新。六、实操指引何时使用 --update-snapshots结合官方文档 docs/04-snapshot-testing.md 与上文机制快照更新有一套清晰的实操约定快照断言失败时AVA 会在终端展示失败原因见下图官方文档配套截图确认变更是有意的再执行更新ava --update-snapshots-u是--update-snapshots的短别名只想更新某一个测试的快照时将--update-snapshots与--match或.only()组合使用。仓库测试对此同样有覆盖selection.js中With --update-snapshots and --match, only selected tests are updated--match foo与With --update-snapshots and line number selection, only selected tests are updatedtest.js:3-5行号选择两个用例均断言expectChanged: true验证只更新选中的测试且未选中的测试快照不会被误伤跳过skip是保护伞被test.skip跳过、或通过--match/行号/.only排除的测试其既有快照在更新时会被skipBlock()原样保留不会出现一更新就全删光的悲剧.snap与.md都会在更新时一起重写save()中writeFileAtomic原子写两份文件lib/snapshot-manager.js#L385-L416若更新时不存在任何新快照块则两份文件会被清理删除L388-L393。七、小结一份 20 行的test.js.md快照报告背后串联起 AVA 快照系统的完整设计generateReport()决定报告的人读格式encodeSnapshots()定义.snap的 v3 二进制编码可读前缀 版本 SHA-256 gzip CBORskipBlock()/skipSnapshot()保证跳过场景下的数据安全而selection.jsbeforeAndAfter宏则把这一切固化进集成测试。理解了这些你就能读懂任何一份快照报告、解释.snap文件头每个字节的含义并在引入test.skip或选择性更新时对快照行为心中有数。【免费下载链接】avaNode.js test runner that lets you develop with confidence 项目地址: https://gitcode.com/gh_mirrors/ava/ava创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表