🧪 Test Hub
testing: Demo target v3.0.0 · built-in demo site

DEMO-T13 TS Freight: public API in TypeScript

Edit Load test Duplicate

DEMO-020's API promises in TypeScript, with the request fixture (no page) and expect.soft (every broken promise in one run): key checks, the shipment contract, exact quote money, the trial key's rate limit.

apidemofreighttypescript DEMO-T13__freight_api_typescript.spec.ts group: Freight in TypeScriptgroup: Python and TypeScript, side by side

Runs
7
Pass rate
71%
5 passed / 2 failed
Avg duration
3s
p95 4s
Estimate
3s
avg of last 10 judged runs
Flakiness
0.33
0 stable · 1 alternates
Current streak
3
passed

Last 7 results newest on the right — click a square to open that run

Duration per run point color = outcome; dashed = 7-run average; click a point to open the run

Step timing trends the same step compared across the last 7 runs — slowest steps first, one line each

How long it takes distribution of 7 runs — two humps mean two different behaviours hiding behind one average

fastest 3s · slowest 4s

Why this test failed grouped by message, last 90 days

timesmessagelast
1 1 of 1 test(s) failed: the public API keeps its promises -- 3 problem… Sep 25 open
1 1 of 1 test(s) failed: the public API keeps its promises -- contract:… Sep 25 open

Outcomes by target version

What this test does plain language, derived from the code

    No steps found.
Show the code
import { test, expect } from '@playwright/test';

// The public API in TypeScript -- DEMO-020's promises, with two Playwright
// Test built-ins: the `request` fixture (HTTP with no page at all, relative
// to the same baseURL) and expect.soft (a broken promise is recorded and the
// test goes on, so one run reports every problem -- Python does that by hand).
const DEMO_KEY = process.env.PW_SECRET_FREIGHT_API_KEY ?? 'acme-demo-7f3a91c2';   // on the developers page
const TRIAL_KEY = 'acme-trial-2b91e4d0';                                          // 5 requests a minute
const API = 'freight/api/v1/';

test('the public API keeps its promises', async ({ request }) => {
  await test.step('auth: no key', async () => {
    const r = await request.get(API + 'shipments/AF-100001');
    expect.soft(r.status(), 'a request with no key must get 401').toBe(401);
  });

  await test.step('contract: a shipment', async () => {
    const r = await request.get(API + 'shipments/AF-100001', { headers: { 'X-API-Key': DEMO_KEY } });
    expect.soft(r.status()).toBe(200);
    if (r.ok()) {
      const body = await r.json();
      const has = Object.keys(body).sort().join(', ');
      for (const field of ['id', 'status', 'origin', 'destination', 'service', 'weight_kg', 'eta', 'events']) {
        expect.soft(body, `contract: field '${field}' is missing (the response has: ${has})`).toHaveProperty(field);
      }
    }
  });

  await test.step('money: SPRING10', async () => {
    const r = await request.post(API + 'quotes', {
      headers: { 'X-API-Key': DEMO_KEY },
      data: { origin: 'San Francisco', destination: 'San Diego', weight_kg: 120,
              service: 'standard', promo: 'SPRING10' },
    });
    expect.soft(r.status()).toBe(200);
    if (r.ok()) {
      const q = await r.json();
      expect.soft(Number(q.discount), `money: SPRING10 on a $${q.subtotal} subtotal is 10%`)
        .toBeCloseTo(Number(q.subtotal) * 0.10, 2);
    }
  });

  await test.step('limits: six calls on the trial key', async () => {
    const codes: number[] = [];
    let last = await request.get(API + 'shipments/AF-100002', { headers: { 'X-API-Key': TRIAL_KEY } });
    codes.push(last.status());
    for (let i = 1; i < 6; i++) {
      last = await request.get(API + 'shipments/AF-100002', { headers: { 'X-API-Key': TRIAL_KEY } });
      codes.push(last.status());
    }
    expect.soft(codes[codes.length - 1], `limits: 5 calls a minute, but 6 in a row answered ${codes}`).toBe(429);
    if (codes[codes.length - 1] === 429) {
      expect.soft(last.headers()['retry-after'], 'a 429 must say when to retry').toBeTruthy();
    }
  });
});

All runs

RunStatusQueuedDuration VersionTriggerBatch
#477 passed 2026-09-25 00:30:11 3s 3.0.0 group group: Python and TypeScript,…
#465 passed 2026-09-25 00:29:44 3s 3.0.0 group group: Freight in TypeScript
#431 passed 2026-09-25 00:23:39 3s 3.0.0 cli-adopted 7 tests (terminal)
#424 failed 2026-09-25 00:23:08 3s 2.1.0 cli-adopted 7 tests (terminal)
#417 failed 2026-09-25 00:22:38 3s 2.0.0 cli-adopted 7 tests (terminal)
#410 passed 2026-09-25 00:22:11 3s 1.1.0 cli-adopted 7 tests (terminal)
#403 passed 2026-09-25 00:21:43 4s 1.0.0 cli-adopted 7 tests (terminal)