https://github.com/adrozdenko/pactwork
Contract-first API simulation framework - Mocks you can trust
https://github.com/adrozdenko/pactwork
api-testing contract-testing mock msw openapi typescript
Last synced: 24 days ago
JSON representation
Contract-first API simulation framework - Mocks you can trust
- Host: GitHub
- URL: https://github.com/adrozdenko/pactwork
- Owner: adrozdenko
- License: mit
- Created: 2026-02-04T23:11:02.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-02-05T12:27:09.000Z (about 2 months ago)
- Last Synced: 2026-02-05T13:07:18.538Z (about 2 months ago)
- Topics: api-testing, contract-testing, mock, msw, openapi, typescript
- Language: TypeScript
- Size: 118 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
- Roadmap: ROADMAP.md
Awesome Lists containing this project
README
Pactwork
Generate API mocks from your OpenAPI spec. They stay in sync automatically.
Why Pactwork •
Quick Start •
Storybook •
Runtime •
CI/CD •
Roadmap
---
## Why Pactwork
**The problem:** API mocks drift from reality. You write them manually, the API evolves, and suddenly your tests pass but production breaks.
**The fix:** Point Pactwork at your OpenAPI spec. It generates [MSW](https://mswjs.io/) mocks, validates them continuously, and tells you the moment they fall out of sync.
| Without Pactwork | With Pactwork |
|------------------|---------------|
| Write mocks by hand | Generate from your spec |
| Hope they match the API | Validate automatically |
| Miss error states | Test every response your API can return |
| Debug in production | Catch drift in development |
```bash
# One command. Mocks that match your API.
npx pactwork generate --spec ./openapi.yaml
```
---
## Key Features
| Feature | What you get |
|---------|-------------|
| **Mock Generation** | Generate MSW mock handlers from any OpenAPI 2.0, 3.0, or 3.1 spec |
| **Drift Detection** | Know immediately when your mocks fall out of sync with the spec |
| **Scenario Catalog** | Test every error your API can return (404, 500, timeouts, etc.) |
| **Runtime Utilities** | Simulate latency, flaky networks, and error sequences in tests |
| **Storybook Addon** | Switch API states directly from the Storybook toolbar |
| **Coverage Reporting** | See which API scenarios your Storybook stories cover |
| **CI Gates** | Block deployments when mocks don't match the spec |
| **Type Generation** | Get TypeScript types from your spec, always up to date |
---
## Quick Start
### Install
```bash
npm install -D pactwork msw
```
### Generate mocks
```bash
# Generate MSW mock handlers from your OpenAPI spec
npx pactwork generate --spec ./openapi.yaml --output ./src/mocks
# Include error scenarios for testing
npx pactwork generate --spec ./openapi.yaml --with-scenarios
```
### What you get
Pactwork generates ready-to-use MSW handlers and a scenario catalog:
```
src/mocks/
├── handlers.ts # MSW handlers for every endpoint in your spec
└── scenarios.ts # Error/edge case responses (404, 500, etc.)
```
```typescript
// handlers.ts (generated)
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/api/users/:id', () => {
return HttpResponse.json({ id: 1, name: 'Jane Doe', email: 'jane@example.com' })
}),
http.post('/api/users', () => {
return HttpResponse.json({ id: 2, name: 'New User' }, { status: 201 })
}),
// ... one handler per operation in your spec
]
```
### Use with MSW
**Browser (Storybook, development):**
```typescript
import { setupWorker } from 'msw/browser'
import { handlers } from './mocks/handlers'
const worker = setupWorker(...handlers)
await worker.start()
```
**Node (tests):**
```typescript
import { setupServer } from 'msw/node'
import { handlers } from './mocks/handlers'
const server = setupServer(...handlers)
beforeAll(() => server.listen())
afterAll(() => server.close())
```
---
## Storybook Integration
Test every API state visually with `@pactwork/storybook-addon`.
### Install
```bash
npm install -D @pactwork/storybook-addon
```
### Configure
Register the addon in your Storybook config:
```typescript
// .storybook/main.ts
export default {
addons: ['@pactwork/storybook-addon'],
}
```
Then set up toolbar controls in your preview. See the [full Storybook setup guide](packages/storybook-addon/README.md) for the complete configuration.
### What it does
| Control | Purpose |
|---------|---------|
| **Scenario dropdown** | Switch between success, error, and edge case responses |
| **Latency selector** | Simulate slow networks (0ms to 5s) |
| **Network toggle** | Simulate offline and connection errors |
| **Addon panel** | See request logs, active state, and available mock handlers |
### Set scenarios per story
```typescript
// UserCard.stories.tsx
import { setScenario, resetState, setLatency } from '../mocks/handlers'
export const Loading: Story = {
beforeEach: () => {
resetState()
setLatency(3000)
},
}
export const NotFound: Story = {
beforeEach: () => {
resetState()
setScenario('getUser', 'notFound')
},
}
export const ServerError: Story = {
beforeEach: () => {
resetState()
setScenario('getUser', 'serverError')
},
}
```
---
## Runtime Utilities
Control API behavior programmatically in your tests.
```typescript
import { handlers, handlerMeta, scenarios } from './mocks'
import { applyScenario, withLatency, withSequence, pipe } from 'pactwork/runtime'
// Return a 404 for getUser
const errorHandlers = applyScenario(handlers, handlerMeta, 'getUser', scenarios.getUser.notFound)
// Slow down all responses by 500ms
const slowHandlers = withLatency(handlers, handlerMeta, 500)
// Simulate a flaky API: fail twice, then succeed
const flakyHandlers = withSequence(handlers, handlerMeta, 'getUser', [500, 500, 200])
// Compose multiple behaviors
const testHandlers = pipe(
handlers,
h => withLatency(h, handlerMeta, 100),
h => applyScenario(h, handlerMeta, 'getUser', scenarios.getUser.notFound)
)
```
### Available utilities
| Utility | What it does |
|---------|-------------|
| `applyScenario(handlers, meta, operationId, scenario)` | Replace a response with an error or edge case |
| `withLatency(handlers, meta, ms)` | Add delay to all responses |
| `withLatency(handlers, meta, operationId, ms)` | Add delay to one operation |
| `withSequence(handlers, meta, operationId, statuses)` | Return different statuses in sequence |
| `withRateLimit(handlers, meta, operationId, opts)` | Simulate rate limiting (429) |
| `withNetworkError(handlers, meta, operationId, opts)` | Simulate timeout, abort, or connection errors |
| `withSeed(handlers, meta, seed)` | Deterministic response data |
| `pipe(handlers, ...transformers)` | Compose multiple utilities together |
---
## CLI Commands
| Command | What it does |
|---------|-------------|
| `pactwork generate` | Generate MSW mock handlers from your spec |
| `pactwork validate` | Check if mocks match the spec |
| `pactwork breaking` | Compare two spec versions for breaking changes |
| `pactwork types` | Generate TypeScript types from your spec |
| `pactwork scenarios` | List available error scenarios from your spec |
| `pactwork coverage` | Report which scenarios your Storybook stories cover |
| `pactwork can-i-deploy` | CI gate — block deploys when mocks drift |
| `pactwork record` | Create a contract from your spec |
| `pactwork verify` | Verify a contract against the current spec |
### Common flags
```bash
# CI mode — minimal output, strict exit codes
pactwork validate --ci
# Auto-fix — regenerate when drift is found
pactwork validate --fix
# Generate with error scenarios
pactwork generate --with-scenarios
# Compare API versions for breaking changes
pactwork breaking --old v1.yaml --new v2.yaml
# GitHub Actions annotations
pactwork validate --format github
# Coverage with minimum threshold
pactwork coverage --min-coverage 80
```
---
## CI Integration
### GitHub Action
```yaml
- uses: adrozdenko/pactwork@v1
with:
spec: ./openapi.yaml
```
### CLI in CI
```yaml
steps:
- name: Validate mocks
run: npx pactwork validate --ci --format github
- name: Check deployment safety
run: npx pactwork can-i-deploy
```
### Exit codes
| Code | Meaning |
|------|---------|
| `0` | Mocks match the spec |
| `1` | Drift or breaking changes detected |
| `2` | Warnings treated as errors |
---
## Automated Drift Repair
For CI pipelines and AI agents, use this workflow to auto-fix drift:
```bash
# 1. Check for drift
pactwork validate --ci
# Exit 0 = mocks match, done
# Exit 1 = drift detected, continue
# 2. Regenerate mocks
pactwork generate
# 3. Verify the fix
pactwork validate --ci
# 4. Commit
git add src/mocks
git commit -m "fix: regenerate mocks from updated spec"
```
---
## Configuration
Create `pactwork.config.ts` for project-wide settings:
```typescript
import { defineConfig } from 'pactwork'
export default defineConfig({
spec: { path: './api/openapi.yaml' },
generate: {
output: './src/mocks',
typescript: true,
},
})
```
---
## Requirements
- Node.js 20.11+
- MSW 2.x
- OpenAPI 2.0, 3.0, or 3.1 spec
---
## Contributing
```bash
git clone https://github.com/adrozdenko/pactwork.git
npm install
npm test
```
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
---
## License
MIT © [adrozdenko](https://github.com/adrozdenko)