Skip to content

notNullThen/simple-api-playwright-nodejs

Repository files navigation

simple-api-playwright

npm NuGet GitHub

Type-safe API testing with Playwright. Request intercepts, type-safe endpoints, and dual-mode support for both API and UI tests.

Make API requests like this:

const response = await api.createUser(user).request();

Or API waits like this:

const [, userResponse] = await Promise.all([
  page.click(loginButton),
  api.getUser(userId).wait(),
]);

Before that, define your API endpoints like this:

import { APIEndpointBase } from "simple-api-playwright";

export default class UsersAPI extends APIEndpointBase {
  constructor(context: APIContext) {
    super(context, "api/users");
  }

  getUser = async (id: string) =>
    this.action<User>({ url: `/users/${id}`, method: "GET" });

  createUser = async (body: User) =>
    this.action<User>({ url: "/users", method: "POST", body });
}

Installation

npm install --save-dev simple-api-playwright @playwright/test

Quick Start

  1. Configure APIClient:
import { APIClient } from "simple-api-playwright";

APIClient.setInitialConfig({
  baseURL: "https://api.example.com",
  apiWaitTimeout: 5000,
  expectedStatusCodes: [200, 201],
});

// Set bearer token for authenticated requests
APIClient.setBearerToken(request, "your-jwt-token");
  1. Create your API endpoint class:
import { APIEndpointBase } from "simple-api-playwright";

export default class UsersAPI extends APIEndpointBase {
  constructor(context: APIContext) {
    super(context, "api/users");
  }

  getUser = async (id: string) =>
    this.action<User>({ url: `/users/${id}`, method: "GET" });

  createUser = async (body: User) =>
    this.action<User>({ url: "/users", method: "POST", body });
}
  1. Use it in your tests:
import { test } from "@playwright/test";

test("fetch user", async ({ request }) => {
  const api = new UsersAPI(request);
  const { responseBody: user } = await api.getUser("some-id");
});
  1. With UI interactions:
test("click and verify", async ({ page }) => {
  const api = new UsersAPI(page);
  const [, response] = await Promise.all([
    page.click(loginButton),
    api.getUser("some-id").wait(),
  ]);
});

Features

  • ✨ Type-safe HTTP requests with TypeScript generics
  • 🎭 Dual-mode: Direct API calls or UI-based request interception
  • 🔐 Built-in bearer token support
  • ⚡ Minimal dependencies (Playwright peer dependency)
  • 🌐 Works with Node.js, browser, ESM, and CommonJS

Authentication & Configuration

Setting Global Configuration

The best place to configure APIClient.setInitialConfig() is in your playwright.config.ts file, so all tests automatically use consistent API settings:

// playwright.config.ts
import { defineConfig } from "@playwright/test";
import { APIClient } from "simple-api-playwright";

const additionalConfig = {
  apiWaitTimeout: 5 * 1000,
  expectedAPIResponseCodes: [200, 201],
};

APIClient.setInitialConfig({
  baseURL: "https://api.example.com",
  apiWaitTimeout: additionalConfig.apiWaitTimeout,
  expectedStatusCodes: additionalConfig.expectedAPIResponseCodes,
});

export default defineConfig({
  testDir: "./tests",
  fullyParallel: true,
  use: {
    baseURL: "https://api.example.com",
    actionTimeout: 5000,
  },
});

This ensures all tests and workers inherit the same configuration without repetition.

Bearer Token Authentication

Set the bearer token for authenticated requests. Typically done after login in your test fixtures:

const loginResponse = await loginPage.login(email, password);
const token = loginResponse.authentication.token;
APIClient.setBearerToken(request, token);

This is especially useful in parallel test workers where each worker needs separate authentication:

export const test = baseTest.extend({
  page: async ({ page }, use) => {
    const context = page.context();
    const loginResponse = await loginToCurrentUser(context.request);

    const token = loginResponse.token;
    APIClient.setBearerToken(context.request, token);

    await use(page);
  },
});

Parallel Worker Support

For parallel test execution, manage separate user accounts and authentication per worker:

const createdUsers = new Map<number, User>();
const loginResponses = new Map<number, LoginResponse>();

export const test = baseTest.extend({
  createdUser: [
    async ({}, use) => {
      const workerIndex = test.info().workerIndex;
      await use(createdUsers.get(workerIndex));
    },
    { scope: "worker" },
  ],
  loginResponse: [
    async ({}, use) => {
      const workerIndex = test.info().workerIndex;
      const loginResponse = loginResponses.get(workerIndex);
      await use(loginResponse);
    },
    { scope: "worker" },
  ],
  page: async ({ page }, use) => {
    const context = page.context();
    const workerIndex = test.info().workerIndex;

    // Acquire user account for this worker
    const user = await acquireUserForWorker(context.request, workerIndex);

    // Login and set bearer token
    const loginResponse = await loginUser(context.request, user);
    APIClient.setBearerToken(context.request, loginResponse.token);

    createdUsers.set(workerIndex, user);
    loginResponses.set(workerIndex, loginResponse);

    await use(page);
  },
});

This ensures each parallel worker has its own authenticated session.

For more examples and detailed API docs, see GitHub.

License

MIT © 2026 Jeno Pekarjuk

About

Simple API client NuGet package for Playwright Node.js

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors