Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Microsoft Playwright APIRequestContext Dispose

From Leeroopedia
Knowledge Sources
Domains API_Testing, HTTP, Test_Teardown
Last Updated 2026-02-11 00:00 GMT

Overview

Concrete tool for cleaning up test-created resources via HTTP DELETE requests and disposing of HTTP client contexts after tests complete, provided by the Playwright library.

Description

Playwright provides multiple mechanisms for test teardown and resource cleanup:

test.afterAll() Hook

The afterAll hook (defined at packages/playwright/types/test.d.ts:L6121-6162) runs once after all tests in a file or describe block have completed. It receives the request fixture, allowing tests to make API calls to clean up server-side resources. This hook always runs, even when tests fail, ensuring cleanup is not skipped.

request.delete() Method

The delete() method sends an HTTP DELETE request to remove resources created during test setup. It follows the same pattern as other request methods, accepting a URL and optional configuration.

context.dispose() Method

The dispose() method (implemented at packages/playwright-core/src/client/fetch.ts:L110-129) releases all resources held by the APIRequestContext:

  • On the server side (packages/playwright-core/src/server/fetch.ts:L654-659), disposal flushes any active tracing artifacts and clears the stored response bodies from memory.
  • Once disposed, the context can no longer be used to make requests.
  • The method accepts an optional { reason?: string } parameter to document why the context was disposed.

Symbol.asyncDispose Support

The APIRequestContext implements Symbol.asyncDispose (at packages/playwright-core/src/client/fetch.ts:L106-108), enabling automatic disposal when used with the await using syntax in TypeScript 5.2+.

Usage

Use test.afterAll() with request.delete() to remove test-created resources from the server. Call dispose() on any manually created APIRequestContext instances (those created via APIRequest.newContext()). The built-in request fixture is automatically disposed by Playwright and does not require manual disposal.

Code Reference

Source Location

  • Repository: playwright
  • afterAll hook: packages/playwright/types/test.d.ts:L6121-6162
  • Client dispose: packages/playwright-core/src/client/fetch.ts:L110-129
  • Server dispose: packages/playwright-core/src/server/fetch.ts:L654-659
  • Symbol.asyncDispose: packages/playwright-core/src/client/fetch.ts:L106-108

Signature

// Test teardown hook
test.afterAll(
  inner: (args: { request: APIRequestContext }, testInfo: TestInfo) => Promise<any>
): void;

// HTTP DELETE request
request.delete(url: string, options?: {
  data?: string | Buffer | Serializable;
  form?: { [key: string]: string | number | boolean };
  headers?: { [key: string]: string };
  params?: { [key: string]: string | number | boolean };
  timeout?: number;
  failOnStatusCode?: boolean;
  ignoreHTTPSErrors?: boolean;
  maxRedirects?: number;
  maxRetries?: number;
}): Promise<APIResponse>;

// Context disposal
context.dispose(options?: {
  reason?: string;
}): Promise<void>;

Import

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

I/O Contract

Inputs

Name Type Required Description
afterAll callback (args: { request: APIRequestContext }, testInfo: TestInfo) => Promise<any> Yes An async function that receives the request fixture and testInfo. Executes after all tests in the current scope have completed, regardless of pass/fail status.
delete: url string Yes The URL of the resource to delete. Relative URLs are resolved against the context's baseURL.
delete: options object No Optional request configuration including headers, timeout, body data (for DELETE requests that require a body), and other standard request options.
dispose: options.reason string No An optional human-readable reason for disposing the context. Logged for debugging purposes.

Outputs

Name Type Description
delete() return Promise<APIResponse> The API response from the DELETE request. Check response.ok() to verify the deletion succeeded. A 204 No Content status typically indicates successful deletion.
dispose() return Promise<void> Resolves when the context has been fully disposed. Server-side tracing is flushed and all cached response bodies are cleared from memory.

Usage Examples

Basic Example

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

test.use({
  baseURL: 'https://api.example.com',
  extraHTTPHeaders: {
    'Authorization': 'Bearer my-token',
  },
});

let createdUserId: number;

test.beforeAll(async ({ request }) => {
  // Setup: create a test user
  const response = await request.post('/api/users', {
    data: {
      username: 'cleanup-test-user',
      email: 'cleanup@example.com',
    },
  });
  expect(response.ok()).toBeTruthy();
  const body = await response.json();
  createdUserId = body.id;
});

test('verify user was created', async ({ request }) => {
  const response = await request.get(`/api/users/${createdUserId}`);
  expect(response.ok()).toBeTruthy();
});

test.afterAll(async ({ request }) => {
  // Teardown: delete the test-created user
  const deleteResponse = await request.delete(`/api/users/${createdUserId}`);
  expect(deleteResponse.ok()).toBeTruthy();
});

Example: Manual Context Disposal

import { test, request as playwrightRequest } from '@playwright/test';

test('create and dispose manual context', async () => {
  const context = await playwrightRequest.newContext({
    baseURL: 'https://api.example.com',
  });

  try {
    const response = await context.get('/api/health');
    expect(response.ok()).toBeTruthy();
  } finally {
    // Always dispose the context, even if the test fails
    await context.dispose({ reason: 'Test completed' });
  }
});

Example: Using Symbol.asyncDispose

import { test, request as playwrightRequest } from '@playwright/test';

test('automatic disposal with await using', async () => {
  // TypeScript 5.2+ syntax: context is automatically disposed
  // when it goes out of scope
  await using context = await playwrightRequest.newContext({
    baseURL: 'https://api.example.com',
  });

  const response = await context.get('/api/health');
  expect(response.ok()).toBeTruthy();

  // No manual dispose() call needed -- Symbol.asyncDispose handles it
});

Example: Comprehensive Setup and Teardown

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

test.use({
  baseURL: 'https://api.example.com',
  extraHTTPHeaders: {
    'Authorization': 'Bearer admin-token',
  },
});

const createdResources: { type: string; id: number }[] = [];

test.beforeAll(async ({ request }) => {
  // Create multiple test resources
  const userResponse = await request.post('/api/users', {
    data: { username: 'test-user', role: 'editor' },
  });
  const user = await userResponse.json();
  createdResources.push({ type: 'users', id: user.id });

  const articleResponse = await request.post('/api/articles', {
    data: { title: 'Test Article', authorId: user.id },
  });
  const article = await articleResponse.json();
  createdResources.push({ type: 'articles', id: article.id });
});

test('tests run here...', async ({ request }) => {
  // Test logic
});

test.afterAll(async ({ request }) => {
  // Clean up in reverse order to respect dependencies
  for (const resource of createdResources.reverse()) {
    const response = await request.delete(
      `/api/${resource.type}/${resource.id}`
    );
    // Tolerate 404 in case a test already deleted the resource
    if (response.status() !== 404) {
      expect(response.ok()).toBeTruthy();
    }
  }
});

Related Pages

Implements Principle

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment