Overview
TheTemplateAPI 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
| Parameter | Type | Required | Description |
|---|---|---|---|
options | TemplateOptions | Yes | Template 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
| Parameter | Type | Required | Description |
|---|---|---|---|
templateId | string | Yes | ID of the template to invoke |
options | TemplateInvocationOptions | Yes | Invocation 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
| Parameter | Type | Required | Description |
|---|---|---|---|
options | TemplateOptions & TemplateInvocationOptions | Yes | Combined 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
| Parameter | Type | Required | Description |
|---|---|---|---|
options | TemplateListOptions | No | Filtering 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
| Parameter | Type | Required | Description |
|---|---|---|---|
templateId | string | Yes | ID of the template to update |
updates | Partial<TemplateOptions> | Yes | Fields 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
| Parameter | Type | Required | Description |
|---|---|---|---|
templateId | string | Yes | ID 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
- Clear naming: Use descriptive names that indicate the template’s purpose
- Comprehensive instructions: Include all necessary steps and edge cases
- Structured output: Define clear schemas for consistent results
- Appropriate tags: Use tags for categorization and filtering
- 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();
}
}
