CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-playwright-chromium

A high-level API to automate Chromium

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

api-testing.mddocs/

API Testing

HTTP API testing capabilities with request/response handling, authentication, context management, and comprehensive testing utilities for REST and GraphQL APIs.

Capabilities

API Request Context

Create isolated contexts for API testing with session management, authentication, and configuration.

/**
 * HTTP API testing interface
 */
interface APIRequest {
  /** Create new API request context */
  newContext(options?: APIRequestNewContextOptions): Promise<APIRequestContext>;
  /** Send GET request */
  get(url: string, options?: APIRequestGetOptions): Promise<APIResponse>;
  /** Send POST request */
  post(url: string, options?: APIRequestPostOptions): Promise<APIResponse>;
  /** Send PUT request */
  put(url: string, options?: APIRequestPutOptions): Promise<APIResponse>;
  /** Send PATCH request */
  patch(url: string, options?: APIRequestPatchOptions): Promise<APIResponse>;
  /** Send DELETE request */
  delete(url: string, options?: APIRequestDeleteOptions): Promise<APIResponse>;
  /** Send HEAD request */
  head(url: string, options?: APIRequestHeadOptions): Promise<APIResponse>;
}

/**
 * API request context with session management and authentication
 */
interface APIRequestContext {
  /** Send GET request */
  get(url: string, options?: APIRequestGetOptions): Promise<APIResponse>;
  /** Send POST request */
  post(url: string, options?: APIRequestPostOptions): Promise<APIResponse>;
  /** Send PUT request */
  put(url: string, options?: APIRequestPutOptions): Promise<APIResponse>;
  /** Send PATCH request */
  patch(url: string, options?: APIRequestPatchOptions): Promise<APIResponse>;
  /** Send DELETE request */
  delete(url: string, options?: APIRequestDeleteOptions): Promise<APIResponse>;
  /** Send HEAD request */
  head(url: string, options?: APIRequestHeadOptions): Promise<APIResponse>;
  /** Send custom HTTP request */
  fetch(urlOrRequest: string | APIRequest, options?: APIRequestFetchOptions): Promise<APIResponse>;
  /** Get or set storage state for authentication */
  storageState(options?: StorageStateOptions): Promise<StorageState>;
  /** Clean up context resources */
  dispose(): Promise<void>;
}

Usage Examples:

// Create API context with authentication
const apiContext = await request.newContext({
  baseURL: 'https://api.example.com',
  extraHTTPHeaders: {
    'Authorization': 'Bearer your-token-here',
    'Content-Type': 'application/json'
  }
});

// Simple API requests
const response = await apiContext.get('/users');
const users = await response.json();

const createResponse = await apiContext.post('/users', {
  data: {
    name: 'John Doe',
    email: 'john@example.com'
  }
});

// Context with session management
const authContext = await request.newContext();

// Login and save session
const loginResponse = await authContext.post('/auth/login', {
  data: { username: 'user', password: 'pass' }
});

// Session is automatically maintained for subsequent requests
const profileResponse = await authContext.get('/profile');

// Save authentication state
const state = await authContext.storageState();

API Response Handling

Comprehensive response handling with JSON parsing, status checking, and data extraction.

/**
 * API response interface with testing-focused methods
 */
interface APIResponse {
  /** Get response URL */
  url(): string;
  /** Get HTTP status code */
  status(): number;
  /** Get status text */
  statusText(): string;
  /** Get response headers */
  headers(): { [key: string]: string; };
  /** Get all headers (including multiple values) */
  allHeaders(): Promise<{ [key: string]: string; }>;
  /** Get headers as array */
  headersArray(): Promise<{ name: string; value: string; }[]>;
  /** Get single header value */
  headerValue(name: string): Promise<string | null>;
  /** Get multiple header values */
  headerValues(name: string): Promise<string[]>;
  /** Parse response as JSON */
  json(): Promise<any>;
  /** Get response as text */
  text(): Promise<string>;
  /** Get response as buffer */
  body(): Promise<Buffer>;
  /** Check if status indicates success (200-299) */
  ok(): boolean;
  /** Get response sizes */
  sizes(): Promise<ResponseSizes>;
}

Usage Examples:

// Basic response handling
const response = await apiContext.get('/api/data');

console.log(`Status: ${response.status()}`);
console.log(`Success: ${response.ok()}`);

if (response.ok()) {
  const data = await response.json();
  console.log('Data:', data);
} else {
  const error = await response.text();
  console.log('Error:', error);
}

// Header inspection
const headers = response.headers();
const contentType = headers['content-type'];
const rateLimit = await response.headerValue('x-rate-limit-remaining');

// Response validation
const apiResponse = await apiContext.post('/api/users', {
  data: { name: 'Test User', email: 'test@example.com' }
});

if (apiResponse.status() === 201) {
  const createdUser = await apiResponse.json();
  console.log('Created user:', createdUser);
} else {
  console.log('Failed to create user:', apiResponse.statusText());
}

Authentication Patterns

Common authentication patterns including basic auth, bearer tokens, and session management.

Usage Examples:

// Basic Authentication
const basicAuthContext = await request.newContext({
  httpCredentials: {
    username: 'admin',
    password: 'secret'
  }
});

// Bearer Token Authentication
const tokenContext = await request.newContext({
  extraHTTPHeaders: {
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
  }
});

// API Key Authentication
const apiKeyContext = await request.newContext({
  extraHTTPHeaders: {
    'X-API-Key': 'your-api-key-here'
  }
});

// Session-based Authentication
const sessionContext = await request.newContext();

// Login to get session cookie
await sessionContext.post('/auth/login', {
  form: {
    username: 'user@example.com',
    password: 'password123'
  }
});

// Session cookie is automatically included in subsequent requests
const userData = await sessionContext.get('/user/profile');

// OAuth2 Flow Simulation
const oauthContext = await request.newContext();

// Step 1: Get authorization code
const authResponse = await oauthContext.post('/oauth/authorize', {
  form: {
    client_id: 'your-client-id',
    redirect_uri: 'http://localhost:3000/callback',
    response_type: 'code',
    scope: 'read write'
  }
});

// Step 2: Exchange code for token
const tokenResponse = await oauthContext.post('/oauth/token', {
  form: {
    client_id: 'your-client-id',
    client_secret: 'your-client-secret',
    code: 'authorization-code',
    grant_type: 'authorization_code'
  }
});

const { access_token } = await tokenResponse.json();

// Step 3: Use token for API requests
const protectedContext = await request.newContext({
  extraHTTPHeaders: {
    'Authorization': `Bearer ${access_token}`
  }
});

Request Data Formats

Support for various request data formats including JSON, form data, and multipart uploads.

Usage Examples:

// JSON Data
const jsonResponse = await apiContext.post('/api/users', {
  data: {
    name: 'John Doe',
    email: 'john@example.com',
    settings: {
      theme: 'dark',
      notifications: true
    }
  }
});

// Form Data (application/x-www-form-urlencoded)
const formResponse = await apiContext.post('/api/login', {
  form: {
    username: 'user@example.com',
    password: 'secretpassword',
    remember_me: 'true'
  }
});

// Multipart Form Data (multipart/form-data)
const multipartResponse = await apiContext.post('/api/upload', {
  multipart: {
    title: 'Document Title',
    description: 'File description',
    file: fs.readFileSync('document.pdf')
  }
});

// Raw Data
const rawResponse = await apiContext.post('/api/webhook', {
  data: Buffer.from('raw binary data'),
  headers: {
    'Content-Type': 'application/octet-stream'
  }
});

// GraphQL Queries
const graphqlResponse = await apiContext.post('/graphql', {
  data: {
    query: `
      query GetUser($id: ID!) {
        user(id: $id) {
          id
          name
          email
          posts {
            title
            content
          }
        }
      }
    `,
    variables: {
      id: '123'
    }
  }
});

const graphqlData = await graphqlResponse.json();

Testing Utilities

Built-in utilities for common API testing scenarios including retries, timeouts, and validation.

Usage Examples:

// Request with timeout
const response = await apiContext.get('/slow-endpoint', {
  timeout: 5000 // 5 seconds
});

// Request with retries (custom implementation)
async function requestWithRetry(url: string, options: any, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await apiContext.get(url, options);
      if (response.ok()) return response;
      
      if (i === maxRetries - 1) throw new Error(`Failed after ${maxRetries} retries`);
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); // Exponential backoff
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

// Rate limiting handling
async function handleRateLimit(response: APIResponse) {
  if (response.status() === 429) {
    const retryAfter = await response.headerValue('retry-after');
    if (retryAfter) {
      await new Promise(resolve => setTimeout(resolve, parseInt(retryAfter) * 1000));
    }
  }
}

// Response validation
async function validateApiResponse(response: APIResponse, expectedSchema: any) {
  if (!response.ok()) {
    throw new Error(`API error: ${response.status()} ${response.statusText()}`);
  }
  
  const data = await response.json();
  
  // Validate response structure (pseudo-code)
  if (!validateSchema(data, expectedSchema)) {
    throw new Error('Response does not match expected schema');
  }
  
  return data;
}

Configuration Types

interface APIRequestNewContextOptions {
  /** Base URL for relative requests. */
  baseURL?: string;
  /** Additional HTTP headers. */
  extraHTTPHeaders?: { [key: string]: string; };
  /** HTTP credentials. */
  httpCredentials?: { username: string; password: string; };
  /** Whether to ignore HTTPS errors. */
  ignoreHTTPSErrors?: boolean;
  /** Network proxy settings. */
  proxy?: { server: string; bypass?: string; username?: string; password?: string; };
  /** Storage state to populate context with. */
  storageState?: string | StorageState;
  /** Request timeout in milliseconds. */
  timeout?: number;
  /** User agent string. */
  userAgent?: string;
}

interface APIRequestGetOptions {
  /** Request data. */
  data?: string | Buffer | Serializable;
  /** Whether to throw on non-2xx/3xx status codes. */
  failOnStatusCode?: boolean;
  /** Form data. */
  form?: { [key: string]: string | number | boolean; };
  /** Request headers. */
  headers?: { [key: string]: string; };
  /** Whether to ignore HTTPS errors. */
  ignoreHTTPSErrors?: boolean;
  /** Maximum redirects to follow. */
  maxRedirects?: number;
  /** Maximum retries on network errors. */
  maxRetries?: number;
  /** Multipart form data. */
  multipart?: { [key: string]: string | number | boolean; };
  /** Query parameters. */
  params?: { [key: string]: string | number | boolean; };
  /** Request timeout. */
  timeout?: number;
}

interface APIRequestPostOptions {
  /** Request data. */
  data?: string | Buffer | Serializable;
  /** Whether to throw on non-2xx/3xx status codes. */
  failOnStatusCode?: boolean;
  /** Form data. */
  form?: { [key: string]: string | number | boolean; };
  /** Request headers. */
  headers?: { [key: string]: string; };
  /** Whether to ignore HTTPS errors. */
  ignoreHTTPSErrors?: boolean;
  /** Maximum redirects to follow. */
  maxRedirects?: number;
  /** Maximum retries on network errors. */
  maxRetries?: number;
  /** Multipart form data. */
  multipart?: { [key: string]: string | number | boolean; };
  /** Query parameters. */
  params?: { [key: string]: string | number | boolean; };
  /** Request timeout. */
  timeout?: number;
}

interface APIRequestPutOptions {
  /** Request data. */
  data?: string | Buffer | Serializable;
  /** Whether to throw on non-2xx/3xx status codes. */
  failOnStatusCode?: boolean;
  /** Form data. */
  form?: { [key: string]: string | number | boolean; };
  /** Request headers. */
  headers?: { [key: string]: string; };
  /** Whether to ignore HTTPS errors. */
  ignoreHTTPSErrors?: boolean;
  /** Maximum redirects to follow. */
  maxRedirects?: number;
  /** Maximum retries on network errors. */
  maxRetries?: number;
  /** Multipart form data. */
  multipart?: { [key: string]: string | number | boolean; };
  /** Query parameters. */
  params?: { [key: string]: string | number | boolean; };
  /** Request timeout. */
  timeout?: number;
}

interface APIRequestDeleteOptions {
  /** Request data. */
  data?: string | Buffer | Serializable;
  /** Whether to throw on non-2xx/3xx status codes. */
  failOnStatusCode?: boolean;
  /** Form data. */
  form?: { [key: string]: string | number | boolean; };
  /** Request headers. */
  headers?: { [key: string]: string; };
  /** Whether to ignore HTTPS errors. */
  ignoreHTTPSErrors?: boolean;
  /** Maximum redirects to follow. */
  maxRedirects?: number;
  /** Maximum retries on network errors. */
  maxRetries?: number;
  /** Multipart form data. */
  multipart?: { [key: string]: string | number | boolean; };
  /** Query parameters. */
  params?: { [key: string]: string | number | boolean; };
  /** Request timeout. */
  timeout?: number;
}

interface StorageState {
  /** Cookies to set. */
  cookies: Array<{
    name: string;
    value: string;
    domain: string;
    path: string;
    expires: number;
    httpOnly: boolean;
    secure: boolean;
    sameSite: 'Strict' | 'Lax' | 'None';
  }>;
  /** Local storage entries to set. */
  origins: Array<{
    origin: string;
    localStorage: Array<{
      name: string;
      value: string;
    }>;
  }>;
}

type Serializable = any;

Integration with Browser Context

API testing can be integrated with browser automation for end-to-end testing scenarios.

Usage Examples:

// Share authentication between browser and API contexts
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();

// Login through browser
await page.goto('https://example.com/login');
await page.fill('[name="email"]', 'user@example.com');
await page.fill('[name="password"]', 'password123');
await page.click('button[type="submit"]');

// Extract authentication state
const storageState = await context.storageState();

// Use authentication state for API testing
const apiContext = await request.newContext({
  baseURL: 'https://api.example.com',
  storageState
});

// API requests now use the same authentication as browser
const apiResponse = await apiContext.get('/user/profile');
const userData = await apiResponse.json();

// Verify UI reflects API data
await page.goto('https://example.com/profile');
const displayedName = await page.textContent('.user-name');
console.assert(displayedName === userData.name);

Error Handling

Usage Examples:

try {
  const response = await apiContext.get('/api/data');
  
  if (!response.ok()) {
    const errorBody = await response.text();
    throw new Error(`API Error ${response.status()}: ${errorBody}`);
  }
  
  const data = await response.json();
  return data;
} catch (error) {
  if (error.message.includes('timeout')) {
    console.log('Request timed out, retrying...');
    // Implement retry logic
  } else if (error.message.includes('ECONNREFUSED')) {
    console.log('Server is not available');
  } else {
    console.log('API request failed:', error.message);
  }
  throw error;
}

Install with Tessl CLI

npx tessl i tessl/npm-playwright-chromium

docs

api-testing.md

browser-management.md

element-handling.md

index.md

input-simulation.md

network-control.md

page-interaction.md

tile.json