Babysitter pact-contract-testing
Consumer-driven contract testing with Pact framework. Generate consumer contracts, configure Pact Broker publishing, execute provider verification, detect breaking changes, and integrate with CI/CD pipelines.
git clone https://github.com/a5c-ai/babysitter
T=$(mktemp -d) && git clone --depth=1 https://github.com/a5c-ai/babysitter "$T" && mkdir -p ~/.claude/skills && cp -r "$T/library/specializations/qa-testing-automation/skills/pact-contract-testing" ~/.claude/skills/a5c-ai-babysitter-pact-contract-testing && rm -rf "$T"
library/specializations/qa-testing-automation/skills/pact-contract-testing/SKILL.mdpact-contract-testing
You are pact-contract-testing - a specialized skill for consumer-driven contract testing with the Pact framework, enabling reliable API integration testing between services.
Overview
This skill enables AI-powered contract testing including:
- Generating consumer contracts (Pact files)
- Configuring Pact Broker publishing
- Provider verification execution
- Breaking change detection
- Webhook integration for CI/CD
- Can-i-deploy checks
- Contract versioning management
- Bidirectional contract testing
Prerequisites
- Node.js, Java, or Python environment
- Pact library for your language
- Pact Broker (self-hosted or PactFlow)
- CI/CD pipeline access
- Consumer and provider applications
Capabilities
1. Consumer Contract Generation
Create consumer-side contracts with Pact JS:
import { PactV3, MatchersV3 } from '@pact-foundation/pact'; const { like, eachLike, regex } = MatchersV3; const provider = new PactV3({ consumer: 'frontend-app', provider: 'user-service', logLevel: 'info' }); describe('User API Contract', () => { it('should return user by ID', async () => { // Arrange: Define expected interaction await provider .given('a user with ID 123 exists') .uponReceiving('a request for user 123') .withRequest({ method: 'GET', path: '/api/users/123', headers: { Accept: 'application/json', Authorization: regex(/Bearer .+/, 'Bearer token123') } }) .willRespondWith({ status: 200, headers: { 'Content-Type': 'application/json' }, body: { id: like(123), email: like('user@example.com'), name: like('John Doe'), createdAt: like('2024-01-15T10:30:00Z'), roles: eachLike('user') } }); // Act & Assert: Execute test await provider.executeTest(async (mockServer) => { const response = await fetch(`${mockServer.url}/api/users/123`, { headers: { Accept: 'application/json', Authorization: 'Bearer token123' } }); expect(response.status).toBe(200); const user = await response.json(); expect(user.id).toBe(123); }); }); it('should return 404 for non-existent user', async () => { await provider .given('user 999 does not exist') .uponReceiving('a request for non-existent user') .withRequest({ method: 'GET', path: '/api/users/999' }) .willRespondWith({ status: 404, body: { error: like('User not found'), code: like('USER_NOT_FOUND') } }); await provider.executeTest(async (mockServer) => { const response = await fetch(`${mockServer.url}/api/users/999`); expect(response.status).toBe(404); }); }); });
2. Provider Verification
Verify provider against contracts:
import { Verifier } from '@pact-foundation/pact'; const verifier = new Verifier({ provider: 'user-service', providerBaseUrl: 'http://localhost:3000', // Fetch pacts from broker pactBrokerUrl: 'https://your-broker.pactflow.io', pactBrokerToken: process.env.PACT_BROKER_TOKEN, // Provider version providerVersion: process.env.GIT_COMMIT || '1.0.0', providerVersionBranch: process.env.GIT_BRANCH || 'main', // State handlers stateHandlers: { 'a user with ID 123 exists': async () => { // Set up test data await db.users.create({ id: 123, email: 'user@example.com', name: 'John Doe' }); }, 'user 999 does not exist': async () => { // Ensure user doesn't exist await db.users.delete(999); } }, // Publish results publishVerificationResult: true, enablePending: true, includeWipPactsSince: '2024-01-01' }); describe('Provider Verification', () => { beforeAll(async () => { // Start provider service await startServer(); }); afterAll(async () => { await stopServer(); }); it('should verify all consumer contracts', async () => { await verifier.verifyProvider(); }); });
3. Pact Broker Publishing
Publish contracts to Pact Broker:
import { Publisher } from '@pact-foundation/pact'; const publisher = new Publisher({ pactFilesOrDirs: ['./pacts'], pactBroker: 'https://your-broker.pactflow.io', pactBrokerToken: process.env.PACT_BROKER_TOKEN, consumerVersion: process.env.GIT_COMMIT || '1.0.0', branch: process.env.GIT_BRANCH || 'main', tags: [process.env.GIT_BRANCH || 'main'] }); await publisher.publishPacts();
4. Can-I-Deploy Check
Verify deployment safety:
# Check if consumer can be deployed pact-broker can-i-deploy \ --pacticipant frontend-app \ --version $(git rev-parse HEAD) \ --to-environment production \ --broker-base-url https://your-broker.pactflow.io \ --broker-token $PACT_BROKER_TOKEN # Check if provider can be deployed pact-broker can-i-deploy \ --pacticipant user-service \ --version $(git rev-parse HEAD) \ --to-environment production \ --broker-base-url https://your-broker.pactflow.io \ --broker-token $PACT_BROKER_TOKEN # Record deployment pact-broker record-deployment \ --pacticipant user-service \ --version $(git rev-parse HEAD) \ --environment production \ --broker-base-url https://your-broker.pactflow.io \ --broker-token $PACT_BROKER_TOKEN
5. CI/CD Integration
GitHub Actions workflow:
name: Contract Tests on: push: branches: [main, develop] pull_request: branches: [main] env: PACT_BROKER_URL: https://your-broker.pactflow.io PACT_BROKER_TOKEN: ${{ secrets.PACT_BROKER_TOKEN }} jobs: consumer-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Run consumer contract tests run: npm run test:contract:consumer - name: Publish pacts run: | npx pact-broker publish ./pacts \ --consumer-app-version ${{ github.sha }} \ --branch ${{ github.ref_name }} \ --broker-base-url $PACT_BROKER_URL \ --broker-token $PACT_BROKER_TOKEN provider-verification: runs-on: ubuntu-latest needs: consumer-tests steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Start provider run: npm run start:test & - name: Verify provider run: npm run test:contract:provider can-i-deploy: runs-on: ubuntu-latest needs: [consumer-tests, provider-verification] if: github.ref == 'refs/heads/main' steps: - name: Can I deploy? run: | docker run --rm pactfoundation/pact-cli \ broker can-i-deploy \ --pacticipant frontend-app \ --version ${{ github.sha }} \ --to-environment production \ --broker-base-url $PACT_BROKER_URL \ --broker-token $PACT_BROKER_TOKEN
6. Webhook Configuration
Set up Pact Broker webhooks:
# Trigger provider verification on consumer change pact-broker create-webhook \ 'https://api.github.com/repos/org/provider-repo/dispatches' \ --request=POST \ --header 'Accept: application/vnd.github.v3+json' \ --header 'Authorization: Bearer ${GITHUB_TOKEN}' \ --data '{"event_type": "contract_requiring_verification", "client_payload": {"pact_url": "${pactbroker.pactUrl}"}}' \ --description "Trigger provider verification on contract change" \ --contract-content-changed \ --broker-base-url https://your-broker.pactflow.io \ --broker-token $PACT_BROKER_TOKEN
7. Bidirectional Contract Testing
Use with OpenAPI specifications:
// Provider publishes OpenAPI spec import { PactV3 } from '@pact-foundation/pact'; // Consumer tests against provider's published OpenAPI const provider = new PactV3({ consumer: 'frontend-app', provider: 'user-service', pactBrokerUrl: 'https://your-broker.pactflow.io', pactBrokerToken: process.env.PACT_BROKER_TOKEN }); // Provider publishes OAS // pact-broker publish-provider-contract \ // openapi.yaml \ // --provider user-service \ // --provider-app-version $(git rev-parse HEAD) \ // --branch main \ // --content-type application/yaml \ // --verification-success \ // --broker-base-url https://your-broker.pactflow.io \ // --broker-token $PACT_BROKER_TOKEN
8. Matchers and Generators
Use flexible matching:
import { MatchersV3 } from '@pact-foundation/pact'; const { like, // Type matching eachLike, // Array matching regex, // Regex matching integer, // Integer type decimal, // Decimal type boolean, // Boolean type string, // String type datetime, // ISO datetime uuid, // UUID format ipv4Address, // IPv4 address email, // Email format atLeastOneLike, // At least one item matching atMostLike, // At most N items matching constrainedArrayLike // Min/max array } = MatchersV3; const userContract = { id: uuid(), email: email('test@example.com'), name: string('John Doe'), age: integer(25), balance: decimal(100.50), isActive: boolean(true), createdAt: datetime("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), roles: eachLike('user'), preferences: like({ theme: 'dark', notifications: true }), tags: constrainedArrayLike('tag', 1, 5) };
MCP Server Integration
This skill can leverage the following MCP servers for enhanced capabilities:
| Server | Description | Installation |
|---|---|---|
| PactFlow MCP Server | AI-powered contract testing in IDE | PactFlow Blog |
Best Practices
- Consumer-first - Start with consumer expectations
- Provider states - Use meaningful state names
- Versioning - Use git commit hashes for versions
- CI integration - Automate all contract testing
- Can-i-deploy - Always check before deployment
- Pending pacts - Enable for new consumers
- WIP pacts - Include work-in-progress pacts
- Branch awareness - Tag pacts with branch names
Process Integration
This skill integrates with the following processes:
- All phases of contract testingcontract-testing.js
- API contract validationapi-testing.js
- CI/CD contract integrationcontinuous-testing.js
- Contract verification gatesquality-gates.js
Output Format
When executing operations, provide structured output:
{ "operation": "verify", "provider": "user-service", "providerVersion": "abc123", "consumers": [ { "name": "frontend-app", "version": "def456", "status": "passed", "interactions": 5, "passed": 5, "failed": 0 } ], "canDeploy": true, "environment": "production", "verificationUrl": "https://broker.pactflow.io/verifications/123" }
Error Handling
- Handle missing provider states gracefully
- Provide clear mismatch descriptions
- Log full request/response on failures
- Support retry for transient failures
- Document breaking changes clearly
Constraints
- Contracts represent consumer needs, not full API
- Provider states must be reproducible
- Broker must be accessible from CI/CD
- Version management is critical
- Breaking changes require coordination