or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-interactions.mdbidi-protocol.mdbrowser-automation.mdbrowser-options.mddriver-management.mdelement-location.mderror-handling.mdindex.mdwait-conditions.md
tile.json

bidi-protocol.mddocs/

BiDi Protocol

Modern bidirectional communication protocol for advanced browser automation, real-time monitoring, and enhanced debugging capabilities with WebDriver BiDi.

Capabilities

BrowsingContext Class

BiDi browsing context management for advanced page lifecycle control and monitoring.

/**
 * BiDi browsing context for advanced browser control
 */
class BrowsingContext {
  constructor(driver: WebDriver, id?: string);
  
  /** Create new browsing context */
  static create(driver: WebDriver, type: string, options?: CreateContextOptions): Promise<BrowsingContext>;
  
  /** Navigate to URL with advanced options */
  navigate(url: string, options?: NavigateOptions): Promise<NavigateResult>;
  
  /** Get browsing context tree */
  getTree(options?: GetTreeOptions): Promise<ContextInfo[]>;
  
  /** Get all top-level contexts */
  static getTopLevelContexts(driver: WebDriver): Promise<BrowsingContext[]>;
  
  /** Close browsing context */
  close(): Promise<void>;
  
  /** Activate browsing context */
  activate(): Promise<void>;
  
  /** Reload page with options */
  reload(options?: ReloadOptions): Promise<NavigateResult>;
  
  /** Set viewport dimensions */
  setViewport(width: number, height: number, devicePixelRatio?: number): Promise<void>;
  
  /** Print page to PDF */
  printPage(options?: PrintOptions): Promise<PrintResult>;
  
  /** Capture screenshot */
  captureScreenshot(options?: ScreenshotOptions): Promise<string>;
  
  /** Capture box screenshot */
  captureBoxScreenshot(x: number, y: number, width: number, height: number): Promise<string>;
  
  /** Capture element screenshot */
  captureElementScreenshot(element: ElementReference): Promise<string>;
  
  /** Handle user prompt */
  handleUserPrompt(accept?: boolean, userText?: string): Promise<void>;
  
  /** Traverse history */
  traverseHistory(delta: number): Promise<void>;
  
  /** Navigate forward */
  forward(): Promise<void>;
  
  /** Navigate back */
  back(): Promise<void>;
  
  /** Locate nodes using BiDi locators */
  locateNodes(locator: Locator, options?: LocateOptions): Promise<NodeInfo[]>;
  
  /** Locate single node */
  locateNode(locator: Locator, options?: LocateOptions): Promise<NodeInfo>;
  
  /** Locate element as WebElement */
  locateElement(locator: Locator): Promise<WebElement>;
  
  /** Locate elements as WebElement array */
  locateElements(locator: Locator): Promise<WebElement[]>;
}

Usage Examples:

const { BrowsingContext } = require('selenium-webdriver');

// Create new tab
let newContext = await BrowsingContext.create(driver, 'tab');
await newContext.navigate('https://example.com');

// Navigate with readiness state
let result = await newContext.navigate('https://example.com/page2', {
  wait: 'complete'
});
console.log('Navigation result:', result);

// Get context tree
let contextTree = await newContext.getTree({ maxDepth: 2 });
console.log('Context tree:', contextTree);

// Set viewport for responsive testing
await newContext.setViewport(375, 812, 3.0); // iPhone 12 Pro dimensions

// Capture screenshots
let fullScreenshot = await newContext.captureScreenshot();
let elementScreenshot = await newContext.captureElementScreenshot({
  sharedId: 'element-id',
  handle: 'element-handle'
});

// Print to PDF
let pdfResult = await newContext.printPage({
  orientation: 'portrait',
  scale: 1.0,
  background: true,
  width: 8.27, // A4 width in inches
  height: 11.7 // A4 height in inches
});

// Handle prompts
await newContext.handleUserPrompt(true, 'User input text');

// History navigation
await newContext.back();
await newContext.forward();
await newContext.traverseHistory(-2); // Go back 2 pages

BiDi Locators

Advanced locator strategies specific to the BiDi protocol.

/**
 * BiDi-specific element locators
 */
class Locator {
  /** CSS selector locator */
  static css(selector: string): Locator;
  
  /** XPath locator */
  static xpath(xpath: string): Locator;
  
  /** Inner text locator with options */
  static innerText(text: string, options?: InnerTextOptions): Locator;
}

interface InnerTextOptions {
  ignoreCase?: boolean;
  matchType?: 'full' | 'partial';
  maxDepth?: number;
}

interface LocateOptions {
  maxNodeCount?: number;
  serializationOptions?: SerializationOptions;
  startNodes?: NodeReference[];
}

interface SerializationOptions {
  maxDomDepth?: number;
  maxObjectDepth?: number;
  includeShadowTree?: 'none' | 'open' | 'all';
}

Usage Examples:

// BiDi locators
let cssLocator = Locator.css('.button[data-action="submit"]');
let xpathLocator = Locator.xpath('//button[contains(@class, "primary")]');

// Text-based location
let textLocator = Locator.innerText('Submit', {
  ignoreCase: true,
  matchType: 'partial'
});

// Locate nodes with options
let nodes = await context.locateNodes(cssLocator, {
  maxNodeCount: 10,
  serializationOptions: {
    maxDomDepth: 2,
    includeShadowTree: 'open'
  }
});

// Convert to WebElements
let element = await context.locateElement(cssLocator);
let elements = await context.locateElements(textLocator);

LogInspector Class

Real-time log monitoring and filtering with BiDi protocol.

/**
 * BiDi log inspection and monitoring
 */
class LogInspector {
  constructor(driver: WebDriver);
  
  /** Start listening for log entries */
  onLog(callback: (logEntry: LogEntry) => void): Promise<void>;
  
  /** Stop listening for log entries */
  close(): Promise<void>;
  
  /** Filter logs by level */
  filterByLevel(level: string): LogInspector;
  
  /** Filter logs by source */
  filterBySource(source: string): LogInspector;
  
  /** Filter logs by text content */
  filterByText(pattern: string | RegExp): LogInspector;
}

interface LogEntry {
  level: string;
  text: string;
  timestamp: number;
  source: {
    realm: string;
    context: string;
  };
  type: string;
  method?: string;
  args?: any[];
}

Usage Examples:

const { LogInspector } = require('selenium-webdriver');

// Create log inspector
let logInspector = new LogInspector(driver);

// Listen to all logs
await logInspector.onLog((logEntry) => {
  console.log(`[${logEntry.level}] ${logEntry.text}`);
});

// Filter logs by level
let errorInspector = new LogInspector(driver);
await errorInspector
  .filterByLevel('error')
  .onLog((errorEntry) => {
    console.error('Error detected:', errorEntry.text);
    // Handle critical errors
  });

// Filter by source
let consoleInspector = new LogInspector(driver);
await consoleInspector
  .filterBySource('console-api')
  .onLog((consoleEntry) => {
    console.log('Console output:', consoleEntry.text);
  });

// Filter by text pattern
let apiInspector = new LogInspector(driver);
await apiInspector
  .filterByText(/API.*error/i)
  .onLog((apiError) => {
    console.warn('API error detected:', apiError.text);
  });

// Close inspector when done
await logInspector.close();

NetworkInspector Class

Network request and response monitoring with BiDi protocol.

/**
 * BiDi network inspection and monitoring
 */
class NetworkInspector {
  constructor(driver: WebDriver);
  
  /** Start network monitoring */
  start(): Promise<void>;
  
  /** Stop network monitoring */
  stop(): Promise<void>;
  
  /** Listen for request events */
  onRequest(callback: (request: NetworkRequest) => void): Promise<void>;
  
  /** Listen for response events */
  onResponse(callback: (response: NetworkResponse) => void): Promise<void>;
  
  /** Listen for network errors */
  onError(callback: (error: NetworkError) => void): Promise<void>;
  
  /** Add request interception */
  addIntercept(pattern: InterceptPattern): Promise<string>;
  
  /** Remove request interception */
  removeIntercept(interceptId: string): Promise<void>;
  
  /** Continue intercepted request */
  continueRequest(requestId: string, overrides?: RequestOverrides): Promise<void>;
  
  /** Fail intercepted request */
  failRequest(requestId: string, errorReason: string): Promise<void>;
  
  /** Provide intercepted response */
  provideResponse(requestId: string, response: ResponseData): Promise<void>;
}

interface NetworkRequest {
  requestId: string;
  url: string;
  method: string;
  headers: Record<string, string>;
  body?: string;
  timestamp: number;
}

interface NetworkResponse {
  requestId: string;
  url: string;
  status: number;
  headers: Record<string, string>;
  body?: string;
  timestamp: number;
}

Usage Examples:

const { NetworkInspector } = require('selenium-webdriver');

// Create network inspector
let networkInspector = new NetworkInspector(driver);
await networkInspector.start();

