You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Jest测试中PostgreSQL时间戳结果对比失败问题排查

解决Jest测试中PostgreSQL日期类型与Faker生成Date对象的匹配问题

这个问题我之前也踩过坑,核心原因其实很清楚:pg库默认会把PostgreSQL的timestamp with time zone类型以ISO格式的字符串返回,而你用faker生成的approved是一个Date对象。toStrictEqual是严格相等校验,不仅对比值还会校验类型,所以直接对比肯定失败。你之前转换没成功,大概率是转换的时机或者方式不对,下面给你几个可行的解决方案:

方案1:将Faker生成的Date对象转为ISO字符串(最直接)

pg返回的日期字符串是标准的ISO 8601格式(比如"2019-12-19T03:48:20.613Z"),你只需要把faker生成的Date对象调用toISOString()方法,就能得到完全匹配的格式。注意别用toString(),它返回的是人类可读的日期字符串,和pg的格式完全不一样。

修改测试代码如下:

// 先把template1的approved转换成和pg返回一致的ISO字符串
const expectedRow = {
  ...template1,
  approved: template1.approved.toISOString(),
  id: 1,
  modified: null,
};

expect(response.body.rows).toStrictEqual([expectedRow]);

方案2:将API返回的字符串日期转为Date对象对比

如果更希望用Date类型来对比,可以把返回结果里的approved字符串转成Date对象。不过这里要注意一个细节:如果PostgreSQL存储时截断了毫秒(比如某些配置下只保留到秒),那faker生成的Date对象带毫秒,转成Date后对比还是会失败,这时候需要统一处理毫秒。

示例代码:

// 处理返回结果,把approved转成Date
const receivedRow = {
  ...response.body.rows[0],
  approved: new Date(response.body.rows[0].approved),
};

// 如果需要忽略毫秒,可统一截断
const normalizeDate = (date) => {
  date.setMilliseconds(0);
  return date;
};

expect(normalizeDate(receivedRow.approved)).toEqual(normalizeDate(template1.approved));
expect(receivedRow).toMatchObject({ ...template1, id: 1, modified: null });

方案3:使用Jest的toMatchObject做模糊匹配

如果不需要严格校验所有字段的类型(比如只关心日期值是否正确,不纠结是字符串还是Date),可以用toMatchObject配合expect.stringMatchingexpect.any(Date)来做灵活校验:

// 匹配ISO字符串格式的日期
expect(response.body.rows[0]).toMatchObject({
  ...template1,
  approved: expect.stringMatching(template1.approved.toISOString()),
  id: 1,
  modified: null,
});

// 或者只要是Date类型就通过(适合不需要精确到毫秒的场景)
const receivedRowWithDate = {
  ...response.body.rows[0],
  approved: new Date(response.body.rows[0].approved),
};
expect(receivedRowWithDate).toMatchObject({
  ...template1,
  approved: expect.any(Date),
  id: 1,
  modified: null,
});

方案4:全局配置pg客户端自动转换日期类型

如果你想从根源解决,让API返回的日期直接是Date对象,不需要每次测试都转换,可以在pg客户端初始化时配置类型解析器,把PostgreSQL的timestamp类型自动转为Date:

const { Client } = require('pg');

const client = new Client({
  host: 'your-host',
  database: 'your-db',
  // 其他连接配置...
  types: {
    parse: {
      // 1114是不带时区的timestamp的OID,1184是带时区的timestamp的OID
      1114: (value) => new Date(value),
      1184: (value) => new Date(value),
    },
  },
});

配置后,pg会自动把这两种timestamp类型转成Date对象,测试时直接用faker生成的Date对比即可。


内容的提问来源于stack exchange,提问作者Dycey

火山引擎 最新活动