SoftwareTestPilot
Automation TestingPublished: 12 min read

Playwright API Testing — The Complete Guide (2026)

Skip Postman for automated checks — Playwright's request context runs API + UI tests in one runner, one report, and one CI job. Full setup, auth patterns, contract snapshots, and a worked login-to-checkout suite.

Avinash K
Founder & QA Engineer at SoftwareTestPilot
Share:XLinkedInWhatsApp
Playwright API testing with request context — auth, contracts, and CI.
Playwright API testing with request context — auth, contracts, and CI.

Last updated 2026-07-20 · 12 min read · By Avinash K

Playwright's request context is the most under-used API testing feature in QA. It gives you HTTP calls, shared auth state, and trace-viewer debugging inside the same runner as your UI tests — which means one report, one CI job, and no more "Postman collection last updated 2023" tickets.

Key takeaways

  • Set up request.newContext() in 5 lines.
  • Reuse the browser's auth cookies for API calls (no double login).
  • Snapshot response contracts to catch breaking changes.
  • A full login → create order → assert API + UI worked example.

1. Basic setup

import { test, expect } from '@playwright/test';

test('GET /api/health returns 200', async ({ request }) => {
  const res = await request.get('/api/health');
  expect(res.status()).toBe(200);
  expect(await res.json()).toMatchObject({ status: 'ok' });
});

The request fixture is built into every test — no plugin, no extra package.

2. Sharing auth with the browser

// global-setup.ts
import { request } from '@playwright/test';
export default async () => {
  const ctx = await request.newContext();
  const res = await ctx.post('/api/login', { data: { email, password } });
  await ctx.storageState({ path: 'auth.json' });
};

// playwright.config.ts
use: { storageState: 'auth.json' }

Now every UI test and every API test reuses the same session — no duplicate login, no flaky token expiry.

3. Contract snapshots

test('order response contract', async ({ request }) => {
  const res = await request.post('/api/orders', { data: { sku: 'ABC', qty: 1 } });
  expect(await res.json()).toMatchSnapshot('order.json');
});

The first run writes the snapshot; every subsequent run fails on shape drift. Cheaper than a full Pact setup for internal APIs.

4. Login → API → UI worked example

test('checkout via API, verify in UI', async ({ page, request }) => {
  const order = await request.post('/api/orders', {
    data: { sku: 'ABC', qty: 2 },
  });
  const { id } = await order.json();

  await page.goto(`/orders/${id}`);
  await expect(page.getByRole('heading', { name: /order confirmed/i })).toBeVisible();
});

See Playwright fixtures deep dive for how to wrap this in a fixture, and the locators guide for the UI half. Full docs: playwright.dev/docs/api-testing.

Frequently asked questions

1.Does this replace Postman entirely?
For automated regression, yes. Keep Postman for exploratory API work and for sharing collections with non-coders — but move CI checks to Playwright.
2.Can I use Playwright API testing without a browser?
Yes. request.newContext() runs headless with zero browser overhead — perfect for pure API suites in CI.
3.How do I handle bearer tokens?
Set them in extraHTTPHeaders on the context, or capture them in globalSetup and store in auth.json. Never hardcode tokens in tests.
4.What about GraphQL?
Use request.post() with query and variables in the JSON body. Playwright treats it as a normal POST — no special plugin needed.