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

wait-conditions.mddocs/

Wait Conditions

Intelligent waiting mechanisms for handling dynamic web applications and timing-sensitive operations with built-in conditions and custom condition support.

Capabilities

Page State Conditions

Wait for various page state changes including title, URL, and alert presence.

/**
 * Wait for exact page title match
 * @param title - Expected title string
 * @returns Condition that resolves when title matches
 */
function titleIs(title: string): Condition<boolean>;

/**
 * Wait for page title to contain substring
 * @param substr - Substring to search for in title
 * @returns Condition that resolves when title contains substring
 */
function titleContains(substr: string): Condition<boolean>;

/**
 * Wait for page title to match regular expression
 * @param regex - Regular expression to match against title
 * @returns Condition that resolves when title matches regex
 */
function titleMatches(regex: RegExp): Condition<boolean>;

/**
 * Wait for exact URL match
 * @param url - Expected URL string
 * @returns Condition that resolves when URL matches
 */
function urlIs(url: string): Condition<boolean>;

/**
 * Wait for URL to contain substring
 * @param substrUrl - Substring to search for in URL
 * @returns Condition that resolves when URL contains substring
 */
function urlContains(substrUrl: string): Condition<boolean>;

/**
 * Wait for URL to match regular expression
 * @param regex - Regular expression to match against URL
 * @returns Condition that resolves when URL matches regex
 */
function urlMatches(regex: RegExp): Condition<boolean>;

/**
 * Wait for alert dialog to be present
 * @returns Condition that resolves to Alert when present
 */
function alertIsPresent(): Condition<Alert>;

Usage Examples:

const { Builder, By, until } = require('selenium-webdriver');

let driver = await new Builder().forBrowser('chrome').build();

// Wait for page title changes
await driver.get('https://example.com');
await driver.wait(until.titleIs('Welcome to Example'), 5000);

// Wait for title to contain text
await driver.wait(until.titleContains('Loading'), 3000);

// Wait for URL changes after navigation
await driver.findElement(By.linkText('Next Page')).click();
await driver.wait(until.urlContains('/page2'), 5000);

// Wait for URL pattern match
await driver.wait(until.urlMatches(/\/user\/\d+/), 3000);

// Wait for alert and handle it
await driver.findElement(By.id('show-alert')).click();
let alert = await driver.wait(until.alertIsPresent(), 2000);
console.log('Alert text:', await alert.getText());
await alert.accept();

Element Location Conditions

Wait for elements to appear or disappear from the DOM.

/**
 * Wait for element to be located in DOM
 * @param locator - Element locator
 * @returns Condition that resolves to WebElement when located
 */
function elementLocated(locator: By): Condition<WebElement>;

/**
 * Wait for elements to be located in DOM
 * @param locator - Element locator  
 * @returns Condition that resolves to WebElement array when located
 */
function elementsLocated(locator: By): Condition<WebElement[]>;

/**
 * Wait for element to become stale (removed from DOM)
 * @param element - WebElement to wait for staleness
 * @returns Condition that resolves when element becomes stale
 */
function stalenessOf(element: WebElement): Condition<boolean>;

Usage Examples:

// Wait for element to appear in DOM
let dynamicElement = await driver.wait(
  until.elementLocated(By.id('dynamic-content')), 
  10000
);

// Wait for multiple elements
let listItems = await driver.wait(
  until.elementsLocated(By.css('.list-item')), 
  5000
);
console.log(`Found ${listItems.length} list items`);

// Wait for element to be removed
let loadingSpinner = await driver.findElement(By.id('loading'));
await driver.wait(until.stalenessOf(loadingSpinner), 8000);
console.log('Loading spinner disappeared');

Element State Conditions

Wait for elements to reach specific states like visibility, interactability, and selection.

/**
 * Wait for element to be visible
 * @param elementOrLocator - WebElement or locator
 * @returns Condition that resolves to WebElement when visible
 */
function elementIsVisible(elementOrLocator: WebElement | By): Condition<WebElement>;

/**
 * Wait for element to be invisible/hidden
 * @param elementOrLocator - WebElement or locator
 * @returns Condition that resolves when element is not visible
 */
function elementIsNotVisible(elementOrLocator: WebElement | By): Condition<boolean>;

/**
 * Wait for element to be enabled
 * @param elementOrLocator - WebElement or locator
 * @returns Condition that resolves to WebElement when enabled
 */
function elementIsEnabled(elementOrLocator: WebElement | By): Condition<WebElement>;

