Playwright Network Monitoring and API Testing

This chapter introduces how to monitor browser network traffic and use Playwright for standalone API testing.


Listening to Network Requests and Responses

page.on('request') listening to requests

Example

test('Monitoring network requests', async ({ page }) => {
  const requests = [];

  // Listen to all requests
  page.on('request', request => {
    requests.push({
      url: request.url(),
      method: request.method(),
      postData: request.postData(),
    });
  });

  await page.goto('https://www.example.com/');

  // Print all requests
  console.log('The page made a total of', requests.length, 'requests');
  requests.forEach(r => console.log(r.method, r.url));
});

page.on('response') listening to responses

Example

test('Monitoring network responses', async ({ page }) => {
  page.on('response', async response => {
    // Only focus on API responses
    if (response.url().includes('/api/')) {
      console.log('API status code:', response.status());
      console.log('API URL:', response.url());
    }
  });

  await page.goto('https://www.example.com/');
});

page.waitForResponse() waiting for a specific response

Example

test('Waiting for API response to complete', async ({ page }) => {
  // Prepare to listen for the API response before clicking the button
  const responsePromise = page.waitForResponse(
    response => response.url().includes('/api/search') && response.status() === 200
  );

  // Trigger search
  await page.getByPlaceholder('Search EXAMPLE tutorial').fill('Playwright');
  await page.keyboard.press('Enter');

  // Wait for the API response
  const response = await responsePromise;
  const data = await response.json();

  // Verify the data returned by the API
  expect(data.results.length).toBeGreaterThan(0);
});

Console message listening

Example

test('Listening to console errors', async ({ page }) => {
  const consoleErrors = [];

  // Listen to console messages
  page.on('console', msg => {
    if (msg.type() === 'error') {
      consoleErrors.push(msg.text());
    }
  });

  await page.goto('https://www.example.com/');

  // Assert that the page has no JavaScript errors
  expect(consoleErrors).toHaveLength(0);
});

ConsoleMessage type

TypeCorresponding method
'log'console.log()
'error'console.error()
'warning'console.warn()
'info'console.info()
'debug'console.debug()

API Testing (request fixture)

Playwright'srequestfixture allows you towithout going through the browserdirectly send HTTP requests.

This is ideal for preparing or cleaning up server-side state before and after tests.

Sending GET requests

Example

test('API GET request', async ({ request }) => {
  const response = await request.get('https://jsonplaceholder.typicode.com/posts/1');

  // Verify the response status
  expect(response.status()).toBe(200);

  // Get JSON data
  const data = await response.json();
  expect(data.id).toBe(1);
  expect(data).toHaveProperty('title');
});

Sending POST requests

Example

test('API POST request', async ({ request }) => {
  const response = await request.post('https://jsonplaceholder.typicode.com/posts', {
    data: {
      title: 'EXAMPLE tutorial',
      body: 'Playwright API testing example',
      userId: 1,
    },
  });

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

  const data = await response.json();
  expect(data.title).toBe('EXAMPLE tutorial');
});

Configuring baseURL and authentication headers

Example

// File path: playwright.config.ts
export default defineConfig({
  use: {
    // Base URL for API requests
    baseURL: 'https://api.example.com',

    // Default request headers
    extraHTTPHeaders: {
      'Authorization': 'Bearer YOUR_API_TOKEN',
      'Accept': 'application/json',
    },
  },
});

API + browser combined testing

In real projects, APIs are often used for state management before and after browser operations.

Example

test('API prepare data + browser verification', async ({ request, page }) => {
  // Step 1: Create a test data record via API
  const response = await request.post('/api/todos', {
    data: { title: 'EXAMPLE test task', completed: false },
  });
  const todo = await response.json();

  // Step 2: Verify the data is displayed in the browser
  await page.goto('/todos');
  await expect(page.getByText('EXAMPLE test task')).toBeVisible();

  // Step 3: Clean up data via API
  await request.delete(`/api/todos/${todo.id}`);
});

API testing is much faster than browser operations and is suitable for data preparation and cleanup. Combining API and browser operations can greatly improve test efficiency and reliability.

Other extensions