You know this feeling. A test passes locally, fails in CI, you rerun it, it passes again. Somewhere a third-party API was slow, or returned something unexpected, or was just briefly down. You move on, but it happens again next week.
And that's before you even get to the scenarios you can't test at all: rate limits, timeouts, malformed responses. You can't make a live API produce those on demand. So those code paths go untested.
Mocking solves both problems. Mokapi gives you a spec-validated mock server driven by your OpenAPI or AsyncAPI specs. Every response conforms to the contract. Every request gets validated. Your tests run against something you fully control.
The CI Setup
Mokapi runs in Docker during your test job. Your app points at it instead of the real API. That's the whole switch.
- name: Start Mokapi
run: |
docker run -d --name mokapi \
-p 80:80 \
-v ${{ github.workspace }}/mocks:/mocks \
mokapi/mokapi:latest /mocks
sleep 5
- name: Run Tests
run: npm test
- name: Stop Mokapi
run: docker stop mokapi
Your mock specs live in /mocks in the repo, versioned alongside the code. When the API contract changes, the spec changes, the mock changes, and the tests run against the updated contract automatically.
Simulating the Scenarios That Matter
This is where it gets useful beyond just removing the external dependency. With Mokapi's JavaScript API you can control behavior at runtime without restarting anything.
import { on, sleep } from 'mokapi'
export default () => {
let delay = undefined
on('http', (request, response) => {
if (request.key === '/simulations/delay') {
switch (request.method) {
case 'PUT':
delay = request.query.duration
break
case 'DELETE':
delay = undefined
break
}
}
}, { track: true })
on('http', (request, response) => {
if (delay) {
sleep(delay)
}
}, { track: () => delay !== undefined })
}
Your test sends a PUT to enable a delay, runs the scenario, sends a DELETE to reset. Same pattern works for forcing 500s, 429 rate limits, or any other condition you want to test against.
The track: true on the first handler is worth understanding. Mokapi's dashboard shows every HTTP request with the response and all JavaScript handlers that ran for it. The first handler only updates internal state without touching the response, so Mokapi wouldn't know it was relevant unless you tell it explicitly. track: true keeps it visible in the dashboard, which matters when you're debugging why a test behaved unexpectedly.
What You Actually Get
Consistent test results because nothing outside your control can break them. Coverage of error scenarios that a live API can't reproduce on demand. Faster pipeline runs with no network latency. And because Mokapi validates against the spec, contract violations get caught in CI before they reach production.
Full Walkthrough
The complete guide on mokapi.io covers the full GitHub Actions setup, the JavaScript simulation API, and how to structure your mock specs for a real project.
Happy to answer questions in the comments.
Top comments (0)