/**
 * Wait for element to be disabled
 * @param elementOrLocator - WebElement or locator
 * @returns Condition that resolves when element is disabled
 */
function elementIsDisabled(elementOrLocator: WebElement | By): Condition<boolean>;

/**
 * Wait for element to be selected (checkboxes, radio buttons, options)
 * @param elementOrLocator - WebElement or locator
 * @returns Condition that resolves when element is selected
 */
function elementIsSelected(elementOrLocator: WebElement | By): Condition<boolean>;

/**
 * Wait for element to be deselected
 * @param elementOrLocator - WebElement or locator
 * @returns Condition that resolves when element is not selected
 */
function elementIsNotSelected(elementOrLocator: WebElement | By): Condition<boolean>;

/**
 * Wait for element to be clickable (visible and enabled)
 * @param elementOrLocator - WebElement or locator
 * @returns Condition that resolves to WebElement when clickable
 */
function elementIsClickable(elementOrLocator: WebElement | By): Condition<WebElement>;

Usage Examples:

// Wait for element to become visible
let hiddenPanel = await driver.wait(
  until.elementIsVisible(By.id('info-panel')), 
  5000
);

// Wait for loading indicator to disappear
await driver.wait(
  until.elementIsNotVisible(By.className('loading-spinner')), 
  10000
);

// Wait for form field to be enabled
let submitButton = await driver.wait(
  until.elementIsEnabled(By.id('submit-btn')), 
  3000
);

// Wait for checkbox to be selected
await driver.findElement(By.id('terms')).click();
await driver.wait(
  until.elementIsSelected(By.id('terms')), 
  1000
);

// Wait for button to be clickable
let actionButton = await driver.wait(
  until.elementIsClickable(By.id('action-btn')), 
  5000
);
await actionButton.click();

Element Text Conditions

Wait for element text content to match specific patterns.

/**
 * Wait for element text to exactly match
 * @param elementOrLocator - WebElement or locator
 * @param text - Expected text content
 * @returns Condition that resolves when text matches exactly
 */
function elementTextIs(elementOrLocator: WebElement | By, text: string): Condition<boolean>;

/**
 * Wait for element text to contain substring
 * @param elementOrLocator - WebElement or locator
 * @param substr - Substring to search for
 * @returns Condition that resolves when text contains substring
 */
function elementTextContains(elementOrLocator: WebElement | By, substr: string): Condition<boolean>;

/**
 * Wait for element text to match regular expression
 * @param elementOrLocator - WebElement or locator
 * @param regex - Regular expression to match
 * @returns Condition that resolves when text matches regex
 */
function elementTextMatches(elementOrLocator: WebElement | By, regex: RegExp): Condition<boolean>;

Usage Examples:

// Wait for exact text match
await driver.wait(
  until.elementTextIs(By.id('status'), 'Operation Complete'), 
  8000
);

// Wait for text to contain substring
await driver.wait(
  until.elementTextContains(By.id('counter'), 'items processed'), 
  5000
);

// Wait for text pattern match
await driver.wait(
  until.elementTextMatches(By.id('timestamp'), /\d{4}-\d{2}-\d{2}/), 
  3000
);

// Wait for dynamic content updates
let messageElement = await driver.findElement(By.id('message'));
await driver.findElement(By.id('update-btn')).click();
await driver.wait(
  until.elementTextContains(messageElement, 'Updated successfully'), 
  4000
);

Frame Conditions

Wait for frame availability and switching.

/**
 * Wait until able to switch to frame
 * @param frame - Frame locator, index, name, or WebElement
 * @returns Condition that resolves when frame is available
 */
function ableToSwitchToFrame(frame: number | string | By | WebElement): Condition<boolean>;

Usage Examples:

// Wait for frame to be available by index
await driver.wait(until.ableToSwitchToFrame(0), 5000);

// Wait for frame by name
await driver.wait(until.ableToSwitchToFrame('content-frame'), 3000);

// Wait for frame by locator
await driver.wait(
  until.ableToSwitchToFrame(By.id('payment-frame')), 
  8000
);

// Wait for frame element
let frameElement = await driver.findElement(By.tagName('iframe'));
await driver.wait(until.ableToSwitchToFrame(frameElement), 4000);

Custom Conditions

Create custom wait conditions for specific application needs.

/**
 * Custom condition interface
 */
interface Condition<T> {
  /** Description of what the condition waits for */
  description(): string;
}

/**
 * Create custom condition
 * @param message - Description of the condition
 * @param fn - Function that returns truthy value when condition is met
 * @returns Custom condition
 */
