> ## Documentation Index
> Fetch the complete documentation index at: https://docs.browsertest.in/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript Support

> Full TypeScript support and type definitions for BrowserTest SDK

## Overview

BrowserTest SDK provides comprehensive TypeScript support with full type definitions, IntelliSense support, and type safety for all operations.

## Installation

```bash theme={null}
npm install browsertest-sdk
# TypeScript definitions are included automatically
```

## Basic TypeScript Usage

### Initialization with Types

```typescript theme={null}
import { BrowserTest } from 'browsertest-sdk';

const bt = new BrowserTest({
  apiKey: process.env.BROWSERTEST_API_KEY!
});
```

### Typed Operations

```typescript theme={null}
// Screenshots with full type safety
const screenshot = await bt.screenshot.take({
  url: 'https://example.com',
  fullPage: true,
  format: 'png'
});
// Type: ScreenshotResult

// Agentic testing with structured output
const testResult = await bt.testing.execute({
  instructions: 'Test login functionality',
  url: 'https://example.com/login',
  outputSchema: {
    type: 'object',
    properties: {
      loginSuccessful: { type: 'boolean' },
      userName: { type: 'string' }
    }
  }
});
// Type: TestResult
```

## Type Definitions

### Core Types

```typescript theme={null}
// Configuration
interface BrowserTestConfig {
  apiKey: string;
  baseUrl?: string;
  timeout?: number;
  retries?: number;
}

// Usage information
interface QuotaInfo {
  plan: string;
  usage: {
    screenshot: {
      used: number;
      limit: number;
      remaining: number;
    };
    agentic: {
      used: number;
      limit: number;
      remaining: number;
    };
    total: {
      screenshot: number;
      agentic: number;
    };
  };
}
```

### Screenshot Types

```typescript theme={null}
interface ScreenshotOptions {
  url: string;
  fullPage?: boolean;
  width?: number;
  height?: number;
  format?: 'png' | 'jpeg';
  quality?: number;
  waitFor?: number;
  selector?: string | null;
  timeout?: number;
  blockAds?: boolean;
}

interface ScreenshotResult {
  success: boolean;
  data: {
    screenshot: string;
    url: string;
    title: string;
    width: number;
    height: number;
    format: string;
    fullPage: boolean;
  };
  meta: {
    timeMs: number;
    size: number;
  };
}
```

### Testing Types

```typescript theme={null}
interface TestOptions {
  instructions: string;
  url: string;
  outputSchema?: object;
  config?: TestConfig;
}

interface TestResult {
  success: boolean;
  results: {
    actions: Array<{
      type: string;
      description: string;
      timestamp: string;
    }>;
    structuredData?: any;
    output: string;
  };
  meta: {
    timeMs: number;
    url: string;
  };
}
```

## Advanced TypeScript Patterns

### Generic Types for Structured Output

```typescript theme={null}
// Define your expected output types
interface LoginTestOutput {
  loginSuccessful: boolean;
  userName?: string;
  errorMessage?: string;
  redirectUrl?: string;
}

interface EcommerceTestOutput {
  checkoutSuccessful: boolean;
  orderNumber?: string;
  totalAmount?: string;
  errors: string[];
}

// Typed test functions
async function testLogin(url: string): Promise<LoginTestOutput> {
  const result = await bt.testing.execute({
    instructions: 'Test login with valid credentials',
    url,
    outputSchema: {
      type: 'object',
      properties: {
        loginSuccessful: { type: 'boolean' },
        userName: { type: 'string' },
        errorMessage: { type: 'string' },
        redirectUrl: { type: 'string' }
      }
    }
  });

  return result.results.structuredData as LoginTestOutput;
}

async function testCheckout(url: string): Promise<EcommerceTestOutput> {
  const result = await bt.testing.execute({
    instructions: 'Complete checkout process',
    url,
    outputSchema: {
      type: 'object',
      properties: {
        checkoutSuccessful: { type: 'boolean' },
        orderNumber: { type: 'string' },
        totalAmount: { type: 'string' },
        errors: { type: 'array', items: { type: 'string' } }
      }
    }
  });

  return result.results.structuredData as EcommerceTestOutput;
}

// Usage with type safety
const loginResult = await testLogin('https://example.com/login');
if (loginResult.loginSuccessful) {
  console.log('Login successful for user:', loginResult.userName);
}

const checkoutResult = await testCheckout('https://shop.com/checkout');
if (checkoutResult.checkoutSuccessful) {
  console.log('Order placed:', checkoutResult.orderNumber);
}
```

### Utility Types

```typescript theme={null}
// Extract successful results only
type SuccessfulScreenshot = ScreenshotResult & { success: true };

// Create a type guard
function isSuccessfulScreenshot(result: ScreenshotResult): result is SuccessfulScreenshot {
  return result.success;
}

// Usage
const results = await bt.screenshot.takeBatch({ urls: ['https://site1.com', 'https://site2.com'] });

const successfulResults = results.results.filter(isSuccessfulScreenshot);
// Type: SuccessfulScreenshot[]

successfulResults.forEach(result => {
  // TypeScript knows result.success is true and data exists
  console.log('Success:', result.data.url, result.data.width);
});
```

### Template Types

```typescript theme={null}
interface TemplateConfig<TOutput = any> {
  name: string;
  description: string;
  instructions: string;
  outputSchema: object;
  tags?: string[];
}

interface TemplateInstance<TOutput = any> {
  id: string;
  config: TemplateConfig<TOutput>;
}

// Typed template creation
function createTypedTemplate<TOutput>(
  config: TemplateConfig<TOutput>
): Promise<TemplateInstance<TOutput>> {
  return bt.template.create(config);
}

// Typed template invocation
async function invokeTypedTemplate<TOutput>(
  templateId: string,
  params: { url: string; [key: string]: any }
): Promise<TOutput> {
  const result = await bt.template.invoke(templateId, params);
  return result.results.structuredData as TOutput;
}

// Usage
interface UserRegistrationOutput {
  registrationSuccessful: boolean;
  userId: string;
  emailVerified: boolean;
}

const registrationTemplate = await createTypedTemplate<UserRegistrationOutput>({
  name: 'User Registration Test',
  instructions: 'Test user registration flow',
  outputSchema: {
    type: 'object',
    properties: {
      registrationSuccessful: { type: 'boolean' },
      userId: { type: 'string' },
      emailVerified: { type: 'boolean' }
    }
  }
});

const registrationResult = await invokeTypedTemplate<UserRegistrationOutput>(
  registrationTemplate.id,
  { url: 'https://app.com/register' }
);
// Type: UserRegistrationOutput
```

## Error Handling with Types

### Typed Error Classes

```typescript theme={null}
// Custom error types
class BrowserTestError extends Error {
  constructor(message: string, public status?: number) {
    super(message);
    this.name = 'BrowserTestError';
  }
}

class BrowserTestAuthError extends BrowserTestError {
  constructor(message = 'Authentication failed') {
    super(message);
    this.name = 'BrowserTestAuthError';
  }
}

class BrowserTestQuotaError extends BrowserTestError {
  constructor(message = 'Quota exceeded', public quotaInfo?: QuotaInfo) {
    super(message);
    this.name = 'BrowserTestQuotaError';
  }
}

// Type guard functions
function isBrowserTestAuthError(error: unknown): error is BrowserTestAuthError {
  return error instanceof Error && error.name === 'BrowserTestAuthError';
}

function isBrowserTestQuotaError(error: unknown): error is BrowserTestQuotaError {
  return error instanceof Error && error.name === 'BrowserTestQuotaError';
}

// Typed error handling
async function safeScreenshot(url: string): Promise<ScreenshotResult | null> {
  try {
    return await bt.screenshot.take({ url });
  } catch (error) {
    if (isBrowserTestAuthError(error)) {
      console.error('Auth error:', error.message);
      // Handle auth error
      return null;
    }

    if (isBrowserTestQuotaError(error)) {
      console.error('Quota exceeded:', error.quotaInfo);
      // Handle quota error
      return null;
    }

    throw error; // Re-throw unknown errors
  }
}
```

### Result Types with Discriminated Unions

```typescript theme={null}
// Result types
type OperationResult<TData> =
  | { success: true; data: TData }
  | { success: false; error: string; code?: string };

// Generic operation wrapper
async function executeOperation<TData>(
  operation: () => Promise<TData>
): Promise<OperationResult<TData>> {
  try {
    const data = await operation();
    return { success: true, data };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
      code: error instanceof Error ? error.name : undefined
    };
  }
}

// Usage with type safety
const screenshotResult = await executeOperation(() =>
  bt.screenshot.take({ url: 'https://example.com' })
);

if (screenshotResult.success) {
  // TypeScript knows screenshotResult.data is ScreenshotResult
  console.log('Screenshot size:', screenshotResult.data.meta.size);
} else {
  // TypeScript knows screenshotResult.error exists
  console.error('Screenshot failed:', screenshotResult.error);
}
```

## Class-Based SDK Wrapper

```typescript theme={null}
class TypedBrowserTest {
  constructor(private bt: BrowserTest) {}

  async screenshot(options: ScreenshotOptions): Promise<ScreenshotResult> {
    return this.bt.screenshot.take(options);
  }

  async test<TOutput = any>(
    instructions: string,
    url: string,
    schema?: object
  ): Promise<TestResult & { structuredData: TOutput }> {
    const result = await this.bt.testing.execute({
      instructions,
      url,
      outputSchema: schema
    });

    return {
      ...result,
      results: {
        ...result.results,
        structuredData: result.results.structuredData as TOutput
      }
    };
  }

  async batchScreenshots(urls: string[]): Promise<ScreenshotResult[]> {
    const batch = await this.bt.screenshot.takeBatch({ urls });
    return batch.results.filter(r => r.success).map(r => r.data!);
  }

  async getUsage(): Promise<QuotaInfo> {
    return this.bt.getUsage();
  }
}

// Usage
const typedBt = new TypedBrowserTest(bt);

// Type-safe operations
const screenshot = await typedBt.screenshot({
  url: 'https://example.com',
  fullPage: true
});

interface LoginResult {
  success: boolean;
  username?: string;
}

const loginTest = await typedBt.test<LoginResult>(
  'Test login functionality',
  'https://example.com/login',
  {
    type: 'object',
    properties: {
      success: { type: 'boolean' },
      username: { type: 'string' }
    }
  }
);

// TypeScript knows loginTest.results.structuredData is LoginResult
if (loginTest.results.structuredData.success) {
  console.log('Logged in as:', loginTest.results.structuredData.username);
}
```

## Configuration Types

### Environment-Based Configuration

```typescript theme={null}
type Environment = 'development' | 'staging' | 'production';

interface EnvironmentConfig {
  apiKey: string;
  baseUrl: string;
  timeout: number;
  retries: number;
}

const environmentConfigs: Record<Environment, EnvironmentConfig> = {
  development: {
    apiKey: process.env.BROWSERTEST_DEV_KEY!,
    baseUrl: 'https://api.browsertest.in',
    timeout: 30000,
    retries: 1
  },
  staging: {
    apiKey: process.env.BROWSERTEST_STAGING_KEY!,
    baseUrl: 'https://staging-api.browsertest.in',
    timeout: 45000,
    retries: 3
  },
  production: {
    apiKey: process.env.BROWSERTEST_PROD_KEY!,
    baseUrl: 'https://api.browsertest.in',
    timeout: 60000,
    retries: 5
  }
};

function createBrowserTestForEnvironment(env: Environment): BrowserTest {
  const config = environmentConfigs[env];

  // Validate required environment variables
  if (!config.apiKey) {
    throw new Error(`Missing API key for environment: ${env}`);
  }

  return new BrowserTest(config);
}

// Usage
const env = (process.env.NODE_ENV as Environment) || 'development';
const bt = createBrowserTestForEnvironment(env);
```

### Configuration Validation

```typescript theme={null}
import { z } from 'zod'; // Using zod for runtime validation

const BrowserTestConfigSchema = z.object({
  apiKey: z.string().min(10, 'API key too short'),
  baseUrl: z.string().url().optional(),
  timeout: z.number().min(1000).max(300000).optional(),
  retries: z.number().min(0).max(10).optional()
});

type ValidatedBrowserTestConfig = z.infer<typeof BrowserTestConfigSchema>;

function createValidatedBrowserTest(config: unknown): BrowserTest {
  const validatedConfig = BrowserTestConfigSchema.parse(config);
  return new BrowserTest(validatedConfig);
}

// Usage with runtime validation
try {
  const config = {
    apiKey: process.env.BROWSERTEST_API_KEY!,
    timeout: 30000,
    retries: 3
  };

  const bt = createValidatedBrowserTest(config);
  // Config is validated at runtime
} catch (error) {
  console.error('Invalid configuration:', error);
}
```

