VALIDATION LABFAKE REST API

Requests

Fake REST API

Send canned REST requests and receive deterministic JSON responses; toggle a forced 500 to drive negative-path coverage.

Intermediate

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

fake-rest.spec.ts
ts
1
2
3
4
5
6
7
8
9
10
11
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');
});