function Condition<T>(message: string, fn: (driver: WebDriver) => T | Promise<T>): Condition<T>;

Usage Examples:

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

// Custom condition for page load
let pageFullyLoaded = new Condition('page fully loaded', async (driver) => {
  let readyState = await driver.executeScript('return document.readyState');
  let jQueryReady = await driver.executeScript('return typeof jQuery !== "undefined" ? jQuery.active === 0 : true');
  return readyState === 'complete' && jQueryReady;
});

await driver.wait(pageFullyLoaded, 10000);

// Custom condition for element count
let minimumItemsLoaded = new Condition('at least 5 items loaded', async (driver) => {
  let items = await driver.findElements(By.className('item'));
  return items.length >= 5 ? items : false;
});

let items = await driver.wait(minimumItemsLoaded, 15000);
console.log(`Found ${items.length} items`);

// Custom condition for API response
let dataLoaded = new Condition('data loaded from API', async (driver) => {
  let isLoaded = await driver.executeScript(`
    return window.apiData && window.apiData.loaded === true;
  `);
  return isLoaded;
});

await driver.wait(dataLoaded, 30000);

// Custom condition with element interaction
let modalClosed = new Condition('modal dialog closed', async (driver) => {
  let modals = await driver.findElements(By.className('modal-backdrop'));
  return modals.length === 0;
});

await driver.findElement(By.className('modal-close')).click();
await driver.wait(modalClosed, 5000);

Wait Method Usage

The WebDriver wait method with timeout and custom error messages.

/**
 * Wait for condition to be satisfied
 * @param condition - Condition to wait for
 * @param timeout - Maximum time to wait in milliseconds (default: 5000)
 * @param message - Custom error message for timeout
 * @returns Promise that resolves with condition result
 */
WebDriver.prototype.wait<T>(
  condition: Condition<T>, 
  timeout?: number, 
  message?: string
): Promise<T>;

Usage Examples:

// Basic wait with default timeout (5 seconds)
let element = await driver.wait(until.elementLocated(By.id('target')));

// Wait with custom timeout
let button = await driver.wait(
  until.elementIsClickable(By.id('submit')), 
  10000  // 10 seconds
);

// Wait with custom error message
let result = await driver.wait(
  until.titleContains('Dashboard'), 
  8000,
  'Dashboard page did not load within 8 seconds'
);

// Combining multiple conditions
let loginComplete = new Condition('login process complete', async (driver) => {
  try {
    // Check if we're redirected to dashboard
    let url = await driver.getCurrentUrl();
    if (!url.includes('/dashboard')) return false;
    
    // Check if user menu is visible
    let menus = await driver.findElements(By.id('user-menu'));
    if (menus.length === 0) return false;
    
    // Check if loading indicators are gone
    let loading = await driver.findElements(By.className('loading'));
    return loading.length === 0;
  } catch (error) {
    return false;
  }
});

await driver.wait(loginComplete, 15000, 'Login process did not complete successfully');

Polling and Retry Patterns

Advanced waiting patterns for complex scenarios.

Usage Examples:

// Retry pattern with custom intervals
async function waitWithRetry(condition, maxAttempts = 5, interval = 1000) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await driver.wait(condition, interval);
    } catch (error) {
      if (attempt === maxAttempts) throw error;
      console.log(`Attempt ${attempt} failed, retrying...`);
      await driver.sleep(interval);
    }
  }
}

// Usage
let element = await waitWithRetry(
  until.elementLocated(By.id('flaky-element')), 
  3, 
  2000
);

// Exponential backoff waiting
async function waitWithBackoff(condition, maxWait = 30000) {
  let timeout = 1000;
  let totalTime = 0;
  
  while (totalTime < maxWait) {
    try {
      return await driver.wait(condition, timeout);
    } catch (error) {
      totalTime += timeout;
      timeout = Math.min(timeout * 2, 5000); // Max 5 second intervals
      if (totalTime >= maxWait) throw error;
      await driver.sleep(500);
    }
  }
}

// Conditional waiting based on page state
let conditionalWait = new Condition('conditional element check', async (driver) => {
  let pageType = await driver.executeScript('return document.body.dataset.pageType');
  
  if (pageType === 'loading') {
    // Wait for loading to complete
    let loading = await driver.findElements(By.className('spinner'));
    return loading.length === 0;
  } else if (pageType === 'form') {
    // Wait for form validation
    let errors = await driver.findElements(By.className('error'));
    return errors.length === 0;
  } else {
    // Default condition
    return true;
  }
});

await driver.wait(conditionalWait, 10000);