Database Testing with Poku and Drizzle
End-to-end example of testing Poku and Drizzle ORM, from installing the driver to spinning the database up with Docker Compose.
Open the connection in an outer describe, put every assertion inside its own it, and close the connection at the end of that same describe, so cleanup always runs regardless of what an individual assertion does. The container lifecycle lives in a poku.config.js anonymous plugin that uses @pokujs/docker to run setup before the suite and teardown after it, so the suite runs with a plain npm test.
Install
npm i drizzle-orm pg
npm i -D poku tsx @pokujs/docker @types/pg
Configure the credentials
.env.test:
DB_USER=postgres
DB_PASSWORD=secret
DB_PORT=5432
DB_NAME=app
DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@localhost:${DB_PORT}/${DB_NAME}"
.gitignore:
.env.test
Start the database
docker-compose.yml reads the same .env.test to configure the container:
services:
postgres:
image: postgres:18
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
ports:
- '${DB_PORT}:5432'
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${DB_USER} -d ${DB_NAME}']
interval: 5s
timeout: 5s
retries: 10
start_period: 30s
db-ready:
image: busybox
command: ['tail', '-f', '/dev/null']
depends_on:
postgres:
condition: service_healthy
Define the schema and connection
schema.ts:
import { integer, pgTable, text } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: integer('id').primaryKey(),
name: text('name').notNull(),
});
db.ts reads the connection string from process.env. A single Client, not a pool, keeps every statement on the same connection, which a temporary table requires:
import { drizzle } from 'drizzle-orm/node-postgres';
import { Client } from 'pg';
export const client = new Client({
connectionString: process.env.DATABASE_URL,
});
await client.connect();
export const db = drizzle({ client });
Write the test
users.test.ts:
import { eq, sql } from 'drizzle-orm';
import { describe, it, assert } from 'poku';
import { client, db } from './db.js';
import { users } from './schema.js';
await describe('Users table', async () => {
await describe('Seed', async () => {
await db.execute(
sql`CREATE TEMP TABLE users (id INT PRIMARY KEY, name TEXT NOT NULL)`
);
await db.insert(users).values({ id: 1, name: 'Poku' });
});
await it('reads the inserted user', async () => {
const [user] = await db.select().from(users).where(eq(users.id, 1));
assert.strictEqual(user.name, 'Poku', 'The inserted user is returned');
});
await client.end();
});
Configure Poku
poku.config.js:
import { defineConfig } from 'poku';
import { docker } from '@pokujs/docker';
const compose = docker.compose({ envFile: '.env.test' });
export default defineConfig({
envFile: '.env.test',
plugins: [
{
setup: () => compose.up(),
teardown: () => compose.down(),
},
],
});
Configuring Poku is optional: you can orchestrate your containers however you prefer and run Poku as poku --envFile='.env.test', for example. In that case, @pokujs/docker is not needed.
Run
Add the test script to package.json:
{
"scripts": {
"test": "poku"
}
}
Then run it:
npm test