Shared database testing patterns with testcontainers and Vitest. Use when writing backend tests, setting up test files, debugging test failures, or configuring Vitest. Triggers on "write tests", "test setup", "testcontainers", "vitest config", "test isolation", or when creating new test suites.
This repo uses a shared PostgreSQL container with TRUNCATE resets for fast, isolated tests.
import { describe, it, expect, beforeAll, beforeEach } from "vitest";
import type { Kysely } from "kysely";
import type { DB as DatabaseSchema } from "#schema";
import { getSharedDatabaseHelper, resetSharedDatabase, createTestUser } from "#test-helpers";
describe("My Test Suite", () => {
let db: Kysely<DatabaseSchema>;
beforeAll(async () => {
const dbHelper = await getSharedDatabaseHelper();
db = dbHelper.db;
});
beforeEach(async () => {
await resetSharedDatabase();
});
it("should work", async () => {
const user = await createTestUser(db);
expect(user).toBeDefined();
});
});
| Function | Purpose |
|----------|---------|
| getSharedDatabaseHelper() | Get DB connection (call in beforeAll) |
| resetSharedDatabase() | Reset to clean state (call in beforeEach) |
| createTestUser(db) | Create test user fixture |
// vitest.config.ts
export default defineConfig({
test: {
pool: "threads", // REQUIRED: threads, not forks
maxConcurrency: 4, // Limit parallel tests
isolate: false, // Reuse context for speed
hookTimeout: 120000, // 2 min for container startup
testTimeout: 30000, // 30 sec per test
}
});
Use createSharedTestConfig() from @yourcompany/backend-core/vitest.config.shared:
import { mergeConfig, defineConfig } from "vitest/config";
import { createSharedTestConfig } from "@yourcompany/backend-core/vitest.config.shared";
export default mergeConfig(
createSharedTestConfig({ setupFiles: ["./src/test-setup.ts"] }),
defineConfig({ /* overrides */ })
);
let testUser: User;
beforeEach(async () => {
await resetSharedDatabase();
testUser = await createTestUser(db); // Create AFTER reset
});
describe("Feature", () => {
beforeEach(async () => {
await resetSharedDatabase(); // Applies to ALL nested tests
});
describe("sub-feature", () => {
it("test 1", () => { /* clean DB */ });
it("test 2", () => { /* clean DB */ });
});
});
| Issue | Cause | Solution |
|-------|-------|----------|
| "Database not initialized" | Test ran before setup | Add beforeAll with getSharedDatabaseHelper() |
| Tests interfering | Missing reset | Add resetSharedDatabase() in beforeEach |
| Connection refused | Timeout too short | Increase hookTimeout |
| Slow suite | Check logs | Should see only ONE container startup |
pool: "threads" (not forks)resetSharedDatabase() in beforeEachafterAll cleanup needed - handled globallypnpm --filter @yourcompany/web storybook
Ensure VITE_API_URL and VITE_AUTH_URL are set in .env.development.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer