smithery/patricio0312rev

integration-test-builder

Creates integration tests for API endpoints with database flows, including test harness setup, fixtures, setup/teardown, database seeding, and CI-friendly strategies. Use for "integration testing", "API tests", "database tests", or "test harness".

Installation

$ npx skills add smithery/patricio0312rev --skill integration-test-builder

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/patricio0312rev · top by installs.

npx skills add smithery/patricio0312rev

Browse all from smithery/patricio0312rev

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 12,437 B
  • docs SUMMARY.md 279 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Integration Test Builder

Build comprehensive integration tests for APIs and database flows.

Test Harness Setup

// tests/setup/test-harness.ts
import { PrismaClient } from "@prisma/client";
import { execSync } from "child_process";

export class TestHarness {
  prisma: PrismaClient;

  async setup() {
    // Setup test database
    process.env.DATABASE_URL = process.env.TEST_DATABASE_URL;

    // Run migrations
    execSync("npx prisma migrate deploy");

    // Initialize Prisma client
    this.prisma = new PrismaClient();

    // Clear all data
    await this.clearDatabase();
  }

  async teardown() {
    await this.prisma.$disconnect();
  }

  async clearDatabase() {
    const tables = await this.prisma.$queryRaw<{ tablename: string }[]>`
      SELECT tablename FROM pg_tables WHERE schemaname = 'public'
    `;

    for (const { tablename } of tables) {
      if (tablename !== "_prisma_migrations") {
        await this.prisma.$executeRawUnsafe(
          `TRUNCATE TABLE "${tablename}" CASCADE`
        );
      }
    }
  }

  async seedFixtures() {
    // Seed test data
    await this.prisma.user.create({
      data: {
        email: "[email protected]",
        name: "Test User",
      },
    });
  }
}

API Integration Tests

// tests/api/users.test.ts
import request from "supertest";
import { app } from "@/app";
import { TestHarness } from "../setup/test-harness";

describe("User API", () => {
  let harness: TestHarness;

  beforeAll(async () => {
    harness = new TestHarness();
    await harness.setup();
  });

  afterAll(async () => {
    await harness.teardown();
  });

  beforeEach(async () => {
    await harness.clearDatabase();
    await harness.seedFixtures();
  });

  describe("POST /api/users", () => {
    it("should create new user", async () => {
      // Arrange
      const userData = {
        email: "[email protected]",
        name: "New User",
      };

      // Act
      const response = await request(app)
        .post("/api/users")
        .send(userData)
        .expect(201);

      // Assert
      expect(response.body).toMatchObject({
        email: userData.email,
        name: userData.name,
      });
      expect(response.body.id).toBeDefined();

      // Verify in database
      const user = await harness.prisma.user.findUnique({
        where: { email: userData.email },
      });
      expect(user).toBeDefined();
      expect(user!.name).toBe(userData.name);
    });

    it("should return 400 for invalid email", async () => {
      // Arrange
      const userData = {
        email: "invalid-email",
        name: "Test User",
      };

      // Act
      const response = await request(app)
        .post("/api/users")
        .send(userData)
        .expect(400);

      // Assert
      expect(response.body.error).toContain("Invalid email");
    });

    it("should return 409 for duplicate email", async () => {
      // Arrange
      const userData = {
        email: "[email protected]", // Already exists
        name: "Duplicate User",
      };

      // Act
      const response = await request(app)
        .post("/api/users")
        .send(userData)
        .expect(409);

      // Assert
      expect(response.body.error).toContain("already exists");
    });
  });

  describe("GET /api/users/:id", () => {
    it("should get user by id", async () => {
      // Arrange
      const user = await harness.prisma.user.findFirst();

      // Act
      const response = await request(app)
        .get(`/api/users/${user!.id}`)
        .expect(200);

      // Assert
      expect(response.body).toMatchObject({
        id: user!.id,
        email: user!.email,
        name: user!.name,
      });
    });

    it("should return 404 for non-existent user", async () => {
      // Act
      const response = await request(app).get("/api/users/99999").expect(404);

      // Assert
      expect(response.body.error).toContain("not found");
    });
  });

  describe("PUT /api/users/:id", () => {
    it("should update user", async () => {
      // Arrange
      const user = await harness.prisma.user.findFirst();
      const updates = { name: "Updated Name" };

      // Act
      const response = await request(app)
        .put(`/api/users/${user!.id}`)
        .send(updates)
        .expect(200);

      // Assert
      expect(response.body.name).toBe("Updated Name");

      // Verify in database
      const updatedUser = await harness.prisma.user.findUnique({
        where: { id: user!.id },
      });
      expect(updatedUser!.name).toBe("Updated Name");
    });
  });

  describe("DELETE /api/users/:id", () => {
    it("should delete user", async () => {
      // Arrange
      const user = await harness.prisma.user.findFirst();

      // Act
      await request(app).delete(`/api/users/${user!.id}`).expect(204);

      // Assert - verify deletion in database
      const deletedUser = await harness.prisma.user.findUnique({
        where: { id: user!.id },
      });
      expect(deletedUser).toBeNull();
    });
  });
});

Database Transaction Tests

// tests/integration/order-flow.test.ts
describe("Order Flow", () => {
  it("should create order with items in transaction", async () => {
    // Arrange
    const user = await harness.prisma.user.findFirst();
    const product = await harness.prisma.product.create({
      data: {
        name: "Test Product",
        price: 99.99,
        stock: 10,
      },
    });

    const orderData = {
      userId: user!.id,
      items: [
        {
          productId: product.id,
          quantity: 2,
          price: product.price,
        },
      ],
    };

    // Act
    const response = await request(app)
      .post("/api/orders")
      .send(orderData)
      .expect(201);

    // Assert
    const order = await harness.prisma.order.findUnique({
      where: { id: response.body.id },
      include: { items: true },
    });

    expect(order).toBeDefined();
    expect(order!.items).toHaveLength(1);
    expect(order!.items[0].quantity).toBe(2);

    // Verify stock was decremented
    const updatedProduct = await harness.prisma.product.findUnique({
      where: { id: product.id },
    });
    expect(updatedProduct!.stock).toBe(8); // 10 - 2
  });

  it("should rollback transaction if order creation fails", async () => {
    // Arrange
    const user = await harness.prisma.user.findFirst();
    const product = await harness.prisma.product.create({
      data: {
        name: "Test Product",
        price: 99.99,
        stock: 1, // Only 1 in stock
      },
    });

    const orderData = {
      userId: user!.id,
      items: [
        {
          productId: product.id,
          quantity: 10, // Requesting more than available
          price: product.price,
        },
      ],
    };

    // Act
    await request(app).post("/api/orders").send(orderData).expect(400);

    // Assert - verify rollback
    const orders = await harness.prisma.order.findMany();
    expect(orders).toHaveLength(0);

    // Verify stock unchanged
    const unchangedProduct = await harness.prisma.product.findUnique({
      where: { id: product.id },
    });
    expect(unchangedProduct!.stock).toBe(1);
  });
});

Authentication Tests

// tests/integration/auth.test.ts
describe("Authentication", () => {
  describe("POST /api/auth/login", () => {
    it("should login with valid credentials", async () => {
      // Arrange
      await harness.prisma.user.create({
        data: {
          email: "[email protected]",
          password: await hash("password123"),
        },
      });

      // Act
      const response = await request(app)
        .post("/api/auth/login")
        .send({
          email: "[email protected]",
          password: "password123",
        })
        .expect(200);

      // Assert
      expect(response.body.token).toBeDefined();
      expect(response.body.user.email).toBe("[email protected]");
    });

    it("should reject invalid password", async () => {
      // Act
      const response = await request(app)
        .post("/api/auth/login")
        .send({
          email: "[email protected]",
          password: "wrong-password",
        })
        .expect(401);

      // Assert
      expect(response.body.error).toContain("Invalid credentials");
    });
  });

  describe("Protected routes", () => {
    let authToken: string;

    beforeEach(async () => {
      // Login to get token
      const response = await request(app).post("/api/auth/login").send({
        email: "[email protected]",
        password: "password123",
      });

      authToken = response.body.token;
    });

    it("should access protected route with valid token", async () => {
      await request(app)
        .get("/api/profile")
        .set("Authorization", `Bearer ${authToken}`)
        .expect(200);
    });

    it("should reject request without token", async () => {
      await request(app).get("/api/profile").expect(401);
    });

    it("should reject request with invalid token", async () => {
      await request(app)
        .get("/api/profile")
        .set("Authorization", "Bearer invalid-token")
        .expect(401);
    });
  });
});

Fixtures Management

// tests/fixtures/users.ts
export const userFixtures = {
  admin: {
    email: "[email protected]",
    name: "Admin User",
    role: "ADMIN",
  },
  regularUser: {
    email: "[email protected]",
    name: "Regular User",
    role: "USER",
  },
  testUser: {
    email: "[email protected]",
    name: "Test User",
    role: "USER",
  },
};

// tests/fixtures/products.ts
export const productFixtures = {
  laptop: {
    name: "MacBook Pro",
    price: 2499.99,
    stock: 10,
    category: "Electronics",
  },
  phone: {
    name: "iPhone 15",
    price: 999.99,
    stock: 50,
    category: "Electronics",
  },
};

// Usage in tests
await harness.prisma.user.create({
  data: userFixtures.admin,
});

CI-Friendly Strategy

# .github/workflows/integration-tests.yml
name: Integration Tests

on: [push, pull_request]

services:
  postgres:
    image: postgres:15
    env:
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test
      POSTGRES_DB: test_db
    ports:
      - 5432:5432
    options: >-
      --health-cmd pg_isready
      --health-interval 10s
      --health-timeout 5s
      --health-retries 5

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: "20"

      - run: npm ci

      - name: Run migrations
        run: npx prisma migrate deploy
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/test_db

      - name: Run integration tests
        run: npm run test:integration
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/test_db

Parallel Test Execution

// vitest.config.ts
export default defineConfig({
  test: {
    pool: "forks",
    poolOptions: {
      forks: {
        singleFork: false, // Run tests in parallel
      },
    },
    isolate: true, // Isolate each test file
    setupFiles: ["./tests/setup/global-setup.ts"],
  },
});

// Ensure each test file uses separate database
const TEST_DB_PREFIX = "test_db_";

function getDatabaseUrl(): string {
  const workerId = process.env.VITEST_WORKER_ID || "1";
  return `postgresql://test:test@localhost:5432/${TEST_DB_PREFIX}${workerId}`;
}

Best Practices

  1. Isolated tests: Each test can run independently
  2. Clean state: Clear database between tests
  3. Fast fixtures: Minimal data seeding
  4. Transactions: Test rollbacks explicitly
  5. Real database: Don't mock database in integration tests
  6. CI-ready: Use Docker containers
  7. Parallel execution: Independent test databases

Output Checklist

  • Test harness created
  • Database setup/teardown
  • Fixture management
  • API endpoint tests
  • Database transaction tests
  • Authentication tests
  • Error case coverage
  • CI workflow configured
  • Parallel execution support
  • Clear test naming