在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
相关产品推荐
相关产品推荐

