快照测试

toMatchSnapshot — 基础用法

import { render } from '@testing-library/react'; import { Button } from './Button'; test('Button 渲染正确', () => { const { asFragment } = render(<Button label="点击我" />); expect(asFragment()).toMatchSnapshot(); }); // 对象/值的快照 test('转换用户数据', () => { const result = transformUser({ id: 1, name: '张三', role: 'admin' }); expect(result).toMatchSnapshot(); }); // 快照文件保存在 __snapshots__/Button.test.tsx.snap

内联快照

// 首次运行时 Jest 自动写入快照值 test('格式化货币', () => { expect(formatCurrency(1234.5, 'CNY')).toMatchInlineSnapshot(`"¥1,234.50"`); }); test('错误对象结构', () => { const err = createError('NOT_FOUND', '用户未找到'); expect(err).toMatchInlineSnapshot(` Object { "code": "NOT_FOUND", "message": "用户未找到", "timestamp": Any<String>, } `); }); // 优点:快照与测试代码在同一文件,PR 审查更方便

更新快照

# 更新所有过期/变更的快照 npx jest --updateSnapshot npx jest -u # 更新特定测试文件的快照 npx jest Button.test.tsx --updateSnapshot # 交互式更新模式 npx jest --watch # 然后按 'u' 键更新失败的快照 # CI 环境:有新快照或变更时失败 npx jest --ci

自定义快照序列化器

// 为特殊对象类型添加自定义序列化器 expect.addSnapshotSerializer({ test: (val) => val && val.__type === 'Color', print: (val) => `Color(${val.r}, ${val.g}, ${val.b})`, }); test('颜色对象', () => { expect({ __type: 'Color', r: 255, g: 0, b: 128 }) .toMatchInlineSnapshot(`Color(255, 0, 128)`); }); // jest.config.js — 全局序列化器 module.exports = { snapshotSerializers: [ 'enzyme-to-json/serializer', './src/test-utils/mySerializer.js', ], };

异步组件与动态值

import { render, screen, waitFor } from '@testing-library/react'; test('异步数据加载到组件', async () => { const { asFragment } = render(<UserProfile userId="1" />); await waitFor(() => screen.getByText('张三')); expect(asFragment()).toMatchSnapshot(); }); // 使用属性匹配器屏蔽动态值 test('API 响应结构', () => { const response = { id: 123, createdAt: new Date().toISOString(), name: '李四' }; expect(response).toMatchSnapshot({ id: expect.any(Number), createdAt: expect.any(String), }); });

快照测试最佳实践

实践原因
将 .snap 文件提交到 git快照是测试套件的一部分
在 PR 中审查快照差异捕获意外的 UI 回归
保持快照小而聚焦大快照难以审查
简单值用内联快照上下文保留在同一文件中
ID/时间戳使用属性匹配器避免动态数据导致测试不稳定