Files
skills/docs/testkit/testing/testing-integration-postgres/src/fixture/postgres-fixture.md
2026-05-29 08:20:56 +01:00

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_URL is set and non-empty, the fixture parses the URL into a PostgresConfig and returns immediately without starting Docker.
  • pg_isready health check: runs pg_isready -U postgres inside the container — no external pg client or TCP connection required.
  • Injectable exec function: the execFn option allows unit tests to stub the pg_isready call without a real PostgreSQL container.
  • Injectable container factory: the containerFactory option 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 the POSTGRES_URL env 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_isready over TCP: pg_isready is the canonical PostgreSQL health check tool, shipped in the official postgres:16-alpine image. 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: GenericContainer is deferred to start() time so unit tests that provide a containerFactory do not trigger testcontainers initialization.
  • URL construction: the connection URL uses postgresql:// (the PostgreSQL standard scheme) rather than postgres:// to ensure compatibility with clients like postgres (node-postgres) and Prisma.
  • Passthrough URL parsing: pathname.slice(1) strips the leading / from the URL path to extract the database name correctly.