// Monitor requests
await networkInspector.onRequest((request) => {
  console.log(`Request: ${request.method} ${request.url}`);
  
  if (request.url.includes('/api/')) {
    console.log('API request headers:', request.headers);
  }
});

// Monitor responses
await networkInspector.onResponse((response) => {
  console.log(`Response: ${response.status} ${response.url}`);
  
  if (response.status >= 400) {
    console.error('HTTP error response:', response);
  }
});

// Monitor network errors
await networkInspector.onError((error) => {
  console.error('Network error:', error);
});

// Request interception
let interceptId = await networkInspector.addIntercept({
  urlPattern: '*/api/data',
  method: 'GET'
});

await networkInspector.onRequest(async (request) => {
  if (request.url.includes('/api/data')) {
    // Modify request or provide mock response
    await networkInspector.provideResponse(request.requestId, {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ mocked: true, data: [] })
    });
  } else {
    // Continue normal request
    await networkInspector.continueRequest(request.requestId);
  }
});

// Clean up
await networkInspector.removeIntercept(interceptId);
await networkInspector.stop();

ScriptManager Class

Script execution and management with BiDi protocol for enhanced JavaScript capabilities.

/**
 * BiDi script execution and management
 */
class ScriptManager {
  constructor(driver: WebDriver);
  
  /** Evaluate script in browsing context */
  evaluate(script: string, options?: EvaluateOptions): Promise<any>;
  
  /** Call function with arguments */
  callFunction(functionDeclaration: string, options?: CallFunctionOptions): Promise<any>;
  
  /** Add preload script */
  addPreloadScript(script: string, contexts?: string[]): Promise<string>;
  
  /** Remove preload script */
  removePreloadScript(scriptId: string): Promise<void>;
  
  /** Get realms (execution contexts) */
  getRealms(options?: GetRealmsOptions): Promise<RealmInfo[]>;
  
  /** Disown handles (release object references) */
  disown(handles: string[]): Promise<void>;
}

interface EvaluateOptions {
  awaitPromise?: boolean;
  resultOwnership?: 'root' | 'none';
  serializationOptions?: SerializationOptions;
  target?: {
    context: string;
    sandbox?: string;
  };
}

interface RealmInfo {
  realm: string;
  origin: string;
  type: 'window' | 'worker' | 'paint-worklet' | 'audio-worklet' | 'service-worker' | 'shared-worker' | 'dedicated-worker';
  context?: string;
  sandbox?: string;
}

Usage Examples:

const { ScriptManager } = require('selenium-webdriver');

// Create script manager
let scriptManager = new ScriptManager(driver);

// Evaluate JavaScript
let result = await scriptManager.evaluate(`
  return {
    title: document.title,
    url: window.location.href,
    userAgent: navigator.userAgent
  };
`, {
  awaitPromise: false,
  resultOwnership: 'root'
});

console.log('Page info:', result);

// Call function with arguments
let sum = await scriptManager.callFunction(`
  function(a, b) {
    return a + b;
  }
`, {
  arguments: [
    { type: 'number', value: 10 },
    { type: 'number', value: 20 }
  ],
  awaitPromise: false
});

console.log('Sum:', sum); // 30

// Add preload script (runs before page load)
let preloadScriptId = await scriptManager.addPreloadScript(`
  window.testMode = true;
  window.startTime = Date.now();
  
  // Override console methods for testing
  const originalLog = console.log;
  console.log = function(...args) {
    originalLog('[TEST]', ...args);
  };
`);

// Navigate to page (preload script will run)
await driver.get('https://example.com');

// Script is now active on the page
let testMode = await driver.executeScript('return window.testMode');
console.log('Test mode active:', testMode);

// Get execution realms
let realms = await scriptManager.getRealms();
console.log('Available realms:', realms);

// Remove preload script
await scriptManager.removePreloadScript(preloadScriptId);

BrowsingContextInspector Class

Monitor browsing context lifecycle events and changes.

/**
 * BiDi browsing context inspection and monitoring
 */
class BrowsingContextInspector {
  constructor(driver: WebDriver);
  
  /** Listen for context created events */
  onContextCreated(callback: (context: ContextInfo) => void): Promise<void>;
  
  /** Listen for context destroyed events */
  onContextDestroyed(callback: (context: ContextInfo) => void): Promise<void>;
  
  /** Listen for navigation started events */
  onNavigationStarted(callback: (navigation: NavigationInfo) => void): Promise<void>;
  
