← All posts
GuideMarch 21, 2026·6 min read·
GitHub ActionsMockrak6

Mocking flaky third-party APIs in your CI pipeline

Use Mockra ephemeral namespaces to spin up isolated mock environments for every CI run. No shared state, no flaky third-party dependencies, deterministic test results.

The Problem

Your integration test suite calls three third-party APIs: Stripe for payments, SendGrid for emails, and an internal microservice that doesn't have a stable staging environment. The suite passes locally. In CI, it fails about 30% of the time — sometimes it's a Stripe sandbox timeout, sometimes it's the internal service returning a 503 during a deployment window, sometimes it's unexplained.

You've seen teams handle this in two ways: mark flaky tests as "skip" (and never fix them) or add retry logic that makes a 2-minute test suite take 8 minutes. Neither solves the root problem.

The root problem is that your tests have a runtime dependency on APIs you don't control and can't make deterministic.

This tutorial shows how to remove that dependency entirely using Mockra ephemeral namespaces — isolated mock environments created fresh for each CI run and destroyed when it's done.

How Ephemeral Namespaces Work

Mockra's ephemeral namespace API lets you programmatically create and destroy isolated mock environments. Each namespace is a unique URL prefix (mock.mockra.io/your-namespace/) where all your configured mock endpoints are available. Ephemeral namespaces start blank — you upload an OpenAPI schema and configure mock responses before your tests run, or point your tests at a pre-configured persistent namespace.

The workflow:

  1. CI starts → create ephemeral namespace → get namespace slug
  2. Upload your OpenAPI schema to the namespace (or use a pre-configured one)
  3. Run your test suite, pointing it at mock.mockra.io/your-namespace/
  4. CI ends → destroy the namespace

Prerequisites

  • A Mockra account with a Pro plan (ephemeral namespaces are a Pro feature)
  • A Mockra API key created in the dashboard under your workspace's API Keys section
  • GitHub Actions (the tutorial uses GitHub Actions, but the API calls work in any CI system)

Step 1: Create a Mockra API Key

  1. Go to dash.mockra.io → your workspace → API Keys section
  2. Create a key named ci-integration-tests
  3. Copy the key (mra_...) — it is shown once only
  4. Add it to your GitHub repository as a secret: Settings → Secrets and variables → Actions → New repository secret
    • Name: MOCKRA_API_KEY
    • Value: the mra_... key

Step 2: The GitHub Actions Workflow

# .github/workflows/integration-tests.yml
name: Integration Tests

on:
  pull_request:
  push:
    branches: [main]

jobs:
  integration-tests:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Create Mockra ephemeral namespace
        id: mockra
        run: |
          RESPONSE=$(curl -s -X POST https://api.mockra.io/namespaces \
            -H "Authorization: Bearer ${{ secrets.MOCKRA_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{"name": "ci-pr-${{ github.run_id }}"}')

          NAMESPACE=$(echo $RESPONSE | jq -r '.namespace.namespace')
          MOCK_BASE=$(echo $RESPONSE | jq -r '.namespace.mock_url_base')

          echo "namespace=$NAMESPACE" >> $GITHUB_OUTPUT
          echo "mock_base=$MOCK_BASE" >> $GITHUB_OUTPUT

          echo "Created namespace: $NAMESPACE"
          echo "Mock base URL: $MOCK_BASE"

      - name: Upload OpenAPI schema to namespace
        run: |
          # Upload your spec — Mockra auto-generates mock responses for every endpoint
          curl -s -X POST \
            "https://api.mockra.io/workspaces/YOUR_WORKSPACE_ID/schemas" \
            -H "Authorization: Bearer ${{ secrets.MOCKRA_API_KEY }}" \
            -F "file=@path/to/your-api-spec.yaml"

      - name: Run integration tests
        env:
          MOCK_BASE_URL: ${{ steps.mockra.outputs.mock_base }}
        run: |
          # Your test command — tests read MOCK_BASE_URL from the environment
          npm test -- --testPathPattern=integration

      - name: Destroy Mockra namespace
        if: always()
        run: |
          curl -s -X DELETE \
            "https://api.mockra.io/namespaces/${{ steps.mockra.outputs.namespace }}" \
            -H "Authorization: Bearer ${{ secrets.MOCKRA_API_KEY }}"
          echo "Namespace ${{ steps.mockra.outputs.namespace }} destroyed"

Key design decisions worth calling out:

  • if: always() on the destroy step — cleanup runs even when tests fail. No leaked namespaces.
  • github.run_id makes the namespace name unique per CI run — no conflicts on parallel PRs.
  • MOCK_BASE_URL env var — the test runner reads the namespace URL from the environment. This is the same pattern used for staging URLs, database connection strings, and any other per-environment config.
  • jq parses the JSON response — it's available by default on ubuntu-latest.

Step 3: Update Your Tests to Read the Mock URL

// tests/integration/checkout.test.js

// Read mock base URL from environment — falls back to a default for local dev
const MOCK_BASE = process.env.MOCK_BASE_URL ?? 'https://mock.mockra.io/local-dev';

describe('Checkout flow', () => {
  it('creates a payment intent', async () => {
    const response = await fetch(`${MOCK_BASE}/v1/payment_intents`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount: 2000, currency: 'usd' }),
    });

    expect(response.status).toBe(200);
    const data = await response.json();
    expect(data.id).toMatch(/^pi_/);
  });
});

