Skip to main content

Overview

The TemplateAPI provides methods for creating, managing, and executing reusable test templates with structured output schemas.

Methods

create()

Creates a new test template.
create(options: TemplateOptions): Promise<TemplateResponse>

Parameters

ParameterTypeRequiredDescription
optionsTemplateOptionsYesTemplate configuration options

TemplateOptions

interface TemplateOptions {
  /** Template name */
  name: string;
  /** Template description */
  description: string;
  /** Test instructions */
  instructions: string;
  /** JSON schema for structured output */
  outputSchema: object;
  /** Template tags for organization */
  tags?: string[];
}

Returns

Promise<TemplateResponse> - Template creation response

TemplateResponse

interface TemplateResponse {
  template: {
    id: string;
    name: string;
    description: string;
    instructions: string;
    outputSchema: object;
    tags: string[];
    createdAt: string;
    updatedAt: string;
  };
}

Example

const template = await bt.template.create({
  name: 'E-commerce Checkout Test',
  description: 'Test the complete checkout flow',
  instructions: `
    Navigate to the product page.
    Add item to cart.
    Proceed to checkout.
    Fill in shipping information.
    Complete payment.
    Verify order confirmation.
  `,
  outputSchema: {
    type: 'object',
    properties: {
      checkoutSuccessful: { type: 'boolean' },
      orderNumber: { type: 'string' },
      totalAmount: { type: 'string' },
      errors: { type: 'array', items: { type: 'string' } }
    }
  },
  tags: ['checkout', 'e-commerce', 'payment']
});

console.log('Template created:', template.template.id);

invoke()

Invokes a template to create an async test job.
invoke(templateId: string, options: TemplateInvocationOptions): Promise<TemplateJobResponse>

Parameters

ParameterTypeRequiredDescription
templateIdstringYesID of the template to invoke
optionsTemplateInvocationOptionsYesInvocation options

TemplateInvocationOptions

interface TemplateInvocationOptions {
  /** URL to test */
  url: string;
  /** Test configuration overrides */
  config?: TestConfig;
  /** Parameter values for template variables */
  parameters?: Record<string, any>;
}

Returns

Promise<TemplateJobResponse> - Job creation response

TemplateJobResponse

interface TemplateJobResponse {
  jobId: string;
  status: 'pending' | 'running' | 'completed' | 'failed';
  createdAt: string;
  url: string;
}

Example

const job = await bt.template.invoke(template.template.id, {
  url: 'https://example-shop.com/checkout',
  config: {
    viewport: { width: 1920, height: 1080 },
    waitFor: 3000,
    timeout: 120000
  },
  parameters: {
    productId: '12345',
    quantity: 2
  }
});

console.log('Job created:', job.jobId);

createAndInvoke()

Creates a template and immediately invokes it.
createAndInvoke(options: TemplateOptions & TemplateInvocationOptions): Promise<TemplateJobResponse>

Parameters

ParameterTypeRequiredDescription
optionsTemplateOptions & TemplateInvocationOptionsYesCombined template and invocation options

Returns

Promise<TemplateJobResponse> - Job creation response

Example

const result = await bt.template.createAndInvoke({
  name: 'Quick Page Check',
  instructions: 'Navigate to page and verify it loads without errors',
  url: 'https://example.com',
  outputSchema: {
    type: 'object',
    properties: {
      pageLoaded: { type: 'boolean' },
      hasErrors: { type: 'boolean' },
      loadTime: { type: 'number' }
    }
  }
});

console.log('Template created and invoked:', result.jobId);

list()

Lists templates with optional filtering.
list(options?: TemplateListOptions): Promise<TemplateListResponse>

Parameters

ParameterTypeRequiredDescription
optionsTemplateListOptionsNoFiltering and pagination options

TemplateListOptions

interface TemplateListOptions {
  /** Search query for template names */
  search?: string;
  /** Filter by tags */
  tags?: string[];
  /** Maximum number of results */
  limit?: number;
  /** Number of results to skip */
  offset?: number;
  /** Sort order */
  sortOrder?: 'asc' | 'desc';
}

