From harness-claude
Verifies service compatibility using Pact consumer-provider contract tests. Useful for preventing breaking changes across independently deployed services.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:test-contract-testingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Verify service compatibility using Pact consumer-provider contract tests
Verify service compatibility using Pact consumer-provider contract tests
npm install -D @pact-foundation/pact
import { PactV4 } from '@pact-foundation/pact';
const provider = new PactV4({
consumer: 'OrderService',
provider: 'UserService',
});
describe('UserService API', () => {
it('returns user by ID', async () => {
await provider
.addInteraction()
.given('a user exists with ID 123')
.uponReceiving('a request for user 123')
.withRequest('GET', '/api/users/123', (builder) => {
builder.headers({ Accept: 'application/json' });
})
.willRespondWith(200, (builder) => {
builder.headers({ 'Content-Type': 'application/json' }).jsonBody({
id: '123',
name: 'Alice',
email: '[email protected]',
});
})
.executeTest(async (mockServer) => {
const client = new UserClient(mockServer.url);
const user = await client.getUser('123');
expect(user).toEqual({
id: '123',
name: 'Alice',
email: '[email protected]',
});
});
});
});
Generate the pact file — running the consumer test creates a contract file (e.g., pacts/OrderService-UserService.json).
Verify on the provider side:
import { Verifier } from '@pact-foundation/pact';
describe('Pact Verification', () => {
it('validates the OrderService contract', async () => {
const verifier = new Verifier({
providerBaseUrl: 'http://localhost:3001',
pactUrls: ['./pacts/OrderService-UserService.json'],
stateHandlers: {
'a user exists with ID 123': async () => {
await seedUser({ id: '123', name: 'Alice', email: '[email protected]' });
},
},
});
await verifier.verifyProvider();
});
});
// Consumer publishes
await publishPacts({
pactFilesOrDirs: ['./pacts'],
pactBroker: 'https://your-broker.pactflow.io',
consumerVersion: process.env.GIT_SHA,
tags: ['main'],
});
// Provider verifies from broker
const verifier = new Verifier({
providerBaseUrl: 'http://localhost:3001',
pactBrokerUrl: 'https://your-broker.pactflow.io',
providerVersionTags: ['main'],
publishVerificationResult: true,
});
stateHandlers: {
'no users exist': async () => {
await db.user.deleteMany();
},
'a user exists with ID 123': async () => {
await db.user.upsert({
where: { id: '123' },
create: { id: '123', name: 'Alice', email: '[email protected]' },
update: {},
});
},
},
import { like, eachLike, regex } from '@pact-foundation/pact';
.jsonBody({
id: like('123'), // any string
name: like('Alice'), // any string
email: regex(/.*@.*/, '[email protected]'), // matches regex
posts: eachLike({ title: like('Post') }), // array of objects
})
Contract testing verifies that two services agree on the format of their communication. The consumer defines its expectations as a "contract," and the provider verifies it can fulfill that contract.
Consumer-driven contracts: The consumer writes the contract because it knows what it needs. The provider verifies it can deliver. This ensures the provider does not make breaking changes that affect consumers.
Contract vs integration vs E2E:
Contract tests are faster and more focused than integration tests but do not verify business logic.
Pact workflow:
Trade-offs:
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeValidates API contracts with Pact (JS/Python/JVM) and Spring Cloud Contract via consumer-driven testing. Prevents microservice breaking changes.
Verifies API contracts between services using Pact consumer-driven tests, provider verification, schema validation, and OpenAPI specs. Use for microservices communication, preventing breaking changes.
Sets up Pact contract testing for microservices: consumer-driven contracts with provider states and interactions, verification via state handlers, OpenAPI validation middleware, breaking change detection.