## Utility Types

### Extract and Transform Types

```typescript theme={null}
// Extract successful results
type SuccessfulResults<T> = T extends { success: true; data: infer D } ? D : never;

// Extract error types
type ErrorResults<T> = T extends { success: false; error: infer E } ? E : never;

// Transform batch results
type BatchResults<T> = Array<
  | { success: true; data: T }
  | { success: false; error: string }
>;

type SuccessfulBatchResults<T> = Extract<BatchResults<T>, { success: true }>['data'];

// Usage
type ScreenshotBatch = BatchResults<ScreenshotResult['data']>;
type SuccessfulScreenshots = SuccessfulBatchResults<ScreenshotResult['data']>;
```

### API Response Types

```typescript theme={null}
// Generic API response wrapper
interface ApiResponse<TData = unknown, TError = string> {
  success: boolean;
  data?: TData;
  error?: TError;
  meta?: {
    timeMs: number;
    requestId?: string;
  };
}

// Specific response types
type ScreenshotApiResponse = ApiResponse<ScreenshotResult['data']>;
type TestApiResponse = ApiResponse<TestResult>;
type UsageApiResponse = ApiResponse<QuotaInfo>;

// Generic API call wrapper
async function apiCall<TData>(
  operation: () => Promise<TData>
): Promise<ApiResponse<TData>> {
  const startTime = Date.now();

  try {
    const data = await operation();
    return {
      success: true,
      data,
      meta: {
        timeMs: Date.now() - startTime
      }
    };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
      meta: {
        timeMs: Date.now() - startTime
      }
    };
  }
}

// Usage
const screenshotResponse = await apiCall(() =>
  bt.screenshot.take({ url: 'https://example.com' })
);

if (screenshotResponse.success) {
  // TypeScript knows screenshotResponse.data is ScreenshotResult
  console.log('Screenshot taken:', screenshotResponse.data?.meta.size);
}
```

## Best Practices

### Type Safety

1. **Always define interfaces** for structured output schemas
2. **Use strict null checks** with TypeScript's `strictNullChecks`
3. **Leverage discriminated unions** for result types
4. **Create type guards** for error handling

### Development Experience

```typescript theme={null}
// Enable strict TypeScript settings in tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  }
}
```

### IntelliSense and Auto-completion

```typescript theme={null}
// Use JSDoc comments for better IntelliSense
/**
 * Takes a screenshot of the specified URL with optional configuration
 * @param url - The URL to screenshot
 * @param options - Screenshot configuration options
 * @returns Promise resolving to screenshot result
 */
async function takeScreenshot(
  url: string,
  options: Partial<ScreenshotOptions> = {}
): Promise<ScreenshotResult> {
  return bt.screenshot.take({ url, ...options });
}

// IntelliSense will show parameter descriptions and types
const result = await takeScreenshot('https://example.com', {
  fullPage: true, // IntelliSense shows: "Capture full page (default: false)"
  format: 'png'   // IntelliSense shows: "'png' | 'jpeg'"
});
```

### Testing with Types

```typescript theme={null}
// Typed test utilities
interface TestCase<TInput, TOutput> {
  name: string;
  input: TInput;
  expectedOutput: TOutput;
  schema?: object;
}

class TypedTester {
  constructor(private bt: BrowserTest) {}

  async runTest<TOutput>(
    testCase: TestCase<any, TOutput>
  ): Promise<{ success: boolean; result?: TOutput; error?: string }> {
    try {
      const result = await this.bt.testing.execute({
        instructions: `Test: ${testCase.name}`,
        url: testCase.input.url || 'https://example.com',
        outputSchema: testCase.schema
      });

      return {
        success: true,
        result: result.results.structuredData as TOutput
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown error'
      };
    }
  }
}

// Usage
interface LoginOutput {
  success: boolean;
  username?: string;
}

const tester = new TypedTester(bt);

const loginTest: TestCase<{ url: string }, LoginOutput> = {
  name: 'User Login',
  input: { url: 'https://app.com/login' },
  expectedOutput: { success: true },
  schema: {
    type: 'object',
    properties: {
      success: { type: 'boolean' },
      username: { type: 'string' }
    }
  }
};

const testResult = await tester.runTest(loginTest);
if (testResult.success) {
  // TypeScript knows testResult.result is LoginOutput
  console.log('Test passed:', testResult.result);
}
```