Returns

Promise<TemplateListResponse> - List of templates

TemplateListResponse

interface TemplateListResponse {
  templates: Array<{
    id: string;
    name: string;
    description: string;
    tags: string[];
    createdAt: string;
    updatedAt: string;
  }>;
  total: number;
  hasMore: boolean;
}

Examples

// Get all templates
const allTemplates = await bt.template.list();

// Search by name
const searchResults = await bt.template.list({
  search: 'checkout'
});

// Filter by tags
const taggedTemplates = await bt.template.list({
  tags: ['e-commerce', 'payment']
});

// Paginated results
const page1 = await bt.template.list({ limit: 10, offset: 0 });
const page2 = await bt.template.list({ limit: 10, offset: 10 });

update()

Updates an existing template.
update(templateId: string, updates: Partial<TemplateOptions>): Promise<TemplateResponse>

Parameters

ParameterTypeRequiredDescription
templateIdstringYesID of the template to update
updatesPartial<TemplateOptions>YesFields to update

Returns

Promise<TemplateResponse> - Updated template response

Example

const updated = await bt.template.update(template.template.id, {
  name: 'Updated Checkout Test',
  description: 'Improved checkout testing template',
  tags: ['checkout', 'e-commerce', 'payment', 'updated']
});

console.log('Template updated:', updated.template.name);

delete()

Deletes a template.
delete(templateId: string): Promise<void>

Parameters

ParameterTypeRequiredDescription
templateIdstringYesID of the template to delete

Returns

Promise<void> - Resolves when template is deleted

Example

await bt.template.delete(template.template.id);
console.log('Template deleted');

Advanced Usage

Parameterized Templates

const parameterizedTemplate = await bt.template.create({
  name: 'Custom Form Test',
  instructions: `
    Navigate to {{formUrl}}
    Fill out the form with:
    - Name: {{userName}}
    - Email: {{userEmail}}
    - Message: {{userMessage}}
    Submit the form
    Verify success message: "{{expectedMessage}}"
  `,
  outputSchema: {
    type: 'object',
    properties: {
      formSubmitted: { type: 'boolean' },
      successMessage: { type: 'string' },
      formValid: { type: 'boolean' }
    }
  }
});

// Invoke with parameters
const job = await bt.template.invoke(parameterizedTemplate.template.id, {
  url: 'https://example.com',
  parameters: {
    formUrl: '/contact',
    userName: 'John Doe',
    userEmail: 'john@example.com',
    userMessage: 'Test message',
    expectedMessage: 'Thank you for your message!'
  }
});

Template Versioning

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

  async createVersion(templateId: string, updates: Partial<TemplateOptions>): Promise<string> {
    // Get current template
    const current = await this.getTemplateById(templateId);

    // Create new version
    const versionedName = `${current.name} v${Date.now()}`;
    const newTemplate = await this.bt.template.create({
      ...current,
      name: versionedName,
      ...updates
    });

    return newTemplate.template.id;
  }

  async getTemplateById(templateId: string): Promise<TemplateOptions> {
    // This would require a get method (not currently available)
    // For now, we'll need to track templates in our application
    throw new Error('Template retrieval not implemented in SDK');
  }

  async archiveTemplate(templateId: string): Promise<void> {
    await this.bt.template.update(templateId, {
      tags: ['archived', 'deprecated']
    });
  }
}

Template Categories

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

  async createCategorizedTemplate(
    category: string,
    options: TemplateOptions
  ): Promise<TemplateResponse> {
    const categorizedOptions = {
      ...options,
      tags: [...(options.tags || []), `category:${category}`]
    };

    return this.bt.template.create(categorizedOptions);
  }

  async getTemplatesByCategory(category: string): Promise<TemplateListResponse> {
    return this.bt.template.list({
      tags: [`category:${category}`]
    });
  }

  async getAllCategories(): Promise<string[]> {
    const allTemplates = await this.bt.template.list({ limit: 1000 });
    const categories = new Set<string>();

    allTemplates.templates.forEach(template => {
      template.tags.forEach(tag => {
        if (tag.startsWith('category:')) {
          categories.add(tag.replace('category:', ''));
        }
      });
    });

    return Array.from(categories);
  }
}

// Usage
const organizer = new TemplateOrganizer(bt);

await organizer.createCategorizedTemplate('ecommerce', {
  name: 'Product Search Test',
  description: 'Test product search functionality',
  instructions: 'Test search functionality...',
  outputSchema: { /* schema */ },
  tags: ['search', 'products']
});

const ecommerceTemplates = await organizer.getTemplatesByCategory('ecommerce');
const categories = await organizer.getAllCategories();

Error Handling

Template Creation Errors

try {
  const template = await bt.template.create({
    name: 'Test Template',
    description: 'A test template',
    instructions: 'Test instructions',
    outputSchema: { type: 'object', properties: {} }
  });
} catch (error) {
  if (error.name === 'BrowserTestAPIError') {
    console.log('Template creation failed:', error.message);
  }
}

Template Invocation Errors

try {
  const job = await bt.template.invoke(templateId, {
    url: 'https://example.com'
  });
} catch (error) {
  if (error.name === 'BrowserTestAuthError') {
    console.log('Authentication failed - check API key');
  } else if (error.name === 'BrowserTestQuotaError') {
    console.log('Quota exceeded for template invocation');
  }
}

Best Practices

Template Design

  1. Clear naming: Use descriptive names that indicate the template’s purpose
  2. Comprehensive instructions: Include all necessary steps and edge cases
  3. Structured output: Define clear schemas for consistent results
  4. Appropriate tags: Use tags for categorization and filtering
  5. Parameterization: Use variables for flexible templates

Organization

// Template naming convention
const namingConvention = {
  prefix: {
    'ui': 'User Interface',
    'api': 'API Integration',
    'e2e': 'End-to-End',
    'perf': 'Performance'
  },
  pattern: '{Prefix} - {Feature} - {Action}'
};

// Example: "UI - Login - Authentication Flow"

Maintenance

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

  async validateTemplate(templateId: string): Promise<boolean> {
    try {
      // Try to invoke template with test data
      const testJob = await this.bt.template.invoke(templateId, {
        url: 'https://httpbin.org/html', // Simple test page
        config: { timeout: 30000 }
      });

      // Wait for completion
      const status = await this.waitForJob(testJob.jobId, 60000);
      return status === 'completed';

    } catch (error) {
      console.error(`Template ${templateId} validation failed:`, error.message);
      return false;
    }
  }

  private async waitForJob(jobId: string, timeout: number): Promise<string> {
    const startTime = Date.now();

    while (Date.now() - startTime < timeout) {
      const status = await this.bt.testing.getStatus(jobId);

      if (status.job.status === 'completed' || status.job.status === 'failed') {
        return status.job.status;
      }

      await new Promise(resolve => setTimeout(resolve, 2000));
    }

    throw new Error('Job timeout');
  }

  async cleanupOldTemplates(daysOld: number = 90): Promise<number> {
    const cutoff = new Date();
    cutoff.setDate(cutoff.getDate() - daysOld);

    // Note: This would require additional API methods not currently available
    // For now, this is a conceptual implementation
    console.log(`Would clean up templates older than ${cutoff.toISOString()}`);
    return 0;
  }
}

Performance Considerations

// Cache frequently used templates
class TemplateCache {
  private cache = new Map<string, TemplateResponse>();
  private readonly ttl = 5 * 60 * 1000; // 5 minutes

  constructor(private bt: BrowserTest) {}

  async get(templateId: string): Promise<TemplateResponse | null> {
    const cached = this.cache.get(templateId);

    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }

    // Cache miss - fetch from API
    try {
      // Note: Template retrieval not currently available in SDK
      // This would require additional API methods
      return null;
    } catch (error) {
      console.error('Failed to fetch template:', error.message);
      return null;
    }
  }

  set(templateId: string, data: TemplateResponse): void {
    this.cache.set(templateId, {
      data,
      timestamp: Date.now()
    });
  }

  clear(): void {
    this.cache.clear();
  }
}