You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 13:25:01