The local development fallback lets developers run integration tests locally against a persistent namespace. CI runs against a fresh ephemeral one. The test code is identical in both cases.

Step 4: Handling Parallel CI Runs

github.run_id ensures uniqueness — two concurrent PRs each get their own namespace, no shared state. Matrix builds work the same way:

- name: Create Mockra ephemeral namespace
  id: mockra
  run: |
    RESPONSE=$(curl -s -X POST https://api.mockra.io/namespaces \
      -H "Authorization: Bearer ${{ secrets.MOCKRA_API_KEY }}" \
      -H "Content-Type: application/json" \
      -d '{"name": "ci-${{ github.run_id }}-${{ matrix.node-version }}"}')

    NAMESPACE=$(echo $RESPONSE | jq -r '.namespace.namespace')
    MOCK_BASE=$(echo $RESPONSE | jq -r '.namespace.mock_url_base')

    echo "namespace=$NAMESPACE" >> $GITHUB_OUTPUT
    echo "mock_base=$MOCK_BASE" >> $GITHUB_OUTPUT

Testing Failure Scenarios in CI

This is where mocking genuinely earns its keep. Configure mock endpoints to return error responses, then run a separate test suite that verifies your app handles downstream failures correctly.

In the dashboard, set POST /v1/payment_intents to return a 503:

{
  "error": {
    "message": "Service temporarily unavailable"
  }
}

Then in your workflow:

- name: Run resilience tests
  env:
    MOCK_BASE_URL: ${{ steps.mockra.outputs.mock_base }}
    TEST_SCENARIO: payment_service_down
  run: npm test -- --testPathPattern=resilience

Test how your checkout page handles a Stripe outage — deterministically, in CI, before it happens in production.

GitLab CI Equivalent

The same pattern in GitLab CI syntax:

# .gitlab-ci.yml
integration_tests:
  stage: test
  script:
    - |
      RESPONSE=$(curl -s -X POST https://api.mockra.io/namespaces \
        -H "Authorization: Bearer $MOCKRA_API_KEY" \
        -H "Content-Type: application/json" \
        -d "{\"name\": \"ci-${CI_PIPELINE_ID}\"}")
      NAMESPACE=$(echo $RESPONSE | jq -r '.namespace.namespace')
      MOCK_BASE=$(echo $RESPONSE | jq -r '.namespace.mock_url_base')
    - MOCK_BASE_URL=$MOCK_BASE npm test -- --testPathPattern=integration
    - curl -s -X DELETE "https://api.mockra.io/namespaces/${NAMESPACE}" -H "Authorization: Bearer $MOCKRA_API_KEY"

Wrap-Up

Every CI run now gets its own isolated mock environment. Tests that were flaky because of third-party API dependencies are now deterministic. The namespace is cleaned up automatically — no infrastructure to manage.

Ephemeral namespaces are available on Mockra Pro. If you're evaluating, the free tier lets you test with a persistent namespace — the mock endpoint behavior is identical.

Start for free → | View Pro plans →

Try Mockra free

5,000 requests/month, no credit card required. Upload an OpenAPI spec and get mock endpoints in under 60 seconds.

Start for freeTry error.mockra.io