The Problem: Flaky Tests from Random Data
Mock APIs are great for development, but random data can cause flaky tests. Your test passes locally, fails in CI, then passes again on retry. The culprit? Different mock data on each request.
Consider this test:
test('displays user count', async () => {
const res = await fetch('https://apis.aximcode.com/v1/core/users');
const { users } = await res.json();
// This might fail if the mock returns different data!
expect(users.length).toBe(10);
});
AximCode solves this with two features: Deterministic Seeding for stateless reproducibility, and Data Snapshots for stateful test scenarios.
Deterministic Seeding: Same Seed, Same Data
Add ?_seed=123 to any list endpoint. The same seed always returns identical data.
# These requests ALWAYS return identical data
curl "https://apis.aximcode.com/v1/core/users?_seed=12345"
curl "https://apis.aximcode.com/v1/core/users?_seed=12345"
# Different seed = different data
curl "https://apis.aximcode.com/v1/core/users?_seed=99999"
Using Seeds in Tests
const API_BASE = 'https://apis.aximcode.com';
const TEST_SEED = 42;
test('seed 42 always returns the same user data', async () => {
const res = await fetch(`${API_BASE}/v1/core/users?_seed=${TEST_SEED}`);
const { users } = await res.json();
// These exact values are GUARANTEED for seed=42
expect(users[0].name).toBe('Dr. Nelson Wisozk');
expect(users[0].email).toBe('moses5@yahoo.com');
expect(users[1].name).toBe('Johanna Dooley');
expect(users[1].email).toBe('judson_greenfelder13@gmail.com');
});
test('multiple requests with same seed return identical data', async () => {
const url = `${API_BASE}/v1/core/users?_seed=${TEST_SEED}`;
// Make two separate requests
const res1 = await fetch(url);
const res2 = await fetch(url);
const data1 = await res1.json();
const data2 = await res2.json();
// Identical responses every time - fully deterministic
expect(data1.users[0].name).toBe(data2.users[0].name);
expect(data1.users[0].email).toBe(data2.users[0].email);
expect(JSON.stringify(data1)).toBe(JSON.stringify(data2));
});
Seeding in CI/CD Pipelines
Use the same seed across your entire test suite for consistent results:
# GitHub Actions example
env:
MOCK_API_SEED: 12345
steps:
- name: Run tests
run: npm test
// test-setup.js
const TEST_SEED = process.env.MOCK_API_SEED || 12345;
export function mockUrl(path) {
const url = new URL(path, 'https://apis.aximcode.com');
url.searchParams.set('_seed', TEST_SEED);
return url.toString();
}
When to Use Deterministic Seeding
- Unit tests: Test UI components with consistent data
- Integration tests: Verify API response handling
- CI/CD pipelines: Eliminate flaky tests from random data
- Debugging: Reproduce exact responses for investigation
Data Snapshots: Save and Restore Database States
For more complex scenarios involving state, use Data Snapshots. Create a snapshot of your current data, run tests that modify it, then restore to the original state.
Snapshot API
# Create a snapshot before tests
curl -X POST https://apis.aximcode.com/api/data/snapshots \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{"name": "before-integration-tests"}'
# Run your tests (they can modify data freely)
npm test
# Restore to clean state
curl -X POST https://apis.aximcode.com/api/data/snapshots/{id}/restore \
-H "X-API-Key: your_api_key"
Snapshot Workflow in CI/CD
# GitHub Actions workflow
jobs:
test:
steps:
- name: Create test snapshot
run: |
SNAPSHOT_ID=$(curl -s -X POST \
-H "X-API-Key: $AXIMCODE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "ci-run-123"}' \
https://apis.aximcode.com/api/data/snapshots | jq -r '.snapshot.id')
echo "SNAPSHOT_ID=$SNAPSHOT_ID" >> $GITHUB_ENV
- name: Run integration tests
run: npm run test:integration
- name: Restore snapshot
if: always()
run: |
curl -X POST \
-H "X-API-Key: $AXIMCODE_API_KEY" \
https://apis.aximcode.com/api/data/snapshots/$SNAPSHOT_ID/restore
Note: Replace $AXIMCODE_API_KEY with your secrets reference (e.g., GitHub Actions secrets).
When to Use Snapshots
- Integration tests: Tests that create, update, or delete data
- E2E tests: Full workflow tests that modify state
- Test isolation: Ensure tests don't affect each other
- Multiple scenarios: Different snapshots for different test suites
Choosing the Right Approach
| Scenario | Recommended Approach |
|---|---|
| Read-only tests (GET requests) | Deterministic Seeding - Simple, no setup needed |
| Tests that modify data | Snapshots - Restore clean state after |
| Free tier usage | Deterministic Seeding - Available on all tiers |
| Complex test scenarios | Both - Seeding for reads, snapshots for state |
Snapshot Limits by Plan
Snapshots are available on paid plans:
- Developer ($9/mo): 5 snapshots
- Team ($19/mo): 10 snapshots
- Business ($29/mo): 25 snapshots
- Enterprise: Unlimited snapshots
Complete Example: E2E Test Suite
Here's a complete example combining both features:
// test/setup.js
const API_KEY = process.env.AXIMCODE_API_KEY;
const BASE_URL = 'https://apis.aximcode.com';
const TEST_SEED = 42;
let snapshotId;
beforeAll(async () => {
// Create snapshot before any tests run
const res = await fetch(`${BASE_URL}/api/data/snapshots`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: `test-run-${Date.now()}` }),
});
const data = await res.json();
snapshotId = data.snapshot.id;
});
afterAll(async () => {
// Restore snapshot after all tests complete
await fetch(`${BASE_URL}/api/data/snapshots/${snapshotId}/restore`, {
method: 'POST',
headers: { 'X-API-Key': API_KEY },
});
});
// Helper for seeded requests
export function seededUrl(path) {
return `${BASE_URL}${path}?_seed=${TEST_SEED}`;
}
// test/users.test.js
import { seededUrl } from './setup';
test('seed 42 returns known user values', async () => {
const res = await fetch(seededUrl('/v1/core/users'));
const { users } = await res.json();
// With seed=42, these values are guaranteed
expect(users[0].name).toBe('Dr. Nelson Wisozk');
expect(users[0].email).toBe('moses5@yahoo.com');
expect(users[1].name).toBe('Johanna Dooley');
});
test('create user works', async () => {
const res = await fetch('https://apis.aximcode.com/v1/core/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Test User', email: 'test@example.com' }),
});
expect(res.status).toBe(201);
// Data will be restored by afterAll hook
});
Seed Explorer: Preview Data Before Writing Tests
Not sure what values a seed will generate? Use the Seed Explorer in the API Explorer to preview data before writing your tests.
The Seed Explorer lets you:
- Enter any seed number and instantly see the generated data
- Browse all domains (Core, Bookstore, Fintech, Healthcare)
- Export data as JSON fixtures for your test files
- Copy individual entity collections to clipboard
To access it, go to /explore and click the "Seed Explorer" toggle in the header. Enter a seed (like 42) and click "Generate Preview" to see exactly what data your tests will receive.
Get Started
Deterministic seeding is available on all tiers, including free. Just add ?_seed=123 to any list endpoint.
For data snapshots, upgrade to a paid plan and manage snapshots from your dashboard or via the API.
Use the Seed Explorer to preview seeded data and generate test fixtures.
Check out our API documentation for the full endpoint reference.