EXTENSIONS
UI Testing
Automate cross-browser web testing using Karate's built-in driver. Karate provides Chrome DevTools Protocol support for native Chrome automation, W3C WebDriver compatibility for cross-browser testing, and Playwright integration for advanced scenarios — all with the same simple Gherkin syntax.
Karate v2 features a completely rewritten CDP driver with auto-wait, browser pooling, and Shadow DOM support. Chrome/Chromium/Edge via CDP is the primary driver. W3C WebDriver is fully supported for cross-browser testing (Firefox, Safari, Edge). Playwright support is planned. See What's New in v2 for details.
On this page:
- Basic Setup - Launch browsers and navigate to pages
- Driver Configuration - Browser options, headless, remote WebDriver, proxy
- Driver Types - Chrome, Playwright, WebDriver, Appium
- Locators - CSS, XPath, wildcards, friendly locators, tree walking
- Element Interactions - Click, input, select, mouse, file upload
- Waiting Strategies - waitFor, retry, waitUntil, chaining
- Browser JavaScript - script(), scriptAll(), scriptAwait(), function composition
- Pages and Frames - Tabs, iframes, dialogs
- Cookies - Set, get, delete cookies
- Screenshots - Capture, PDF, visual regression
- HTTP Interception - Mock browser requests with Karate mocks
- Hybrid Tests - Combine API and UI testing
- Mobile Testing - Device emulation, Appium
- Docker and CI - karate-chrome, Selenium Grid, distributed testing
- Debugging - VS Code extension, karate.stop(), highlight
- Code Reuse - Shared features, locator patterns
- Java API - Driver and Chrome programmatic APIs
To understand how Karate compares to other UI automation frameworks, read: The world needs an alternative to Selenium - so we built one.
Basic Browser Setup
Configure the driver to launch a browser and navigate to a page:
Feature: Simple browser test
Scenario: Open a webpage
# Tell Karate to use Chrome browser
* configure driver = { type: 'chrome' }
# Open the GitHub login page - this launches the browser
* driver 'https://github.com/login'
# Verify the page loaded by checking the title
* match driver.title contains 'GitHub'
The driver keyword navigates to a URL and initializes the browser instance. All subsequent steps use this driver until the scenario ends.
- The browser launches on the first
driverkeyword - The browser closes automatically when the scenario ends
- Use
driver.quit()only if you need explicit cleanup mid-scenario
Browser Pooling (v2)
Karate v2 automatically pools browser instances when running in parallel — no configuration needed:
Runner.path("features/")
.parallel(4); // pool of 4 browser instances auto-created
- Browser instances are reused across scenarios
- Pool size auto-scales to match the parallelism level
- Clean state reset between scenarios (
about:blank, clear cookies)
For custom browser sources (e.g., Testcontainers), extend PooledDriverProvider. See Docker and CI.
Driver Configuration
Configuration Options
Configure browser behavior with the configure driver statement:
Feature: Driver configuration
Scenario: Chrome with options
# headless: run without visible window, showDriverLog: log HTTP traffic for debugging
* configure driver = { type: 'chrome', headless: true, showDriverLog: true }
* driver 'https://example.com'
| Key | Description | Default |
|---|---|---|
type | Browser type (see Driver Types) | - |
executable | Path to browser or driver executable | Auto-detected |
start | Whether Karate should start the executable | true |
stop | Whether to close browser after scenario (set false for debugging) | true |
port | Port for driver communication | Varies by type |
host | Host for driver communication | localhost |
headless | Run without visible browser window (Chrome only) | false |
timeout | Page load timeout in milliseconds | 30000 |
pollAttempts | Number of attempts to wait for port to be ready | 20 |
pollInterval | Milliseconds between poll attempts | 250 |
showDriverLog | Include WebDriver HTTP traffic in report | false |
showProcessLog | Include executable/driver logs in report | false |
showBrowserLog | Include browser console logs in report | true |
addOptions | Additional CLI arguments as array | null |
beforeStart | OS command to run before scenario (e.g., start video recording) | null |
afterStop | OS command to run after scenario (e.g., stop video recording) | null |
videoFile | Path to video file to embed in HTML report | null |
httpConfig | HTTP client config for remote WebDriver, e.g., { readTimeout: 120000 } | null |
attach | URL pattern to attach to existing Chrome session (type: chrome, start: false) | null |
userDataDir | Path to Chrome user data directory (pass null to use system defaults) | Auto-created |
highlight | Highlight elements before actions (for demos/debugging) | false |
highlightDuration | Duration to highlight elements in milliseconds | 3000 |
screenshotOnFailure | Auto-capture screenshot on test failure | true |
Headless Mode
Run tests without a visible browser window. Ideal for CI/CD pipelines where no display is available:
Feature: Headless testing
Scenario: Run in headless mode
# headless: true runs Chrome without opening a visible window
* configure driver = { type: 'chrome', headless: true }
* driver 'https://example.com'
# You can still take screenshots in headless mode
* screenshot()
Chrome Options
Pass Chrome-specific arguments and preferences. This example shows how to set up driver config globally in karate-config.js:
function fn() {
var config = {
driverConfig: {
type: 'chrome',
// Chrome command-line arguments
addOptions: [
'--disable-notifications', // Block notification popups
'--disable-popup-blocking', // Allow popups (useful for OAuth flows)
'--start-maximized' // Open browser maximized
],
// Chrome preferences (browser settings)
prefs: {
'download.default_directory': '/tmp/downloads' // Set download folder
}
}
};
// Apply driver config globally for all scenarios
karate.configure('driver', config.driverConfig);
return config;
}
webDriverUrl
Connect to a remote WebDriver server (Selenium Grid, Zalenium, cloud providers):
Feature: Remote WebDriver
Scenario: Connect to Selenium Grid
# start: false means don't launch a local browser - connect to remote instead
# webDriverUrl points to the Selenium Grid hub
* configure driver = { type: 'chromedriver', start: false, webDriverUrl: 'http://localhost:4444/wd/hub' }
* driver 'https://example.com'
webDriverSession
Pass custom capabilities to WebDriver. This is useful for headless mode, window size, or browser-specific options:
Feature: Custom WebDriver session
Background:
# Define WebDriver capabilities - this controls browser behavior
# alwaysMatch: capabilities that must be supported by the browser
* def session = { capabilities: { alwaysMatch: { browserName: 'chrome', 'goog:chromeOptions': { args: ['--headless', 'window-size=1280,720'] } } } }
Scenario: Chrome with custom capabilities
# Pass the session config to the driver
* configure driver = { type: 'chromedriver', webDriverSession: '#(session)' }
* driver 'https://example.com'
Common capabilities you can customize:
acceptInsecureCerts- Accept self-signed certificatesmoz:firefoxOptions- Firefox-specific options (e.g., headless mode)proxy- Proxy configuration (see Proxy Configuration)
Also see driver.sessionId to retrieve the WebDriver session ID for downloading test reports or videos.
webDriverPath
For Appium or Selenium Grid on localhost, you may need to append a path:
Feature: Appium with path
Scenario: Connect to local Appium
* configure driver = { type: 'android', webDriverPath: '/wd/hub' }
* driver { webDriverSession: { desiredCapabilities: { app: 'com.example.app' } } }
Driver Types
Choose the driver type based on your testing needs:
| Type | Port | Description |
|---|---|---|
chrome | 9222 | Native Chrome via DevTools Protocol. Recommended for development. |
playwright | 4444 | Playwright integration for cross-browser testing. |
msedge | 9222 | Microsoft Edge (Chromium) via DevTools Protocol. |
chromedriver | 9515 | W3C Chrome WebDriver. |
geckodriver | 4444 | W3C Firefox WebDriver. |
safaridriver | 5555 | W3C Safari WebDriver (macOS only). |
msedgedriver | 9515 | W3C Microsoft Edge WebDriver. |
mswebdriver | 17556 | Microsoft Edge Legacy WebDriver (deprecated). |
iedriver | 5555 | Internet Explorer 11 WebDriver (deprecated). |
android | 4723 | Android automation via Appium. |
ios | 4723 | iOS automation via Appium. |
winappdriver | 4727 | Windows desktop application automation. |
Start with type: 'chrome' for development — it's fastest and requires no additional setup. In Karate v2, Chrome CDP is the primary driver with auto-wait and browser pooling built in.
Karate v2 fully supports W3C WebDriver for cross-browser testing. The chromedriver, geckodriver, safaridriver, and msedgedriver types all work with the new W3C WebDriver backend — achieving 100% pass rate on the W3C test suite. Chrome CDP remains the recommended driver for development due to its speed and extra capabilities (request interception, PDF generation). Appium and WinAppDriver types are planned for a future release.
Playwright Integration
Playwright emulation support is planned for Karate v2, replacing the v1 experimental integration. This will enable Firefox and WebKit testing via Playwright's CDP interface. The documentation below applies to Karate v1.
Playwright provides cross-browser support with Chromium, Firefox, and WebKit engines.
Setup
Add the Playwright dependency before karate-core:
<dependency>
<groupId>io.karate</groupId>
<artifactId>karate-playwright</artifactId>
<scope>test</scope>
</dependency>
Basic Usage
Feature: Playwright browser
Scenario: Test with Playwright
* configure driver = { type: 'playwright' }
* driver 'https://example.com'
* match driver.title == 'Example Domain'
Playwright Options
Configure browser type, context, and other Playwright-specific settings:
Feature: Playwright options
Background:
* def pwOptions = { browserType: 'firefox', context: { viewport: { width: 1280, height: 720 } } }
Scenario: Firefox with Playwright
* configure driver = { type: 'playwright', playwrightOptions: '#(pwOptions)' }
* driver 'https://example.com'
| Option | Description | Default |
|---|---|---|
browserType | chromium, firefox, or webkit | chromium |
channel | Browser channel (e.g., chrome, msedge) | chrome |
context | Playwright browser context options | - |
installBrowsers | Auto-download browsers on first run | true |
For connecting to a remote Playwright server, use playwrightUrl:
Feature: Remote Playwright
Scenario: Connect to Playwright server
* configure driver = { type: 'playwright', start: false, playwrightUrl: 'ws://localhost:4444' }
* driver 'https://example.com'
Playwright Legacy (NodeJS)
For environments requiring a separate Playwright server, you can start one using NodeJS:
npm i -D playwright
Create a server script (playwright/server.js):
const playwright = require('playwright');
const port = process.argv[2] || 4444;
const browserType = process.argv[3] || 'chromium';
const headless = process.argv[4] == 'true';
const serverPromise = playwright[browserType].launchServer({ headless: headless, port: port });
serverPromise.then(bs => console.log(bs.wsEndpoint()));
Create a batch file to start the server, and configure Karate to use it:
Feature: Playwright Legacy
Scenario: Use external Playwright server
* configure driver = { type: 'playwright', executable: 'path/to/start-server' }
* driver 'https://example.com'
Karate scans the log for ws:// URLs and passes three arguments to the executable: port, browserType, and headless.
W3C WebDriver (v2)
Karate v2 includes a fully compliant W3C WebDriver backend for cross-browser testing with Firefox, Safari, Edge, and Chrome. This uses the standard WebDriver protocol — the same one used by Selenium — but with Karate's simple Gherkin syntax.
Quick Examples
Chrome via chromedriver:
Feature: Chrome WebDriver
Scenario: Test with chromedriver
* configure driver = { type: 'chromedriver', headless: true }
* driver 'https://example.com'
* match driver.title == 'Example Domain'
Firefox via geckodriver:
Feature: Firefox WebDriver
Scenario: Test with Firefox
* configure driver = { type: 'geckodriver' }
* driver 'https://example.com'
* match driver.title == 'Example Domain'
Safari via safaridriver (macOS only):
Feature: Safari WebDriver
Scenario: Test with Safari
* configure driver = { type: 'safaridriver' }
* driver 'https://example.com'
* match driver.title == 'Example Domain'
W3C Driver Types
| Type | Executable | Default Port | Browser |
|---|---|---|---|
chromedriver | chromedriver | 9515 | Chrome |
geckodriver | geckodriver | 4444 | Firefox |
safaridriver | safaridriver | 5555 | Safari |
msedgedriver | msedgedriver | 9515 | Edge |
Karate auto-launches the driver executable. Ensure it's on your PATH or set the executable option.
Custom Capabilities
Use the capabilities option to pass W3C capabilities. They're merged into alwaysMatch:
Feature: Custom capabilities
Scenario: Headless Chrome via WebDriver
* configure driver = { type: 'chromedriver', capabilities: { 'goog:chromeOptions': { args: ['--headless'] } } }
* driver 'https://example.com'
For full control over the session payload, use webDriverSession:
Feature: Full session control
Scenario: Custom session
* def session = { capabilities: { alwaysMatch: { browserName: 'chrome', 'goog:chromeOptions': { args: ['--headless', 'window-size=1280,720'] } } } }
* configure driver = { type: 'chromedriver', webDriverSession: '#(session)' }
* driver 'https://example.com'
Remote WebDriver (Selenium Grid, Cloud)
Connect to remote WebDriver servers like Selenium Grid, SauceLabs, or BrowserStack:
Feature: Remote WebDriver
Scenario: Selenium Grid
* configure driver = { type: 'chromedriver', start: false, webDriverUrl: 'http://grid:4444/wd/hub' }
* driver 'https://example.com'
Feature: SauceLabs
Scenario: Cloud testing
* def caps = { platformName: 'Windows 10', browserVersion: 'latest', 'sauce:options': { tunnelId: 'my-tunnel' } }
* configure driver = { type: 'chromedriver', start: false, webDriverUrl: 'https://ondemand.saucelabs.com:443/wd/hub', capabilities: '#(caps)' }
* driver 'https://example.com'
CDP vs W3C WebDriver
| Feature | CDP (chrome) | W3C WebDriver (chromedriver, etc.) |
|---|---|---|
| Speed | Fastest (WebSocket) | Fast (HTTP) |
| Cross-browser | Chrome/Edge only | Any W3C browser |
| Request interception | Yes | No |
| PDF generation | Yes | No |
| Mouse (coordinate) | Yes | No |
| Keyboard input | Yes | Yes (W3C Actions API) |
| Remote/cloud | Via webSocketUrl | Via webDriverUrl |
| Setup | No extra executable | Requires driver executable |
Recommendation: Use CDP (type: 'chrome') for development and Chrome-only CI. Use W3C WebDriver for cross-browser testing or when connecting to Selenium Grid / cloud providers.
Proxy Configuration
For Chrome, use addOptions:
Feature: Chrome proxy
Scenario: With proxy
* configure driver = { type: 'chrome', addOptions: ['--proxy-server="https://proxy:5000"'] }
* driver 'https://example.com'
For WebDriver types, use webDriverSession:
Feature: WebDriver proxy
Background:
* def session = { capabilities: { browserName: 'chrome', proxy: { proxyType: 'manual', httpProxy: 'proxy:5000' } } }
Scenario: With proxy
* configure driver = { type: 'chromedriver', webDriverSession: '#(session)' }
* driver 'https://example.com'
Locators
CSS Selectors
Use CSS selectors to target elements:
Feature: CSS selectors
Scenario: Common CSS patterns
* driver 'https://example.com'
# By ID
* click('#login-button')
# By class
* click('.btn-primary')
# By attribute
* click('[data-testid="submit"]')
# Descendant
* input('.form-group input[name="email"]', 'test@example.com')
# Pseudo-class
* click('ul.menu li:first-child')
XPath Expressions
Use XPath for complex element selection (prefix with /):
Feature: XPath selectors
Scenario: XPath patterns
* driver 'https://example.com'
# By text content
* click('//button[text()="Submit"]')
# Partial text match
* click('//a[contains(text(), "Learn More")]')
# Navigate table structure
* def email = text('//tr[td[text()="John"]]/td[2]')
Wildcard Locators
Find elements by visible text content using {} syntax:
| Locator | Description |
|---|---|
{a}Click Me | First <a> with exact text "Click Me" |
{}Click Me | First element (any tag) with exact text "Click Me" |
{^}Click | First element containing text "Click" |
{^span}Click | First <span> containing text "Click" |
{div:2}Click Me | Second <div> with exact text "Click Me" |
{span/a}Click Me | First <a> inside <span> with exact text "Click Me" |
Feature: Wildcard locators
Scenario: Text-based selection
* driver 'https://example.com'
# Exact text match with tag
* click('{button}Submit')
# Partial text match
* click('{^a}Learn')
# Any tag with exact text
* waitFor('{}Success').exists
Wildcard locators select based on what users see, making tests more readable and resistant to CSS/HTML changes.
Friendly Locators
Find elements by their position relative to visible text—useful for form fields near labels:
| Method | Finds Element |
|---|---|
rightOf() | To the right of given locator |
leftOf() | To the left of given locator |
above() | Above given locator |
below() | Below given locator |
near() | Near given locator (any direction) |
Feature: Friendly locators
Scenario: Form input by label position
* driver 'https://example.com/form'
# Input field to the right of "Username" label
* rightOf('{}Username').input('john_doe')
# Checkbox to the left of "Remember me" text
* leftOf('{}Remember me').click()
# Dropdown below "Country" label
* below('{}Country').select('United States')
# Button near "Submit" text (handles varied layouts)
* near('{}Submit').click()
By default, friendly locators search for <input> elements. Override with find():
Feature: Friendly locator with find
Scenario: Find specific element type
* driver 'https://example.com'
# Find a span instead of input
* rightOf('{}Label').find('span').click()
# Find by text content
* rightOf('{}Label').find('{}Click Me').click()
Tree Walking
Navigate the DOM structure from a known element:
| Property | Returns |
|---|---|
parent | Parent element |
children | Array of child elements |
firstChild | First child element |
lastChild | Last child element |
previousSibling | Previous sibling element |
nextSibling | Next sibling element |
Feature: Tree walking
Scenario: Navigate DOM structure
* driver 'https://example.com'
* def row = locate('//td[text()="John"]')
# Click the button in the same row
* row.parent.locate('button').click()
# Get all cells in the row
* def cells = row.parent.children
* match cells.length == 4
Locator Lookup Pattern
Maintain locators in a JSON file for reusability across tests:
{
"login": {
"username": "#username",
"password": "#password",
"submit": "[data-testid='login-btn']"
},
"dashboard": {
"welcome": "{}Welcome",
"logout": "{a}Logout"
}
}
Feature: Locator lookup
Background:
* call read('locators.json')
Scenario: Use named locators
* driver 'https://example.com/login'
* input(login.username, 'john')
* input(login.password, 'secret')
* click(login.submit)
* waitFor(dashboard.welcome).exists
This pattern provides the benefits of centralized locators without the complexity of traditional Page Object Models.
Shadow DOM (v2)
CSS and wildcard locators work inside Shadow DOM elements in Karate v2:
Feature: Shadow DOM
Scenario: Interact with shadow DOM elements
* driver 'https://example.com/web-components'
# CSS selectors pierce shadow boundaries
* click('shadow-host >> button.inner')
# Wildcard locators also work inside shadow DOM
* click('{button}Submit')
Element Interactions
Click and Input
Basic element interactions for filling forms and clicking buttons:
Feature: Basic interactions
Scenario: Form interaction
* driver 'https://example.com/login'
# input(locator, value) - types text into a field
* input('#username', 'john@example.com')
* input('#password', 'secret123')
# click(locator) - clicks a button or link
* click('button[type="submit"]')
# text(locator) - gets the visible text from an element
* match text('#welcome') contains 'Welcome'
Special Keys
Use the Key object for special keystrokes:
Feature: Special keys
Scenario: Keyboard input
* driver 'https://example.com'
# Enter key
* input('#search', 'karate testing' + Key.ENTER)
# Key combinations
* input('#editor', Key.CONTROL + 'a')
# Tab through form
* input('#field1', 'value')
* input('#field1', Key.TAB)
# Escape to close modal
* input('body', Key.ESCAPE)
Delayed Input
Add delays between keystrokes for JavaScript-heavy forms:
Feature: Delayed input
Scenario: Slow typing for autocomplete
* driver 'https://example.com'
# 100ms delay between each character
* input('#search', 'new york', 100)
# Or with array syntax
* input('#search', ['n', 'e', 'w', Key.SPACE, 'y', 'o', 'r', 'k'], 100)
Select Dropdowns
For native HTML <select> elements:
Feature: Select dropdown
Scenario: Dropdown selection
* driver 'https://example.com/form'
# By visible text
* select('select[name="country"]', '{}United States')
# By value attribute
* select('select[name="state"]', 'CA')
# By index
* select('select[name="city"]', 2)
JavaScript-Powered Dropdowns
Modern dropdowns (Bootstrap, Material UI, etc.) require mouse interactions because they're not native HTML <select> elements:
Feature: JavaScript dropdown
Scenario: Bootstrap dropdown
* driver 'https://example.com'
# First click opens the dropdown menu
* mouse('.dropdown-toggle').click()
# Second click selects an item - use mouse() for JS-rendered elements
* mouse('{a}Option One').click()
For iterating through all dropdown items (useful for testing each option):
Feature: Loop through dropdown
Scenario: Select each option
* driver 'https://example.com'
# Get all dropdown items as an array
* def items = locateAll('a.dropdown-item')
# Define a function that opens dropdown, clicks item, waits
* def selectItem = function(item) { mouse('.dropdown-toggle').click(); item.mouse().click(); delay(500) }
# Loop through each item
* items.forEach(selectItem)
File Uploads
Multiple approaches for file upload:
Feature: File upload
Scenario: Native file input
* configure driver = { type: 'chrome' }
* driver 'https://example.com/upload'
# Chrome-native file input
* driver.inputFile('#file-upload', 'classpath:test-data/document.pdf')
# Multiple files
* driver.inputFile('#file-upload', ['classpath:file1.txt', 'classpath:file2.jpg'])
* click('#upload-button')
For cross-browser compatibility, use multipart upload:
Feature: Multipart upload
Scenario: HTTP-based upload
Given url 'https://example.com/upload'
And multipart file file = { read: 'classpath:document.pdf', filename: 'document.pdf', contentType: 'application/pdf' }
When method post
Then status 200
Mouse Actions
Complex mouse interactions:
Feature: Mouse actions
Scenario: Mouse operations
* driver 'https://example.com'
# Hover
* mouse('.menu-trigger').move()
* waitFor('.submenu').exists
# Click at coordinates
* mouse(100, 200).click()
# Double-click
* mouse('#item').doubleClick()
# Right-click (context menu)
* mouse('#file').rightClick()
# Drag and drop
* mouse('.draggable').down()
* mouse('.drop-zone').move().up()
Scroll
Scroll elements into view:
Feature: Scrolling
Scenario: Scroll to element
* driver 'https://example.com'
* scroll('#footer')
# Chain with click
* scroll('#hidden-button').click()
Waiting Strategies
Karate v2 automatically waits before element operations (click, input, etc.), significantly reducing the need for explicit waitFor() calls. Most interactions "just work" without manual waits. Use the strategies below for complex cases where auto-wait isn't sufficient.
Karate provides multiple wait strategies to handle dynamic content. Choose the right one for your use case:
waitFor()
Wait for an element to appear. Essential for pages with AJAX or lazy-loaded content:
Feature: Wait for element
Scenario: Wait for dynamic content
* driver 'https://example.com'
# Click triggers an async operation
* click('#load-data')
# waitFor() blocks until element exists, then returns the element
* waitFor('#results').exists
# Now safe to check text content
* match text('#results') contains 'Loaded'
waitForUrl()
Wait for the browser URL to change. Use after click actions that trigger page navigation:
Feature: Wait for URL
Scenario: Wait after navigation
* driver 'https://example.com'
# This click navigates to another page
* click('#next-page')
# waitForUrl uses "contains" match - no need for full URL
* waitForUrl('/page-2')
# URL now guaranteed to contain '/page-2'
* match driver.url contains '/page-2'
waitForText()
Wait for specific text content to appear in an element. Useful for status messages or loading states:
Feature: Wait for text
Scenario: Wait for status message
* driver 'https://example.com'
# Submit triggers processing
* click('#submit')
# Wait until element contains the text "Complete" (uses "contains" match)
* waitForText('#status', 'Complete')
waitForEnabled()
Wait for an element to become enabled. Common for form validation where submit is disabled until valid:
Feature: Wait for enabled
Scenario: Wait for button to enable
* driver 'https://example.com'
# Toggle checkbox to accept terms
* input('#terms', Key.SPACE)
# Button becomes enabled after checkbox is checked - wait then click
* waitForEnabled('#submit').click()
waitForResultCount()
Wait for a specific number of elements to exist. Perfect for data tables that load incrementally:
Feature: Wait for results
Scenario: Wait for table rows
* driver 'https://example.com'
# Search triggers loading of results
* click('#search')
# Wait until exactly 5 result rows exist, returns the elements
* def rows = waitForResultCount('.result-row', 5)
* match rows.length == 5
waitForAny()
Wait for any one of multiple possible elements to appear. Useful when different outcomes are possible:
Feature: Wait for any
Scenario: Handle conditional UI
* driver 'https://example.com'
# Don't know if we'll get success or error - wait for either
* retry(5, 10000).waitForAny('#success', '#error')
# optional() safely clicks if element exists, does nothing if not
* optional('#success').click()
* optional('#error').click()
waitUntil()
Wait for a JavaScript condition to become true. The most flexible wait - use for custom conditions:
Feature: Wait until condition
Scenario: Wait for page ready
* driver 'https://example.com'
# Wait for document to fully load (JS runs in browser context)
* waitUntil("document.readyState == 'complete'")
# With locator: _ is the element. Wait for progress bar to reach 100%
* waitUntil('#progress', "_.style.width == '100%'")
# Wait for element to not be disabled (! means "not")
* waitUntil('#submit', '!_.disabled')
retry()
Temporarily override the retry / wait settings for the next action. Use this when specific parts of your flow need longer waits. There are 3 forms:
retry()— use default retry settings (3 attempts, 3 second intervals)retry(count)— custom number of retry attemptsretry(count, interval)— custom attempts AND interval in milliseconds between them
The total wait time is count × interval. For example, retry(40, 250) waits up to 10 seconds.
Feature: Retry examples
Scenario: Retry with actions and waits
* driver 'https://example.com'
# retry implies waitFor before action — element must exist
* retry().click('#slow-button')
* retry(5).click('#very-slow-button')
* retry(5, 10000).click('#extremely-slow-button')
# retry with waitUntil — wait for JS condition to become true
* retry(40, 250).waitUntil("!document.querySelector('#loading-spinner')")
# retry with other wait methods
* retry(5, 10000).waitFor('#dynamic-content')
* retry(5, 10000).waitForEnabled('#submit')
* retry(5, 10000).waitForText('#status', 'Complete')
* retry(5, 10000).waitForUrl('/dashboard')
For actions like click() and input(), retry() implies a waitFor() before the action — the element must appear within the retry window or the test fails.
Default retry settings: 3 attempts with 3000ms intervals. Configure globally in karate-config.js:
// Change default retry for all scenarios
karate.configure('retry', { count: 5, interval: 2000 });
Chaining
Chain wait methods with actions for fluent, readable tests:
Feature: Method chaining
Scenario: Fluent chains
* driver 'https://example.com'
# Wait then click
* waitFor('#button').click()
# Retry with wait then click
* retry(5, 10000).waitForEnabled('#submit').click()
# Scroll then input
* scroll('#hidden-field').input('value')
# Mouse chain
* mouse('#menu').move()
* waitFor('.submenu').exists
Wait API Summary
All wait methods retry internally using the configured retry settings. Use retry() only when you need to override the defaults for a specific action:
| Method | Description |
|---|---|
waitFor('#id') | Wait for element to exist |
waitForText('#id', 'text') | Wait for element to contain text (string contains match) |
waitForEnabled('#id') | Wait for element to be enabled (shortcut for waitUntil('#id', '!_.disabled')) |
waitForUrl('path') | Wait for URL to contain string |
waitForResultCount('.class', n) | Wait for exactly n matching elements |
waitForAny('#a', '#b') | Wait for any one of multiple elements to appear |
waitUntil('expression') | Wait for browser JS expression to be truthy |
waitUntil('#id', '_.value == "x"') | Wait for element JS condition (_ is the element) |
retry(n, ms).waitFor('#id') | Override retry settings for this wait |
retry(n, ms).click('#id') | Wait for element then click (waitFor implied) |
- Use
waitFor()for the first element on a newly loaded page. Stick to this for 95% of tests. - Use
retry()only when you need to override the default wait time, e.g. for slow-loading content. retry().click('#id')is equivalent towaitFor('#id').click()— prefer the latter for readability.
Browser JavaScript
script()
Execute JavaScript in the browser:
Feature: Browser JavaScript
Scenario: Execute script
* driver 'https://example.com'
# Simple evaluation
* def result = script('1 + 2')
* match result == 3
# DOM manipulation
* script("document.querySelector('#hidden').style.display = 'block'")
# Get element property
* match script('#myDiv', '_.innerHTML') contains 'Hello'
# Trigger event
* waitFor('#input').script("_.dispatchEvent(new Event('change'))")
scriptAll()
Execute JavaScript on all matching elements:
Feature: Script all elements
Scenario: Extract table data
* driver 'https://example.com'
* def texts = scriptAll('table td', '_.textContent')
* match texts contains 'Expected Value'
scriptAll() with Filter
Filter results using a JavaScript predicate:
Feature: Filter script results
Scenario: Get specific cells
* driver 'https://example.com'
# Filter for cells containing "data"
* def filtered = scriptAll('td', '_.textContent', function(x){ return x.contains('data') })
* match filtered == ['data1', 'data2']
locateAll() with Filter
Filter located elements:
Feature: Filter located elements
Scenario: Find elements by attribute pattern
* driver 'https://example.com'
* def filter = function(el){ return el.attribute('data-id').startsWith('user_') }
* def userElements = locateAll('[data-id]', filter)
* userElements[0].click()
Function Composition
Create reusable JavaScript functions:
Feature: Function composition
Background:
# Reusable function to extract text from elements
* def getTexts = function(locator){ return scriptAll(locator, '_.textContent') }
Scenario: Use composed function
* driver 'https://example.com'
* def menuItems = getTexts('.menu-item')
* match menuItems contains 'Home'
Looping
Looping Over Elements
Iterate through located elements:
Feature: Loop over elements
Scenario: Click all items
* driver 'https://example.com'
* def buttons = locateAll('.action-button')
* buttons.forEach(btn => btn.click())
Loop Until
Repeat an action until a condition is met:
Feature: Loop until condition
Scenario: Delete all rows
* driver 'https://example.com'
* def deleteRow =
"""
function() {
if (!exists('.data-row')) return true;
click('.delete-button');
delay(500);
}
"""
* waitUntil(deleteRow)
Pages and Frames
Page Navigation
Control browser navigation:
Feature: Page navigation
Scenario: Navigate browser history
* driver 'https://example.com/page1'
* click('#next')
* waitForUrl('/page2')
# Go back
* driver.back()
* match driver.url contains '/page1'
# Go forward
* driver.forward()
# Refresh
* driver.refresh()
# Hard reload (clears cache)
* reload()
Multiple Windows and Tabs
Switch between browser windows:
Feature: Multiple windows
Scenario: Handle new tab
* driver 'https://example.com'
* click('#open-new-tab')
# Switch by index
* switchPage(1)
* match driver.title contains 'New Page'
# Switch back
* switchPage(0)
# Switch by title (contains match)
* switchPage('New Page')
# Close current tab
* close()
Working with Iframes
Switch context to an iframe:
Feature: Iframe handling
Scenario: Interact with iframe content
* driver 'https://example.com'
# Switch by selector
* switchFrame('#editor-iframe')
* input('#content', 'Hello from iframe')
# Switch back to main page
* switchFrame(null)
# Switch by index
* switchFrame(0)
Dialogs
Handle JavaScript dialogs (alert, confirm, prompt):
Feature: Dialog handling
Scenario: Handle dialogs
* driver 'https://example.com'
* click('#show-alert')
# Get dialog text
* match driver.dialogText == 'Are you sure?'
# Accept dialog
* dialog(true)
# Or cancel
* dialog(false)
# Enter text in prompt and accept
* dialog(true, 'User input')
Cookies
Manage browser cookies:
Feature: Cookie management
Scenario: Cookie operations
* driver 'https://example.com'
# Set cookie
* cookie({ name: 'session', value: 'abc123', domain: '.example.com' })
# Get specific cookie
* def myCookie = cookie('session')
* match myCookie.value == 'abc123'
# Get all cookies
* def allCookies = driver.cookies
# Delete specific cookie
* deleteCookie('session')
# Clear all cookies
* clearCookies()
* match driver.cookies == '#[0]'
Screenshots and Visual Testing
Capturing Screenshots
Take screenshots during tests:
Feature: Screenshots
Scenario: Capture screenshots
* driver 'https://example.com'
# Full page screenshot (auto-embedded in report)
* screenshot()
# Named screenshot
* screenshot('homepage')
# Element screenshot
* screenshot('#main-content')
# Get bytes without auto-embed
* def bytes = screenshot(false)
* def file = karate.write(bytes, 'custom.png')
Full Page Screenshots
Capture the entire scrollable page (Chrome only):
Feature: Full page screenshot
Scenario: Capture scrollable content
* configure driver = { type: 'chrome' }
* driver 'https://example.com/long-page'
* def bytes = driver.screenshotFull()
* karate.write(bytes, 'full-page.png')
PDF Generation
Generate PDF from the current page (Chrome only):
Feature: PDF generation
Scenario: Save page as PDF
* configure driver = { type: 'chrome' }
* driver 'https://example.com/report'
* def pdfBytes = pdf({ orientation: 'landscape' })
* karate.write(pdfBytes, 'report.pdf')
Visual Regression Testing
Compare screenshots against baselines:
Feature: Visual regression
Scenario: Compare with baseline
* driver 'https://example.com'
* def current = screenshot('#product-image', true)
* compareImage { baseline: 'classpath:baselines/product.png', latest: current, failureThreshold: 2 }
See Image Comparison for detailed visual testing options.
Intercepting HTTP Requests
Intercept browser HTTP requests and route them to Karate mock servers. This enables:
- Simulating API failures and edge cases
- Replacing slow backend calls with fast mocks
- Testing without external dependencies
driver.intercept()
Set up request interception (Chrome only). Routes matching URLs to a Karate mock feature:
Feature: HTTP interception
Scenario: Mock API responses
* configure driver = { type: 'chrome' }
# Start with blank page to set up interception before any requests
* driver 'about:blank'
# Intercept any URL matching pattern and route to mock feature
# patterns: array of URL patterns (* = wildcard)
# mock: path to Karate mock feature file
* driver.intercept({ patterns: [{ urlPattern: '*api.example.com/*' }], mock: 'mock-api.feature' })
# Now navigate - requests will be intercepted
* driver 'https://example.com'
* click('#load-data')
# The mock feature returned this response
* waitForText('#result', 'Mocked Response')
Mock Feature Setup
Create a mock feature file to handle intercepted requests. Each Scenario matches different URL patterns:
@ignore
Feature: API mock
Background:
# Enable CORS - browser needs this for cross-origin requests
* configure cors = true
Scenario: pathMatches('/users/{id}')
# pathParams.id contains the {id} from URL, e.g., /users/123 -> id = "123"
* def response = { id: '#(pathParams.id)', name: 'Mock User' }
Scenario: pathMatches('/data')
# Return data from a JSON file
* def response = read('mock-data.json')
Scenario:
# Catch-all for unmatched requests - return 404
* def responseStatus = 404
Inline JS Handler
Instead of a mock feature file, you can use an inline JavaScript function. The handler receives the intercepted request and returns a response map — or null to let the request continue to the network:
Feature: Inline interception
Scenario: Mock with JS handler
* configure driver = { type: 'chrome' }
* driver 'about:blank'
* driver.intercept({ patterns: [{ urlPattern: '*/api/*' }], handler: function(req){ return { status: 200, body: '{"mocked":true}' } } })
* driver 'https://example.com'
* click('#load-data')
* waitForText('#result', 'mocked')
The handler function receives an InterceptRequest object with:
req.url— the full request URLreq.method— HTTP method (GET, POST, etc.)req.headers— request headers as a mapreq.postData— request body (for POST/PUT)
Return a map with status, body, and optionally headers to mock the response. Return null to let the request pass through to the network:
Scenario: Selective interception
* driver.intercept({ patterns: [{ urlPattern: '*' }], handler: function(req){ if (req.url.contains('/api/')) return { status: 200, body: '{}' }; return null } })
driver.intercept()works only withtype: 'chrome'- Call
intercept()once per scenario
Hybrid Tests
Combine API and UI testing in a single flow. Karate's unique strength is seamlessly mixing HTTP API calls with browser automation:
Feature: Hybrid API and UI test
Background:
# Set up API base URL for HTTP calls
* url 'https://api.example.com'
Scenario: Create via API, verify in UI
# STEP 1: Create test data via REST API (faster than UI)
Given path 'orders'
And request { product: 'Widget', quantity: 2, customerId: 123 }
When method post
Then status 201
# Save the order ID from API response
* def orderId = response.id
# STEP 2: Switch to browser and verify the order appears in UI
* configure driver = { type: 'chrome' }
* driver 'https://example.com/orders/' + orderId
* match text('.order-status') == 'Pending'
* match text('.quantity') == '2'
Pre-authenticated Sessions
Skip the login UI by getting auth credentials via API and injecting cookies. This dramatically speeds up tests:
Feature: Skip login with API auth
Background:
# STEP 1: Get auth token via API (no browser needed)
* url 'https://api.example.com'
* path 'auth/login'
* request { username: 'test', password: 'secret' }
* method post
# Save the token from API response
* def authToken = response.token
Scenario: Access protected page directly
* configure driver = { type: 'chrome' }
# STEP 2: Start browser on blank page (needed to set cookies)
* driver 'about:blank'
# STEP 3: Set the auth cookie in the browser
* cookie({ name: 'auth_token', value: authToken, domain: '.example.com' })
# STEP 4: Now navigate to protected page - already logged in!
* driver 'https://example.com/dashboard'
* match text('#welcome') contains 'Welcome'
Pre-authenticating via API can save 5-10 seconds per test by avoiding login UI interactions.
Mobile Testing
Appium integration and native mobile testing are planned for a future Karate v2 release. Device emulation via Chrome CDP works in v2. The Appium documentation below applies to Karate v1.
Device Emulation
Emulate mobile devices in Chrome:
Feature: Mobile emulation
Scenario: iPhone emulation
* configure driver = { type: 'chrome' }
* driver.emulateDevice(375, 812, 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X)')
* driver 'https://example.com'
* waitFor('.mobile-menu').exists
Custom Viewport
Test responsive layouts:
Feature: Responsive testing
Scenario: Test breakpoints
* configure driver = { type: 'chrome' }
* driver 'https://example.com'
# Desktop
* driver.dimensions = { width: 1920, height: 1080 }
* waitFor('.desktop-nav').exists
# Tablet
* driver.dimensions = { width: 768, height: 1024 }
* waitFor('.tablet-menu').exists
# Mobile
* driver.dimensions = { width: 375, height: 667 }
* waitFor('.mobile-hamburger').exists
Appium Integration
Test native mobile apps with Appium:
Feature: Appium mobile test
Scenario: Android app test
* configure driver = { type: 'android', webDriverPath: '/wd/hub' }
* driver { webDriverSession: { desiredCapabilities: { app: 'com.example.myapp' } } }
* click('@login-button')
* input('#username', 'test')
| Locator Prefix | Platform | Description |
|---|---|---|
| (none) | android/ios | Name |
@ | android/ios | Accessibility ID |
# | android/ios | ID |
: | ios | iOS predicate string |
^ | ios | iOS class chain |
- | android | Android UIAutomator |
Screen Recording
Record test execution (Appium only):
Feature: Screen recording
Scenario: Record mobile test
* configure driver = { type: 'android' }
* driver.startRecordingScreen()
# ... test steps ...
* driver.saveRecordingScreen('test-recording.mp4', true)
You can also use driver.stopRecordingScreen() for more control, and both methods accept recording options as JSON input.
hideKeyboard
Dismiss the mobile keyboard (Appium only):
Feature: Hide keyboard
Scenario: Dismiss keyboard after input
* input('#search', 'test query')
* driver.hideKeyboard()
* click('#submit')
Docker and CI
Testcontainers (v2 Recommended)
Karate v2 works with any Chromium Docker image via Testcontainers and the PooledDriverProvider pattern:
public class ContainerDriverProvider extends PooledDriverProvider {
private final ChromeContainer container;
public ContainerDriverProvider(ChromeContainer container) {
super();
this.container = container;
}
@Override
protected Driver createDriver(Map<String, Object> config) {
return CdpDriver.connect(container.getCdpUrl(),
CdpDriverOptions.fromMap(config));
}
}
Recommended Docker images:
chromedp/headless-shell— ~200MB, fast startupselenium/standalone-chrome— includes Chrome + ChromeDriverbrowserless/chrome— Chrome with CDP support
Environment variables for Docker/CI:
export KARATE_CHROME_EXECUTABLE=/usr/bin/chromium
export KARATE_CHROME_ARGS="--no-sandbox --disable-gpu --disable-dev-shm-usage"
export KARATE_DRIVER_HEADLESS=true
For autonomous browser testing via LLM agents, the commercial Karate Agent Docker container (karatelabs/karate-agent) provides Chrome, VNC, and a heredoc-over-HTTP API out of the box.
karate-chrome Container (v1)
Legacy Docker approach — Karate v1 only
Run tests with the v1 Karate Chrome container:
docker run --name karate --rm -p 9222:9222 -p 5900:5900 \
-e KARATE_SOCAT_START=true \
--security-opt seccomp=chrome.json \
karatelabs/karate-chrome
Connect from your test:
Feature: Docker Chrome
Scenario: Connect to container
* configure driver = { type: 'chrome', start: false }
* driver 'https://example.com'
Features of karate-chrome:
- Chrome in full mode (non-headless)
- VNC server on port 5900 (password:
karate) - Video recording saved to
/tmp/karate.mp4 - DevTools Protocol on port 9222
DockerTarget
Configure Docker-based testing in karate-config.js:
function fn() {
var config = {};
if (karate.env == 'ci') {
karate.configure('driverTarget', {
docker: 'karatelabs/karate-chrome',
secComp: 'src/test/resources/chrome.json',
vncPort: 5900
});
}
return config;
}
Custom Target
Implement the Target interface for complex CI requirements:
public class CustomTarget implements Target {
@Override
public Map<String, Object> start(ScenarioRuntime sr) {
// Start browser/container, return driver config
return Map.of("type", "chrome", "start", false);
}
@Override
public Map<String, Object> stop(ScenarioRuntime sr) {
// Cleanup, return video path if recorded
return Map.of("videoFile", "/tmp/test.mp4");
}
}
If the machine running Karate is not the same as the target host (e.g., a sibling Docker container), configure DockerTarget with the remoteHost and/or useDockerHost properties.
See karate-devicefarm-demo for AWS DeviceFarm integration example.
Distributed Testing
For running tests across multiple machines or Docker containers, refer to the Distributed Testing wiki.
Selenium Grid
Connect to Selenium Grid or cloud providers:
Feature: Selenium Grid
Scenario: BrowserStack example
* def session = { capabilities: { browserName: 'chrome', 'bstack:options': { os: 'Windows', osVersion: '11' } } }
* configure driver = { type: 'chromedriver', start: false, webDriverUrl: 'https://user:key@hub.browserstack.com/wd/hub', webDriverSession: '#(session)' }
* driver 'https://example.com'
Debugging
VS Code Extension
The Karate extension for VS Code provides step-through debugging for UI tests. You can pause execution, inspect variables, and even step backwards to re-run steps.
Watch the debugging demo video for a walkthrough.
karate.stop()
Pause test execution to inspect browser state:
Feature: Debug pause
Scenario: Pause for inspection
* driver 'https://example.com'
* input('#username', 'admin')
# Pause here - open localhost:9000 to continue
* karate.stop(9000)
* click('#submit')
When paused, the console shows:
*** waiting for socket, type the command below:
curl http://localhost:9000
Open the URL in a browser or use curl to continue execution.
Always remove karate.stop() calls before committing tests!
highlight()
Visually highlight elements during debugging:
Feature: Visual debugging
Scenario: Highlight elements
* configure driver = { type: 'chrome', highlight: true, highlightDuration: 2000 }
* driver 'https://example.com'
# Manual highlight
* highlight('#important-element')
* delay(2000)
* click('#important-element')
highlightAll()
Highlight all matching elements:
Feature: Highlight all
Scenario: Highlight multiple elements
* driver 'https://example.com'
* highlightAll('input')
* delay(2000)
timeout()
Temporarily change the HTTP read timeout for slow-loading pages:
Feature: Timeout adjustment
Scenario: Wait for slow page
* configure driver = { type: 'chrome' }
# Wait up to 3 minutes for page load
* timeout(3 * 60 * 1000)
* driver 'https://example.com/slow-page'
# Reset to defaults
* timeout()
driver.scriptAwait()
Wait for a JavaScript promise to resolve (Chrome only):
Feature: Await promise
Scenario: Wait for async operation
* configure driver = { type: 'chrome' }
* driver 'https://example.com'
# Wait for accessibility audit to complete
* def result = driver.scriptAwait('axe.run()')
* match result.violations == '#[0]'
Console Logs
Access browser console output:
Feature: Console logs
Scenario: Check for errors
* driver 'https://example.com'
* click('#trigger-action')
* def logs = driver.logs
* match logs !contains 'ERROR'
Code Reuse
Pattern 1: Caller Owns the Driver (Recommended)
The cleanest approach — start the driver in the top-level scenario and call features that perform actions:
Feature: User workflow
Background:
* configure driver = { type: 'chrome' }
* def baseUrl = 'https://example.com'
Scenario: Complete user action
* driver baseUrl + '/login'
* call read('login-steps.feature')
* call read('create-item-steps.feature')
@ignore
Feature: Login steps
Scenario:
* input('#username', 'testuser')
* input('#password', 'secret')
* click('#login-button')
* waitForUrl('/dashboard')
Called features inherit the driver automatically — no driver configuration needed inside them.
Pattern 2: Called Feature Starts the Driver
If the called feature initializes the driver, it automatically propagates back to the caller for shared-scope calls (call read(...) without a result variable). This matches v1 behavior — no special configuration needed:
@ignore
Feature: Login flow
Background:
* configure driver = { type: 'chrome' }
Scenario:
* driver baseUrl + '/login'
* input('#username', username)
* input('#password', password)
* click('#login-button')
* waitForUrl('/dashboard')
Feature: User workflow
Background:
* def baseUrl = 'https://example.com'
* def username = 'testuser'
* def password = 'secret'
* call read('login.feature')
Scenario: Complete user action
* click('#create-new')
* input('#name', 'Test Item')
* click('#save')
Browser instances cannot be shared across scenarios with callonce. Use call in shared scope instead.
JavaScript Function Reuse
When reusing functions defined before driver initialization, use karate.get('driver'):
Feature: Function reuse
Background:
* def deleteAllRows =
"""
function() {
var driver = karate.get('driver');
while (driver.exists('.data-row')) {
driver.click('.delete-button');
karate.pause(500);
}
}
"""
Scenario: Clean up data
* configure driver = { type: 'chrome' }
* driver 'https://example.com/admin'
* deleteAllRows()
Java API
Driver Java API
Start a driver programmatically from Java:
import io.karatelabs.driver.Driver;
import io.karatelabs.driver.cdp.CdpDriver;
// v2 uses CdpDriver or W3cDriver directly
Map<String, Object> config = Map.of("type", "chrome", "headless", true);
// typically use Runner.path().parallel() instead for Gherkin tests
Chrome Java API
Use the CDP driver directly for common tasks like HTML-to-PDF conversion or screenshots:
import io.karatelabs.driver.cdp.CdpDriver;
import io.karatelabs.common.FileUtils;
import java.io.File;
import java.nio.file.Files;
public class ChromeExample {
public static void main(String[] args) throws Exception {
CdpDriver chrome = CdpDriver.startHeadless();
chrome.setUrl("https://example.com");
// Generate PDF
byte[] pdf = chrome.pdf();
Files.write(new File("page.pdf").toPath(), pdf);
// Screenshot
byte[] screenshot = chrome.screenshot();
Files.write(new File("screenshot.png").toPath(), screenshot);
chrome.quit();
}
}
For custom Chrome options, build a CdpDriverOptions and call CdpDriver.start(options).
The pdf() method accepts a Map of options documented in Chrome DevTools Page.printToPDF.
Driver Command Reference
Navigation
| Command | Description |
|---|---|
driver 'url' | Navigate to URL (initializes driver on first call) |
driver.url = 'url' | Navigate to URL |
driver.back() | Go back in history |
driver.forward() | Go forward in history |
driver.refresh() | Reload page (keeps cache) |
reload() | Hard reload (clears cache) |
maximize() | Maximize window |
minimize() | Minimize window |
fullscreen() | Enter fullscreen |
close() | Close current tab/page |
driver.quit() | Close browser |
Element Actions
| Command | Description |
|---|---|
click(locator) | Click element |
input(locator, value) | Type into element |
clear(locator) | Clear input field |
submit() | Submit form (chain before click for page load) |
focus(locator) | Focus element |
scroll(locator) | Scroll element into view |
select(locator, value) | Select dropdown option |
mouse(locator) | Get Mouse instance for advanced actions |
highlight(locator) | Visually highlight element |
highlightAll(locator) | Highlight all matching elements |
Element State
| Command | Description |
|---|---|
text(locator) | Get text content |
html(locator) | Get outer HTML |
value(locator) | Get input value |
value(locator, val) | Set input value |
attribute(locator, name) | Get HTML attribute value |
property(locator, name) | Get DOM property value |
enabled(locator) | Check if enabled |
exists(locator) | Check if exists (boolean) |
optional(locator) | Get element or no-op wrapper |
locate(locator) | Get Element instance |
locateAll(locator) | Get all matching Elements |
locateAll(locator, filter) | Get matching Elements with filter function |
position(locator) | Get absolute element position and size |
position(locator, true) | Get viewport-relative position and size |
Waiting
| Command | Description |
|---|---|
waitFor(locator) | Wait for element to exist |
waitForUrl(partial) | Wait for URL to contain string |
waitForText(locator, text) | Wait for text to appear |
waitForEnabled(locator) | Wait for element to be enabled |
waitForResultCount(locator, n) | Wait for n matching elements |
waitForAny(loc1, loc2, ...) | Wait for any element |
waitUntil(jsExpression) | Wait for JS condition |
retry() | Apply retry to next action |
delay(ms) | Sleep (avoid if possible) |
timeout(ms) | Set HTTP read timeout for slow pages |
Chrome-Only Methods
| Command | Description |
|---|---|
driver.screenshotFull() | Capture entire scrollable page |
driver.scriptAwait(js) | Wait for JS promise to resolve |
driver.inputFile(locator, path) | Upload file to input element |
driver.emulateDevice(w, h, ua) | Emulate mobile device |
driver.intercept(config) | Intercept HTTP requests |
Driver Properties
| Property | Description |
|---|---|
driver.url | Current URL |
driver.title | Page title |
driver.dimensions | Window size (get/set) |
driver.cookies | All cookies |
driver.logs | Browser console logs |
driver.dialogText | Current dialog text |
driver.sessionId | WebDriver session ID |
Next Steps
- Visual testing: Image Comparison
- Mock servers: Test Doubles
- Performance testing: Performance Testing
- Reusable features: Calling Features
- More examples: Examples and Demos