如何在Vitest中结合toMatchSnapshot与toBeCloseTo的行为?
在Vitest中实现对象数值的近似快照匹配(精确到指定小数位)
问题场景
我的快照中有如下格式的对象:
{ "meanElements": { "Om": 2.2835713400168607, "am": 1.3043985097733939, "em": 0.166565, "im": 0.5743651675510579, "mm": -4.361270622785478, "nm": 0.049918822378349076, "om": 4.074394344293675 }, "position": { "x": -5869.9169277202145, "y": 6791.004588475254, "z": 0.0037576740924038414 }, "velocity": { "x": -4.630159774803886, "y": -2.7654049420795106, "z": 3.4389423149777203 } }
我需要匹配该对象的结构及其中的数值,但只要求精确到小数点后N位,而非完全匹配。查阅propertyMatchers后发现无法直接使用toBeCloseTo,请问在Vitest中该如何实现?
解决方案
方法1:自定义快照匹配器
你可以在Vitest中自定义一个匹配器,递归遍历对象的所有数值属性,用toBeCloseTo做近似校验,同时保证结构一致。
首先在测试文件或全局配置中注册自定义匹配器:
import { expect } from 'vitest'; expect.extend({ toMatchCloseSnapshot(received, expected, precision = 5) { const checkCloseMatch = (obj1, obj2) => { // 非对象类型直接校验 if (typeof obj1 !== 'object' || obj1 === null) { if (typeof obj1 === 'number' && typeof obj2 === 'number') { expect(obj1).toBeCloseTo(obj2, precision); } else { expect(obj1).toEqual(obj2); } return; } // 遍历对象属性递归校验 Object.keys(obj2).forEach(key => { checkCloseMatch(obj1[key], obj2[key]); }); // 校验结构一致性,防止接收对象多属性 expect(Object.keys(obj1)).toEqual(Object.keys(obj2)); }; try { checkCloseMatch(received, expected); return { pass: true, message: () => '' }; } catch (error) { return { pass: false, message: () => error.message }; } } });
测试中直接使用该匹配器:
test('匹配近似快照', () => { const result = // 你的测试输出对象 const snapshot = // 读取的快照对象或预期对象 expect(result).toMatchCloseSnapshot(snapshot, 5); // 这里指定小数点后5位精度 });
方法2:预处理对象后生成快照
如果不需要动态调整精度,也可以先把对象的数值属性四舍五入到指定小数位,再生成或匹配快照。
先写一个递归处理对象的工具函数:
const roundObjectNumbers = (obj, precision) => { if (typeof obj !== 'object' || obj === null) { return typeof obj === 'number' ? Number(obj.toFixed(precision)) : obj; } const roundedObj = {}; for (const key in obj) { roundedObj[key] = roundObjectNumbers(obj[key], precision); } return roundedObj; };
测试中先处理对象再匹配快照:
test('预处理后匹配快照', () => { const result = // 你的测试输出对象 const processedResult = roundObjectNumbers(result, 5); expect(processedResult).toMatchSnapshot(); });
生成的快照会自动保存四舍五入后的数值,后续测试也会用处理后的对象进行匹配。
内容的提问来源于stack exchange,提问作者1valdis
相关产品推荐
相关产品推荐

