UNPKG

pgsql-test

Version:

pgsql-test offers isolated, role-aware, and rollback-friendly PostgreSQL environments for integration tests — giving developers realistic test coverage without external state pollution

94 lines (93 loc) 3.23 kB
import { getConnEnvOptions } from '@pgpmjs/env'; import { randomUUID } from 'crypto'; import { teardownPgPools } from 'pg-cache'; import { getPgEnvOptions, } from 'pg-env'; import { getDefaultRole } from 'pgsql-client'; import { DbAdmin } from './admin'; import { PgTestConnector } from './manager'; import { seed } from './seed'; import { formatPgError } from './utils'; let manager; export const getPgRootAdmin = (config, connOpts = {}) => { const opts = getPgEnvOptions({ user: config.user, password: config.password, host: config.host, port: config.port, database: connOpts.rootDb }); const admin = new DbAdmin(opts, false, connOpts); return admin; }; const getConnOopts = (cn = {}) => { const connect = getConnEnvOptions(cn.db); const config = getPgEnvOptions({ database: `${connect.prefix}${randomUUID()}`, ...cn.pg }); return { pg: config, db: connect }; }; export const getConnections = async (cn = {}, seedAdapters = [seed.pgpm()]) => { cn = getConnOopts(cn); const config = cn.pg; const connOpts = cn.db; const root = getPgRootAdmin(config, connOpts); await root.createUserRole(connOpts.connections.app.user, connOpts.connections.app.password, connOpts.rootDb); const admin = new DbAdmin(config, false, connOpts); if (process.env.TEST_DB) { config.database = process.env.TEST_DB; } else if (connOpts.template) { admin.createFromTemplate(connOpts.template, config.database); } else { admin.create(config.database); admin.installExtensions(connOpts.extensions); } await admin.grantConnect(connOpts.connections.app.user, config.database); manager = PgTestConnector.getInstance(config); const pg = manager.getClient(config); let teardownPromise = null; let teardownOpts = {}; const teardown = async (opts = {}) => { teardownOpts = opts; if (teardownPromise) return teardownPromise; teardownPromise = (async () => { manager.beginTeardown(); await teardownPgPools(); await manager.closeAll({ keepDb: teardownOpts.keepDb }); })(); return teardownPromise; }; if (seedAdapters.length) { try { await seed.compose(seedAdapters).seed({ connect: connOpts, admin, config: config, pg: manager.getClient(config) }); } catch (error) { // Format the error with PostgreSQL extended fields for better debugging const formatted = formatPgError(error); process.stderr.write(`[pgsql-test] Seed error (continuing):\n${formatted}\n`); // continue without teardown to allow caller-managed lifecycle } } const dbConfig = { ...config, user: connOpts.connections.app.user, password: connOpts.connections.app.password }; const db = manager.getClient(dbConfig, { auth: connOpts.auth, roles: connOpts.roles }); db.setContext({ role: getDefaultRole(connOpts) }); return { pg, db, teardown, manager, admin }; };