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

在Vitest的ESM环境中Mock node-postgres时遇到的问题求助

在Vitest ESM环境中Mock node-postgres的问题

初始实现与局限

我在函数中通过命名导入使用pg的Pool类:

import {Pool} from 'pg';
...
const pool = new Pool({connectionString});
const client = await pool.connect();
await client.query('BEGIN');
...

对应Mock方式如下:

vi.mock('pg', () => {
    const Pool = vi.fn();
    const Client = vi.fn();
    return {Pool, Client};
});

function queryMockImplementation(migrationTableExists: boolean, migratedFiles?: string[]) {
    return (queryString: string) => {
        if (queryString === `SELECT EXISTS (SELECT FROM pg_tables WHERE schemaname = 'administration' AND tablename = 'migrations')`) {
            return Promise.resolve({rows: [{exists: migrationTableExists}]});
        }
        return Promise.resolve({rows: []});
    }
}

function connectMockImplementation(clientQueries: string[], throwOnSqlQuery?: string) {
    return async() => {
        return {
            query: vi.fn().mockImplementation((queryString: string) => {
                if (throwOnSqlQuery === queryString) {
                    throw new Error('Error thrown by mock for client query.');
                }
                clientQueries.push(queryString);
            }),
            release: vi.fn(),
        };
    };
}

测试时的调用代码:

it('Should mock', async () => {
    const {Pool} = await import('pg');
    const clientQueries: string[] = [];
    Pool.prototype.query = vi.fn().mockImplementation(queryMockImplementation(false));
    Pool.prototype.connect = vi.fn().mockImplementation(connectMockImplementation(clientQueries));
    const pool = new Pool();
});

这种方式虽能运行,但存在明显局限:

  • 必须注入clientQueries数组到Mock实现中,才能监听client.query的调用内容
  • 无法直接Mock客户端实例
  • 命名导入的方式会给消费该库的ESM包带来兼容性问题

切换导入方式后的错误

当改为默认导入pg再解构Pool时:

import pg from 'pg';
const {Pool} = pg;

直接触发Vitest错误:

Error: [vitest] No "default" export is defined on the "pg" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "vi.importActual" inside:

vi.mock("pg", async () => {
const actual = await vi.importActual("pg")
return {
...actual,
// your mocked methods
},
})

调整Mock后的新问题

按照提示改用vi.importActual调整Mock:

vi.mock('pg', async () => {
    const actual = <Record<string, any>>await vi.importActual("pg")
    const Pool = vi.fn();
    const Client = vi.fn();
    return {...actual, Pool, Client};
});

但此时出现两个新问题:

  • 测试必须依赖真实数据库和有效的连接字符串才能运行
  • 之前配置的客户端查询Mock完全失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 02:56:26