5.2 KiB
PostgresFixture
(no submodules)
Purpose
PostgresFixture is an integration test fixture that manages the full lifecycle of a PostgreSQL 16 container using testcontainers. It implements the ServiceFixture<PostgresConfig> interface from @suaveplan/testing-integration, providing a ready-to-use PostgreSQL instance for tests with env-bridge passthrough, in-container health checking via pg_isready, and full configuration control over database name, username, and password.
The fixture intentionally excludes the pg client from its dependencies — it returns a plain PostgresConfig object containing a connection URL and parsed components. Consumers provide their own PostgreSQL client, keeping the fixture lightweight and client-agnostic.
Features
- Env-bridge passthrough: when
POSTGRES_URLis set and non-empty, the fixture parses the URL into aPostgresConfigand returns immediately without starting Docker. pg_isreadyhealth check: runspg_isready -U postgresinside the container — no external pg client or TCP connection required.- Injectable exec function: the
execFnoption allows unit tests to stub the pg_isready call without a real PostgreSQL container. - Injectable container factory: the
containerFactoryoption allows unit tests to swap in a fake container without Docker. - Configurable db/user/password: override defaults via options; values flow into container environment variables and the returned connection URL.
- URL parsing for passthrough:
new URL(url)extracts host, port, database, username, and password from thePOSTGRES_URLenv var.
Usage: Basic Example
import { PostgresFixture } from "@suaveplan/testing-integration-postgres";
const fixture = new PostgresFixture();
const config = await fixture.start();
// config.url → "postgresql://test:test@localhost:<randomPort>/test"
// config.host → "localhost"
// config.port → random ephemeral port
// config.database → "test"
// config.username → "test"
// config.password → "test"
await fixture.stop();
Usage: Advanced Example
import { PostgresFixture } from "@suaveplan/testing-integration-postgres";
import postgres from "postgres";
const fixture = new PostgresFixture({
database: "myapp",
username: "appuser",
password: "s3cr3t",
});
const config = await fixture.start();
const sql = postgres(config.url);
// Run migrations, seed data, run tests...
await sql`CREATE TABLE users (id serial PRIMARY KEY, name text)`;
await sql.end();
await fixture.stop();
API Reference
class PostgresFixture
Implements ServiceFixture<PostgresConfig>.
constructor(options?: PostgresFixtureOptions)
Creates a new fixture instance. All options are optional.
name: string
Always "postgres". Used by TestEnvironment as the registry key.
start(): Promise<PostgresConfig>
Starts the service. Returns the runtime configuration. In passthrough mode (when POSTGRES_URL env var is set), returns immediately with parsed config. Otherwise starts a testcontainers container with the configured environment variables.
stop(): Promise<void>
Stops the container. No-op in passthrough mode or when not started.
healthCheck(): Promise<boolean>
Runs pg_isready -U postgres inside the container and returns true when exit code is 0. Returns false if no container is active.
interface PostgresConfig
| Field | Type | Description |
|---|---|---|
url |
string |
Full connection URL: postgresql://user:pass@localhost:<port>/db |
host |
string |
Hostname |
port |
number |
Port number |
database |
string |
Database name |
username |
string |
Username |
password |
string |
Password |
interface PostgresFixtureOptions
| Field | Type | Description |
|---|---|---|
image? |
string |
Docker image override. Defaults to postgres:16-alpine. |
database? |
string |
Database name override. Defaults to "test". |
username? |
string |
Username override. Defaults to "test". |
password? |
string |
Password override. Defaults to "test". |
containerFactory? |
(image: string) => GenericContainer |
Injectable factory for unit testing. |
execFn? |
(cmd: string[]) => Promise<{ exitCode: number }> |
Injectable executor for health check unit testing. |
Implementation Notes
- Why
pg_isreadyover TCP:pg_isreadyis the canonical PostgreSQL health check tool, shipped in the officialpostgres:16-alpineimage. It validates that PostgreSQL is accepting connections at the protocol level, which is more reliable than a bare TCP connect. It also avoids requiring a pg client in this fixture. - Dynamic import of testcontainers:
GenericContaineris deferred tostart()time so unit tests that provide acontainerFactorydo not trigger testcontainers initialization. - URL construction: the connection URL uses
postgresql://(the PostgreSQL standard scheme) rather thanpostgres://to ensure compatibility with clients likepostgres(node-postgres) and Prisma. - Passthrough URL parsing:
pathname.slice(1)strips the leading/from the URL path to extract the database name correctly.