Jest测试中PostgreSQL时间戳结果对比失败问题排查
这个问题我之前也踩过坑,核心原因其实很清楚: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.stringMatching或expect.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




