Playwright API Testing and Reusing Authentication
Introduction
Playwright is not limited to the browser. Its request fixture sends HTTP calls, so you can test APIs directly or prepare test data quickly. You can also sign in once and reuse that saved session in every test, which saves a lot of time. This lesson covers both.
Prerequisites
- Playwright fixtures and configuration basics
- A basic understanding of REST and HTTP status codes
Step-by-Step Guide
Step 1: Send API requests
The request fixture exposes get, post, put, and delete. Check the response with expect and read JSON with response.json().
import { test, expect } from '@playwright/test';
test('GET a post', async ({ request }) => {
const response = await request.get('https://jsonplaceholder.typicode.com/posts/1');
expect(response.ok()).toBeTruthy();
const body = await response.json();
expect(body.id).toBe(1);
});Step 2: Create data with POST
Pass a data object and Playwright sends it as JSON. Assert on the status code your API documents.
test('POST a post', async ({ request }) => {
const response = await request.post('https://jsonplaceholder.typicode.com/posts', {
data: { title: 'CaliberTek', body: 'Hello', userId: 1 },
});
expect(response.status()).toBe(201);
});Step 3: Combine API setup with UI checks
Use the API to create the data a test needs, then verify it in the browser. This is much faster and more reliable than building state by clicking through the UI.
Step 4: Write a setup test that signs in once
A setup test logs in through the UI and saves cookies and local storage to a file. Read credentials from environment variables rather than hard-coding them.
// tests/auth.setup.ts
import { test as setup } from '@playwright/test';
import path from 'path';
const authFile = path.join(__dirname, '../playwright/.auth/user.json');
setup('authenticate', async ({ page }) => {
await page.goto('https://example.com/login');
await page.getByLabel('Username').fill(process.env.APP_USER!);
await page.getByLabel('Password').fill(process.env.APP_PASSWORD!);
await page.getByRole('button', { name: 'Sign in' }).click();
await page.waitForURL('**/dashboard');
await page.context().storageState({ path: authFile });
});Step 5: Reuse the session in your projects
Create a setup project and make the browser project depend on it. Every test then starts already signed in. Add the auth folder to .gitignore so session files are never committed.
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
storageState: 'playwright/.auth/user.json',
},
dependencies: ['setup'],
},
],
});FAQs
- Does storageState save everything about a session?
- It saves cookies and local storage. Data kept only in sessionStorage is not included, so apps that store tokens there need extra handling.
- Why test the API separately from the UI?
- API tests run in milliseconds and pinpoint backend problems without browser noise. Reserve UI tests for behavior that really needs a browser.
Summary
Use the request fixture for fast API checks and data setup, and save an authenticated session once so every UI test can skip the login. Keep credentials in environment variables and session files out of Git.
Comments
Log in or create a free account to join the discussion.