From harness-claude
Provides patterns for writing integration tests using real test databases, Docker containers with Testcontainers, Supertest for APIs, and Prisma transaction isolation.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Write integration tests that exercise real dependencies using test databases and containers
Sets up integration tests across databases, APIs, and message queues using Testcontainers, with DB seeding, cleanup strategies, and Docker dependencies.
Designs and implements integration tests for APIs, databases, external services, and message queues to verify interactions, data flows, and service validations.
Executes integration tests for APIs, databases, services, queues, and files using real dependencies and Docker infra. Validates component interactions without mocks.
Share bugs, ideas, or general feedback.
Write integration tests that exercise real dependencies using test databases and containers
// test/setup.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
datasources: { db: { url: process.env.TEST_DATABASE_URL } },
});
beforeEach(async () => {
// Clean tables in dependency order
await prisma.post.deleteMany();
await prisma.user.deleteMany();
});
afterAll(async () => {
await prisma.$disconnect();
});
export { prisma };
import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';
let container: StartedPostgreSqlContainer;
beforeAll(async () => {
container = await new PostgreSqlContainer().start();
process.env.DATABASE_URL = container.getConnectionUri();
// Run migrations
await execSync('npx prisma migrate deploy');
}, 60_000); // Container startup timeout
afterAll(async () => {
await container.stop();
});
import request from 'supertest';
import { app } from '../app';
describe('POST /api/users', () => {
it('creates a user and returns 201', async () => {
const response = await request(app)
.post('/api/users')
.send({ name: 'Alice', email: 'alice@test.com' })
.expect(201);
expect(response.body).toMatchObject({
name: 'Alice',
email: 'alice@test.com',
});
expect(response.body.id).toBeDefined();
});
it('returns 400 for invalid email', async () => {
await request(app).post('/api/users').send({ name: 'Alice', email: 'invalid' }).expect(400);
});
});
import { prisma } from './setup';
let tx: PrismaClient;
beforeEach(async () => {
// Start a transaction for test isolation
// Each test sees a clean state without deleting data
await prisma.$executeRaw`BEGIN`;
});
afterEach(async () => {
await prisma.$executeRaw`ROLLBACK`;
});
describe('OrderService', () => {
it('creates order and deducts inventory', async () => {
// Arrange — seed test data
const product = await prisma.product.create({
data: { name: 'Widget', stock: 10, price: 9.99 },
});
const service = new OrderService(prisma);
// Act
const order = await service.createOrder({
items: [{ productId: product.id, quantity: 3 }],
userId: testUser.id,
});
// Assert — verify both order creation AND inventory deduction
expect(order.total).toBe(29.97);
const updatedProduct = await prisma.product.findUnique({
where: { id: product.id },
});
expect(updatedProduct!.stock).toBe(7);
});
});
async function createTestUser(overrides?: Partial<User>) {
return prisma.user.create({
data: {
email: `test-${crypto.randomUUID()}@test.com`,
name: 'Test User',
...overrides,
},
});
}
// vitest.config.integration.ts
export default defineConfig({
test: {
include: ['**/*.integration.test.ts'],
setupFiles: ['./test/integration-setup.ts'],
testTimeout: 30_000,
hookTimeout: 60_000,
},
});
Run with: vitest --config vitest.config.integration.ts
Integration tests verify that multiple components work together correctly. They catch issues that unit tests miss — serialization bugs, query errors, constraint violations, and middleware ordering problems.
Test database strategies:
Data isolation approaches:
deleteMany in reverse dependency orderIntegration vs E2E: Integration tests exercise the backend (service + database) without a browser. E2E tests include the full stack (browser + backend + database). Integration tests are faster and more focused.
Trade-offs: