VALIDATION LAB•FAKE REST API
Requests
Fake REST API
Send canned REST requests and receive deterministic JSON responses; toggle a forced 500 to drive negative-path coverage.
Why this matters in QA
QA engineers must read JSON the way frontend engineers read TypeScript. A test that drives the UI is half the story — assertions on the network payload close the loop and catch silent contract drift.
// click Send to inspect the response
Live widget · interact freely
Manual test checklist
- 1Pick `GET /wallet/balance` and Send — body matches the documented contract
- 2Force 500 — code chip flips rose, body shows error structure
- 3Pick `DELETE /sessions/me` — code 204, body is `{ ok: true }`
- 4Confirm the response panel preserves indentation (no stripped whitespace)
- 5Confirm the `rest-code` chip exposes the numeric status code
Expected result
Send returns a 200 (or 204 for DELETE) with the canonical body. Force 500 returns `{ error: 'ledger_timeout' }` with code 500.
Automation challenge
Combine `page.route('**/api/wallet/balance', ...)` with this widget — but use the on-screen Send button to drive the UI. Assert `getByTestId('rest-code')` reads `200`, then assert `rest-body` contains `"balance": 4099.12`.
Stable selectors
- Route select
[data-testid="rest-route"] - Send
[data-testid="rest-send"] - Force 500
[data-testid="rest-send-fail"] - Status code chip
[data-testid="rest-code"] - Response body
[data-testid="rest-body"]
Reference Playwright spec
1234567891011
import { test, expect } from '@playwright/test';
test('fake rest endpoint returns canonical balance', async ({ page }) => {
await page.goto('https://lab.hakdogan.com/data-api/fake-rest');
await page.getByTestId('rest-route').selectOption('GET /wallet/balance');
await page.getByTestId('rest-send').click();
await expect(page.getByTestId('rest-code')).toHaveText('200');
await expect(page.getByTestId('rest-body')).toContainText('"balance": 4099.12');
});