  /** Listen for navigation completed events */
  onNavigationCompleted(callback: (navigation: NavigationInfo) => void): Promise<void>;
  
  /** Listen for user prompt events */
  onUserPrompt(callback: (prompt: UserPromptInfo) => void): Promise<void>;
  
  /** Stop monitoring */
  close(): Promise<void>;
}

interface ContextInfo {
  context: string;
  url: string;
  children: ContextInfo[];
  parent?: string;
  userContext: string;
}

interface NavigationInfo {
  context: string;
  navigation: string;
  url: string;
  timestamp: number;
}

interface UserPromptInfo {
  context: string;
  type: 'alert' | 'confirm' | 'prompt' | 'beforeunload';
  message: string;
  defaultValue?: string;
}

Usage Examples:

const { BrowsingContextInspector } = require('selenium-webdriver');

// Create context inspector
let contextInspector = new BrowsingContextInspector(driver);

// Monitor new contexts (tabs, iframes)
await contextInspector.onContextCreated((context) => {
  console.log('New context created:', context.url);
  
  if (context.url.includes('popup')) {
    console.log('Popup detected, may need handling');
  }
});

// Monitor context destruction
await contextInspector.onContextDestroyed((context) => {
  console.log('Context destroyed:', context.context);
});

// Monitor navigation events
await contextInspector.onNavigationStarted((navigation) => {
  console.log('Navigation started to:', navigation.url);
});

await contextInspector.onNavigationCompleted((navigation) => {
  console.log('Navigation completed:', navigation.url);
  console.log('Load time:', Date.now() - navigation.timestamp, 'ms');
});

// Monitor user prompts
await contextInspector.onUserPrompt((prompt) => {
  console.log(`User prompt detected: ${prompt.type} - ${prompt.message}`);
  
  // Auto-handle prompts based on type
  if (prompt.type === 'alert') {
    // Handle alert automatically
  } else if (prompt.type === 'confirm') {
    // Handle confirmation
  }
});

// Navigate and see events fire
await driver.get('https://example.com');

// Clean up
await contextInspector.close();

Input Class (BiDi)

Enhanced input handling with BiDi protocol for advanced interaction capabilities.

/**
 * BiDi input handling for advanced interactions
 */
class Input {
  constructor(driver: WebDriver);
  
  /** Perform action sequence in browsing context */
  perform(contextId: string, actions: ActionSequence[]): Promise<void>;
  
  /** Release all input sources */
  release(contextId: string): Promise<void>;
  
  /** Set files on input element */
  setFiles(contextId: string, element: ElementReference, files: string[]): Promise<void>;
}

interface ActionSequence {
  type: 'pointer' | 'key' | 'wheel';
  id: string;
  actions: Action[];
}

interface Action {
  type: string;
  duration?: number;
  x?: number;
  y?: number;
  button?: number;
  key?: string;
  value?: string;
  deltaX?: number;
  deltaY?: number;
}

Usage Examples:

const { Input } = require('selenium-webdriver');

// Create BiDi input handler
let input = new Input(driver);
let contextId = await driver.getWindowHandle();

// Complex pointer sequence
await input.perform(contextId, [{
  type: 'pointer',
  id: 'mouse',
  actions: [
    { type: 'pointerMove', x: 100, y: 100, duration: 500 },
    { type: 'pointerDown', button: 0 },
    { type: 'pointerMove', x: 200, y: 200, duration: 1000 },
    { type: 'pointerUp', button: 0 }
  ]
}]);

// Multi-touch gestures
await input.perform(contextId, [
  {
    type: 'pointer',
    id: 'finger1',
    actions: [
      { type: 'pointerMove', x: 100, y: 100 },
      { type: 'pointerDown', button: 0 },
      { type: 'pointerMove', x: 150, y: 150, duration: 1000 },
      { type: 'pointerUp', button: 0 }
    ]
  },
  {
    type: 'pointer', 
    id: 'finger2',
    actions: [
      { type: 'pointerMove', x: 200, y: 200 },
      { type: 'pointerDown', button: 0 },
      { type: 'pointerMove', x: 150, y: 150, duration: 1000 },
      { type: 'pointerUp', button: 0 }
    ]
  }
]);

// File upload via BiDi
let fileInput = await driver.findElement(By.css('input[type="file"]'));
await input.setFiles(contextId, {
  sharedId: await fileInput.getId()
}, ['/path/to/file1.jpg', '/path/to/file2.png']);

// Release all inputs
await input.release(contextId);