- 测试
【免费下载链接】ava
Node.js test runner that lets you develop with confidence 🚀
The actual snapshot is saved inchanging-label.js.snap.
Generated by AVA.
报告中 `## foo` 小节对应测试标题,小节内的 `> Snapshot 1` 即快照的 **label**,随后是以 4 空格缩进展示的快照内容(concordance 序列化后的描述形式)。 ## 快照 label:默认规则与自定义语法 每个快照断言在报告中都有一个可读标签。从源码 `lib/snapshot-manager.js` 的 `formatEntry` 函数([lib/snapshot-manager.js#L90-L103](https://link.gitcode.com/i/d60314c743e33c6a9effa06358a815c4))可以看到默认 label 的生成规则: ```js label = `Snapshot ${index + 1}`, // Human-readable labels start counting at 1.即默认 label 按快照在测试内的出现顺序从 1 开始编号,形如Snapshot 1、Snapshot 2。同一小节(同一测试标题)下的多个快照通过序号区分。label 随后被逐行加上>前缀转换为引用块(blockquote)写入报告:
const blockquote = label.split(/\n/).map(line => '> ' + line).join('\n');因此> Snapshot 1是报告中对快照 #1 的可读标识,其序号与.snap文件中按 index 存储的快照数据一一对应(见recordSerialized,lib/snapshot-manager.js#L322-L339)。
除了默认编号,t.snapshot()断言接受可选的第二个参数作为自定义 label。工作流测试的 fixture(test/snapshot-workflow/fixtures/changing-label/test.js)演示了这一用法:
test('foo', t => { t.snapshot({foo: 'one'}, process.env.TEMPLATE ? undefined : 'a new message'); });当TEMPLATE=true时(模拟初始状态),调用t.snapshot({foo: 'one'}),label 采用默认值Snapshot 1;当以普通方式运行时,调用t.snapshot({foo: 'one'}, 'a new message'),label 被自定义为a new message。这个 fixture 正是为了模拟"用户修改了快照的 label"这一真实开发场景。
核心实验:label 变更在两种模式下的行为差异
test/snapshot-workflow/changing-label.js是围绕本快照报告设计的工作流测试,它通过test.serial声明了两个互相对照的用例(test/snapshot-workflow/changing-label.js):
| 测试用例 | 运行方式 | 预期结果 |
|---|---|---|
Changing a snapshot's label does not change the .snap or .md | 直接运行 AVA | expectChanged: false,.snap与.md均保持不变 |
With --update-snapshots, changing a snapshot's label updates the .snap and .md | 追加--update-snapshots标志 | expectChanged: true,.snap与.md均被更新 |
两个用例共用同一 fixture 目录changing-label,仅cli参数不同。这一对照设计精确揭示了 AVA 的快照更新语义:
关键结论 1:不传--update-snapshots时,label 变更不会改动任何快照文件。此时快照断言会因 label 变化而失败,但磁盘上的.snap与.md保持原样——失败是提示性的,需要开发者主动确认变更是否有意。
关键结论 2:传入--update-snapshots时,label 变更会同时刷新.snap与.md。快照数据被重新记录(携带新 label),报告按新 label 重新生成。
快照报告 diff 的解读
changing-label.js.md报告的正文部分记录了第二个用例的快照报告 diff,即beforeAndAfter宏在更新前后对.md报告内容做的对比(test/snapshot-workflow/helpers/macros.js):
## foo - > Snapshot 1 + > a new message { foo: 'one', }解读要点:
- > Snapshot 1表示更新前的旧报告使用默认 labelSnapshot 1;+ > a new message表示更新后的新报告使用自定义 labela new message;- 快照数据体
{foo: 'one'}在 diff 中保持不变——label 是独立于快照内容存储的元信息,更改 label 不触碰数据本身; - 报告中还有一处细微差异:旧报告标题为
# Snapshot report for \test.js`,因为 fixture 在临时目录中运行时被统一命名为test.js(参见readSnapshots读取test.js.snap与test.js.md` 的实现)。
beforeAndAfter宏(test/snapshot-workflow/helpers/macros.js#L28-L65)的执行流程是:先将 fixture 复制到临时目录,运行一次 AVA(视用例决定是否携带--update-snapshots),再对比运行前后读取到的.snap(需经 gzip 解压)与.md内容:
if (expectChanged) { t.not(after.report, before.report, 'expected .md to be changed'); t.notDeepEqual(after.snapshot, before.snapshot, 'expected .snap to be changed'); t.snapshot(cleanStringDiff(before.report, after.report), 'snapshot report diff'); } else { t.is(after.report, before.report, 'expected .md to be unchanged'); t.deepEqual(after.snapshot, before.snapshot, 'expected .snap to be unchanged'); }注意宏中用t.snapshot(..., 'snapshot report diff')将 diff 本身固化为嵌套快照,这就是本文所读文件changing-label.js.md的生成来源——整个工作流测试套件是"用快照测试来测试快照功能"的自举式验证。
源码级原理:label 如何在更新中流转
要理解 label 变更为什么能正确反映到两个文件中,需要追踪lib/snapshot-manager.js中 label 的生命周期:
记录(record):
recordSerialized将{data, label}按belongsTo(测试标题)与index写入新的快照块(lib/snapshot-manager.js#L322-L339)。--update-snapshots模式下执行record(),新 label 连同新数据一并写入.snap。跳过(skip):未变更的快照走
skipSnapshot路径。注意其中特意保留旧 label(lib/snapshot-manager.js#L368-L383):// Retain the label from the old snapshot, so as not to assume that the // snapshot.skip() arguments are well-formed. const snapshot = oldBlock?.snapshots[index] ?? {}; ... this.recordSerialized({belongsTo, index, ...snapshot});这保证了未更新的快照不会因 label 缺失而丢失标识。
报告生成(formatEntry):
combineEntries遍历快照块,将每个条目的 label 转为>引用块并与缩进后的数据描述拼接,最终生成.md报告(lib/snapshot-manager.js#L90-L119)。标志解析:
--update-snapshots(短名-u)在 CLI 层被解析并注入运行配置(lib/cli.js中update-snapshots标志定义见 lib/cli.js#L75,其解析分支见 lib/cli.js#L232-L233),最终传入快照管理器驱动"更新"而非"比较"模式。
实战操作:更新快照 label 的标准流程
结合官方文档 docs/04-snapshot-testing.md 与本文工作流测试的验证,在真实项目中更新快照 label(或内容)的推荐流程如下:
先运行测试确认失败原因:label 变更后,快照断言失败,报告会展示
.snap中旧 label 与期望新 label 的差异(官方文档中展示了失败输出样式,见 docs/04-snapshot-testing.md 相关截图说明);确认变更有意:人工核对 diff,确保 label 与内容的修改符合预期;
更新快照,在项目根目录执行:
$ ava --update-snapshots该命令会重写
.snap与.md两个文件;精准更新单个测试:仅需更新某个测试时,可将
--update-snapshots与--match或.only()组合使用,例如:$ ava --update-snapshots --match='foo'审查报告 diff:提交前通过版本控制系统对比
.md文件的变更,确认 label 更新符合预期(这正是.md报告设计用于源码控制 diff 的初衷);配置固定存储位置(可选):若希望快照统一存放,可在
package.json的ava配置中指定snapshotDir(详见 docs/06-configuration.md):{ "ava": { "snapshotDir": "custom-directory" } }快照目录结构仍会镜像测试文件的目录层级;若测试经 TypeScript 预编译运行,AVA 会借助 source map 定位原始文件,将快照保存在源文件旁(参见 docs/recipes/typescript.md)。
维护快照工作流测试的注意事项
如果你希望亲自运行或维护这套工作流测试(仓库test/snapshot-workflow/),test/snapshot-workflow/README.md给出了关键约束:
初始化一致性:所有使用同一 fixture 的测试必须以相同方式初始化 fixture(通常是等价于在 fixture 目录执行
TEMPLATE=true npx ava --update-snapshots),否则会互相覆盖期望的初始状态;更新 fixture 初始快照:当快照文件格式或 fixture 本身发生变化时,用如下命令批量刷新 fixture 的初始状态:
$ npx test-ava test/snapshot-workflow/** -- --update-fixture-snapshots
- 测试
【免费下载链接】ava
Node.js test runner that lets you develop with confidence 🚀
相关推荐
Snapshot report for `test/snapshot-workflow/try-skip.js`
Snapshot report for test/snapshot workflow/try skip.js The actual snapshot is sa
测试Puter AI 模型响应自 2026 年 9 月起默认 OpenAI 格式,旧代码怎么迁移?
Puter AI 模型响应自 2026 年 9 月起默认 OpenAI 格式,旧代码怎么迁移? 如果你的应用通过 puter js SDK 的 puter.ai
测试Snapshot report for `test/test-timeouts/test.js`
Snapshot report for test/test timeouts/test.js The actual snapshot is saved in t
测试
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考