library/specializations/qa-testing-automation/skills/pact-contract-testing/SKILL.md
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.
npx skillsauth add a5c-ai/babysitter pact-contract-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are pact-contract-testing - a specialized skill for consumer-driven contract testing with the Pact framework, enabling reliable API integration testing between services.
This skill enables AI-powered contract testing including:
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('[email protected]'),
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);
});
});
});
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: '[email protected]', 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();
});
});
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();
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
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
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
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
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('[email protected]'),
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)
};
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 |
This skill integrates with the following processes:
contract-testing.js - All phases of contract testingapi-testing.js - API contract validationcontinuous-testing.js - CI/CD contract integrationquality-gates.js - Contract verification gatesWhen 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"
}
development
Model documentation skill for generating model cards following Google's model card framework.
development
MLflow integration skill for experiment tracking, model registry, and artifact management. Enables LLMs to log experiments, compare runs, manage model lifecycle, and retrieve artifacts through the MLflow API.
data-ai
LIME-based local explanation skill for individual predictions across tabular, text, and image data.
devops
Kubeflow Pipelines skill for ML workflow orchestration, component management, and Kubernetes-native ML.