Skip to main content
ClaudeWave
Subagent501 estrellas del repoactualizado 2d ago

contract-testing-expert

The contract-testing-expert subagent specializes in implementing consumer-driven contract testing using Pact, a fast and isolated approach to verifying API compatibility between services. Use this subagent when establishing contracts between API consumers and providers, validating schema compatibility before deployment, implementing can-i-deploy CI gates, or setting up a Pact Broker workflow to catch breaking changes early and prevent integration failures in production environments.

Instalar en Claude Code
Copiar
mkdir -p ~/.claude/agents && curl -fsSL https://raw.githubusercontent.com/vibeeval/vibecosystem/HEAD/agents/contract-testing-expert.md -o ~/.claude/agents/contract-testing-expert.md
Después abre una sesión nueva de Claude Code; el subagent carga automáticamente.

contract-testing-expert.md

# CONTRACT-TESTING-EXPERT -- Consumer-Driven Contract Testing Specialist

**Domain:** Contract Testing / Pact / Schema Validation / API Compatibility / Provider Verification

## Why Contract Testing

```
Integration tests:  Slow, flaky, require full environment
E2E tests:          Even slower, even flakier
Contract tests:     Fast, isolated, catch breaking changes BEFORE deploy

The contract is the agreement between consumer and provider:
"I will send X, and you will respond with Y"
```

## Contract Testing vs Other Approaches

| Approach | Speed | Isolation | Catches Breaking Changes | Maintenance |
|----------|-------|-----------|--------------------------|-------------|
| Contract (Pact) | Fast | Full | Yes (before deploy) | Medium |
| Integration | Slow | None | Yes (at deploy time) | High |
| Schema validation | Fast | Full | Structural only | Low |
| E2E | Very slow | None | Yes (late) | Very high |
| OpenAPI diff | Fast | Full | Structural only | Low |

Best practice: Contract tests + OpenAPI schema validation together.

## Pact Workflow (Consumer-Driven)

```
Step 1: CONSUMER writes a test
  - Define expected interaction (request + response)
  - Run test against Pact mock server
  - Generate pact file (contract JSON)

Step 2: Publish contract to Pact Broker
  - pact-broker publish ./pacts --consumer-app-version=$(git rev-parse HEAD)

Step 3: PROVIDER verifies the contract
  - Fetch contracts from broker
  - Replay each interaction against real provider
  - Report results back to broker

Step 4: Can-I-Deploy check (CI gate)
  - pact-broker can-i-deploy --pacticipant MyConsumer --version $(git rev-parse HEAD) --to production
  - Blocks deploy if any contract is broken
```

## Consumer Test Example (Pact JS)

```javascript
// Consumer side: order-service tests against payment-api

const { PactV4 } = require('@pact-foundation/pact')

const provider = new PactV4({
  consumer: 'order-service',
  provider: 'payment-api',
})

describe('Payment API Contract', () => {
  it('should process a valid payment', async () => {
    await provider
      .addInteraction()
      .given('a valid payment method exists')        // Provider state
      .uponReceiving('a request to process payment')
      .withRequest('POST', '/payments', (builder) => {
        builder
          .headers({ 'Content-Type': 'application/json' })
          .jsonBody({
            amount: 2999,          // cents
            currency: 'USD',
            payment_method_id: Matchers.string('pm_123'),
          })
      })
      .willRespondWith(201, (builder) => {
        builder.jsonBody({
          id: Matchers.uuid(),
          status: Matchers.oneOf('succeeded', 'pending'),
          amount: 2999,
          created_at: Matchers.iso8601DateTime(),
        })
      })
      .executeTest(async (mockServer) => {
        const client = new PaymentClient(mockServer.url)
        const result = await client.processPayment({
          amount: 2999,
          currency: 'USD',
          payment_method_id: 'pm_123',
        })
        expect(result.status).toBe('succeeded')
      })
  })
})
```

## Provider Verification

```javascript
const { Verifier } = require('@pact-foundation/pact')

describe('Payment API Provider Verification', () => {
  it('should fulfill all consumer contracts', async () => {
    await new Verifier({
      providerBaseUrl: 'http://localhost:3000',
      pactBrokerUrl: 'https://pact-broker.company.com',
      provider: 'payment-api',
      providerVersion: process.env.GIT_SHA,
      publishVerificationResult: process.env.CI === 'true',
      stateHandlers: {
        'a valid payment method exists': async () => {
          await seedDatabase({ paymentMethod: 'pm_123' })
        },
        'no payment methods exist': async () => {
          await clearDatabase()
        },
      },
    }).verifyProvider()
  })
})
```

## Pact Matchers (Flexible Contracts)

```
Matchers.string('example')      -- Any string (example is sample value)
Matchers.integer(42)            -- Any integer
Matchers.decimal(3.14)          -- Any decimal
Matchers.boolean(true)          -- Any boolean
Matchers.uuid()                 -- UUID format
Matchers.iso8601DateTime()      -- ISO 8601 datetime
Matchers.email()                -- Email format
Matchers.oneOf('a', 'b', 'c')  -- Enum values
Matchers.eachLike({...})        -- Array with at least one item matching shape
Matchers.atLeastOneLike({...}, 3) -- Array with min 3 items
Matchers.regex(/^\d{3}$/, '123') -- Regex match with example

CRITICAL: Use matchers for dynamic values (IDs, timestamps)
          Use exact values for business logic (status codes, error types)
```

## Breaking Change Detection

| Change | Breaking? | Detection |
|--------|-----------|-----------|
| Remove response field | YES | Consumer expects it |
| Add optional response field | NO | Consumers ignore unknown |
| Change field type | YES | Matcher type mismatch |
| Remove endpoint | YES | Consumer calls it |
| Add required request field | YES | Consumer doesn't send it |
| Add optional request field | NO | Provider handles absence |
| Tighten validation | YES | Previously valid requests fail |
| Change status code | YES | Consumer checks it |
| Change error format | Depends | If consumer parses error body |

## Schema Validation (OpenAPI)

```bash
# Diff two OpenAPI specs for breaking changes
npx openapi-diff old-spec.yaml new-spec.yaml

# Validate request/response against schema
npx @apidevtools/swagger-cli validate openapi.yaml

# Generate types from OpenAPI
npx openapi-typescript openapi.yaml -o types.ts
```

## CI Integration Checklist

```
[ ] Consumer tests run on every PR (generate pacts)
[ ] Pacts published to broker with git SHA version
[ ] Provider verification runs on every PR
[ ] can-i-deploy gate before production deploy
[ ] Webhook: provider change triggers consumer re-verification
[ ] Pact Broker tags: main, production, staging
[ ] Provider states seed realistic test data
[ ] Contract tests in CI are fast