A Postman collection running in CI requires Newman, and parallelization above the free tier requires Postman Cloud. Migrating to Playwright's request fixture means the same runner, the same CI command (npx playwright test), and the same fixture system your UI tests already use. This article covers the concept-by-concept translation from Postman to Playwright, the auth fixture that replaces pm.environment.set(), and why you should rewrite rather than auto-translate when migrating large collections.

The conceptual translation

| Postman concept | Playwright equivalent |

|---|---|

| Collection | Test file |

| Request | request.get(), request.post(), etc. |

| Pre-request script | beforeEach hook or fixture setup |

| Test script (pm.test) | expect() assertions |

| Environment variable | process.env.VARIABLE |

| Collection variable | Test fixture or shared constant |

| Authorization → Bearer Token | Header in request.post({ headers: { Authorization: ... } }) |

| Newman (CLI runner) | npx playwright test |

Your first Postman test rewritten in Playwright

Postman:

// POST {{baseUrl}}/auth/login
// Body: { "email": "{{email}}", "password": "{{password}}" }
// Tests tab:
pm.test("Status is 200", function() {
    pm.response.to.have.status(200);
});
pm.test("Returns token", function() {
    const body = pm.response.json();
    pm.expect(body.token).to.be.a('string');
    pm.environment.set("authToken", body.token);
});

Playwright:

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

test('login returns auth token', async ({ request }) => {
  const response = await request.post(`${process.env.BASE_URL}/auth/login`, {
    data: {
      email: process.env.TEST_EMAIL,
      password: process.env.TEST_PASSWORD,
    },
  });

  expect(response.status()).toBe(200);

  const body = await response.json();
  expect(typeof body.token).toBe('string');
  expect(body.token.length).toBeGreaterThan(0);
});

Cleaner. Version controlled. No cloud dependency.

Sharing auth token between tests

In Postman, you'd set an environment variable in one test and use it in the next. In Playwright, use a fixture or global setup.

Approach 1: Global setup (for the whole suite)

// global-setup.ts
import { request } from '@playwright/test';
import fs from 'fs';

export default async function globalSetup() {
  const ctx = await request.newContext();
  const response = await ctx.post(`${process.env.BASE_URL}/auth/login`, {
    data: {
      email: process.env.TEST_EMAIL,
      password: process.env.TEST_PASSWORD,
    },
  });
  const { token } = await response.json();

  // Save for tests to use
  process.env.AUTH_TOKEN = token;
  await ctx.dispose();
}

Approach 2: Auth fixture (per test)

// fixtures/auth.ts
import { test as base, APIRequestContext } from '@playwright/test';

type AuthFixtures = {
  authedRequest: APIRequestContext;
  authToken: string;
};

export const test = base.extend<AuthFixtures>({
  authToken: async ({ request }, use) => {
    const response = await request.post('/auth/login', {
      data: {
        email: process.env.TEST_EMAIL!,
        password: process.env.TEST_PASSWORD!,
      },
    });
    const { token } = await response.json();
    await use(token);
  },

  authedRequest: async ({ playwright, authToken }, use) => {
    const context = await playwright.request.newContext({
      baseURL: process.env.BASE_URL,
      extraHTTPHeaders: {
        Authorization: `Bearer ${authToken}`,
      },
    });
    await use(context);
    await context.dispose();
  },
});

Tests:

import { test } from '../fixtures/auth';
import { expect } from '@playwright/test';

test('get user profile (authenticated)', async ({ authedRequest }) => {
  const response = await authedRequest.get('/user/profile');
  expect(response.status()).toBe(200);

  const user = await response.json();
  expect(user.email).toBeDefined();
});

Migrating Postman collections

For large Postman collections, the migration strategy:

1. Export your collection as JSON from Postman

2. Identify the critical paths: not every Postman request needs to be a Playwright test. Focus on the ones you run as regression.

3. Translate request-by-request, starting with the simplest (GET requests, no auth)

4. Group by resource: one file per API domain (users.spec.ts, orders.spec.ts, payments.spec.ts)

Don't try to auto-translate. Postman's scripting model doesn't map cleanly to Playwright, and the mechanical translation produces unreadable tests. Rewrite them.

What Postman does better

Postman still has advantages for certain workflows:

Exploratory testing: Postman's UI is faster for one-off requests during development. You don't need to write code to try an endpoint. Documentation: Postman collections can generate API documentation. Playwright tests don't. Collaboration with non-coders: A product manager or developer who isn't comfortable with code can use Postman.

The practical division: use Postman for exploring and documenting APIs during development. Use Playwright for regression test suites that run in CI. They complement each other.

Running API tests in CI

Once you've moved tests to Playwright, CI is simple: same as any other Playwright suite.

# .github/workflows/api-tests.yml
jobs:
  api-tests:
    runs-on: ubuntu-latest
    env:
      BASE_URL: ${{ vars.STAGING_URL }}
      TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
      TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npx playwright test tests/api/

No Newman. No Postman cloud. No paid plan for CI. Just npx playwright test.

→ See also: API Testing with Playwright's APIRequestContext (No Postman Required) | Postman for QA Engineers: From First Request to API Test Suite | GitHub Actions for Playwright Tests: The Complete Setup (2026)