contract-test-writer
Skill0 starsChanged 39 days agoMITView on GitHub
Writes consumer-driven contract tests at service and API boundaries - Pact consumer tests, provider verification, broker publishing, and can-i-deploy gates - so an incompatible change fails a build instead of breaking integrations in production. Use when someone asks "how do I stop the backend breaking my client", "set up Pact between these services", "a renamed field broke a consumer that unit tests passed", or two separately deployed services must stay in sync. Do NOT use for designing a new API contract from scratch or reviewing its design - use api-design instead; do NOT use for end-to-end user-journey tests - use e2e-scenario-author instead; do NOT use for calls inside a single deployable - write a unit test.
In this repository8 other files it gives its agents.
- coverage-gap-finderSkill
- e2e-scenario-authorSkill
- flaky-test-detanglerSkill
- mock-stub-designerSkill
- mutation-test-runnerSkill
- playwright-testingSkill
- tdd-expertSkill
- test-data-builderSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 7 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 31
Use matchers: like() for scalars, eachLike() for arrays, term()/regex for patterns.
- Distinctive: line 64
Run the consumer test to emit the pact file.
- Distinctive: line 80
Do not assert exact field values that are not part of the contract - it produces false breaks on harmless data changes, and false breaks …
- Distinctive: line 81
Do not include unread response fields just because the provider returns them - every extra field is a freedom the provider loses for …
- Distinctive: line 82
Do not verify business correctness, performance, or auth flows here - keep logic in unit tests and critical journeys in a thin E2E layer.
- Distinctive: line 83
Do not write contract tests for calls inside a single deployable - the compiler and unit tests already cover that boundary.
- Distinctive: line 84
Do not gate deploys against only the latest pact when older consumer versions are still running in an environment.
- Distinctive: line 85
Do not let the provider team write the "consumer" test from their own schema - that inverts consumer-driven and re-creates the original …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Contract Test Writer
Pin the shape of a network boundary from the consumer's side so a provider change that breaks any deployed consumer fails the provider's build, not production. The costly failure this prevents is the silent break: both teams' unit tests pass, both deploys go green, and the integration dies at runtime because a field was renamed or a status code changed and nothing in either pipeline knew the other side existed.
Operating procedure
The consumer-driven order is the point: the consumer declares what it needs first, and the provider verifies against that declaration. Reversing it (provider publishes a schema, consumers hope) is how unread fields calcify and real dependencies go untracked.
Step 1: Gather inputs
- The boundary: consumer name, provider name, and the calls in play. Confirm it is a real network boundary you do not control end-to-end (cross-service call, client-to-API). For an internal function call inside one deployable, stop - write a unit test instead.
- The fields the consumer actually reads from each response - from the consumer's code, not the provider's docs.
- Broker availability: Pact Broker or PactFlow URL and write credentials (default: recommend standing one up; pacts committed to a repo go stale silently).
- The environments where consumer versions run (prod, staging), for can-i-deploy.
Label as a guess any field list not confirmed against consumer source.
Step 2: Write the consumer test against a mock provider
Declare only the request shape and the exact response fields the consumer reads - never the provider's full schema. Over-specifying makes the provider brittle to harmless additions. The consumer-driven rule: a field enters the contract only when a consumer consumes it.
Step 3: Match on type and shape, not literal values
Use matchers: like() for scalars, eachLike() for arrays, term()/regex for patterns. Pin a literal only when it is semantically part of the contract - an enum member, a specific status code.
Bad - pinned fixture values plus fields the consumer never reads; harmless data changes now break the build:
.willRespondWith({
status: 200,
body: {
id: 42, name: 'Alice Smith', email: 'alice@example.com',
createdAt: '2021-03-04T10:00:00Z', internalScore: 0.87, region: 'us-east-1',
},
})Good - matchers for shape, literals only where meaning lives, only consumed fields:
.willRespondWith({
status: 200,
body: {
id: like(42),
name: like('Alice Smith'),
status: term({ matcher: 'active|suspended', generate: 'active' }), // enum: pinned
},
})Step 4: Declare coarse provider states
For responses that depend on data, declare a coarse, reusable provider state ("user exists", "user is suspended") in the consumer test rather than encoding exact rows. Fine-grained states ("user 42 with 3 orders placed on Tuesday") multiply provider setup hooks and couple the contract to fixtures.
Step 5: Publish the pact
Run the consumer test to emit the pact file. Publish to the broker tagged with the consumer version and git sha, plus the branch. The broker's matrix of verified consumer-provider version pairs is what makes Step 7 possible.
Step 6: Verify in the provider's pipeline
In the provider's own test suite, replay the pact against the real provider: stand up the endpoint, implement a setup hook for each declared provider state, and verify recorded requests against expectations. A renamed field or changed status code must fail this build. Verification that runs anywhere other than the provider's merge-blocking pipeline is decoration.
Step 7: Gate deploys with can-i-deploy
Run can-i-deploy against the consumer versions actually running in each target environment - not just the latest pact on main. Older consumer versions still deployed are still contracts in force; a provider change compatible with main but not with the version running in prod is still a production break.
Deliverable
Produce: (A) consumer tests emitting a pact whose every field is traceable to a consumer read, (B) broker publishing wired with version, sha, and branch tags, (C) provider verification with state hooks running in the provider's merge-blocking CI, and (D) a can-i-deploy gate checking every environment's deployed consumer versions before release.
Do NOT
- Do not assert exact field values that are not part of the contract - it produces false breaks on harmless data changes, and false breaks teach teams to ignore the gate.
- Do not include unread response fields just because the provider returns them - every extra field is a freedom the provider loses for nothing.
- Do not verify business correctness, performance, or auth flows here - keep logic in unit tests and critical journeys in a thin E2E layer; a contract test asserts shape compatibility only.
- Do not write contract tests for calls inside a single deployable - the compiler and unit tests already cover that boundary.
- Do not gate deploys against only the latest pact when older consumer versions are still running in an environment.
- Do not let the provider team write the "consumer" test from their own schema - that inverts consumer-driven and re-creates the original blindness.
Quality bar
- The contract contains only fields the consumer consumes - nothing the provider happens to return.
- Matchers everywhere except deliberately pinned enums and status codes; zero coupling to fixture values.
- Provider verification runs in the provider's pipeline and a deliberately renamed field demonstrably fails it.
- Provider states are coarse and shared; can-i-deploy checks every deployed consumer version, not just main.
- Both teams can name where the pact lives and which build breaks when compatibility does.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

