Skip to main content

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.

On this page:

Why Karate for UI Testing?

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:

Gherkin
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.

Driver Lifecycle
  • The browser launches on the first driver keyword
  • The browser closes automatically when the scenario ends
  • Use driver.quit() only if you need explicit cleanup mid-scenario

Driver Configuration

Configuration Options

Configure browser behavior with the configure driver statement:

Gherkin
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'
KeyDescriptionDefault
typeBrowser type (see Driver Types)-
executablePath to browser or driver executableAuto-detected
startWhether Karate should start the executabletrue
stopWhether to close browser after scenario (set false for debugging)true
portPort for driver communicationVaries by type
hostHost for driver communicationlocalhost
headlessRun without visible browser window (Chrome only)false
timeoutPage load timeout in milliseconds30000
pollAttemptsNumber of attempts to wait for port to be ready20
pollIntervalMilliseconds between poll attempts250
showDriverLogInclude WebDriver HTTP traffic in reportfalse
showProcessLogInclude executable/driver logs in reportfalse
showBrowserLogInclude browser console logs in reporttrue
addOptionsAdditional CLI arguments as arraynull
beforeStartOS command to run before scenario (e.g., start video recording)null
afterStopOS command to run after scenario (e.g., stop video recording)null
videoFilePath to video file to embed in HTML reportnull
httpConfigHTTP client config for remote WebDriver, e.g., { readTimeout: 120000 }null
attachURL pattern to attach to existing Chrome session (type: chrome, start: false)null
userDataDirPath to Chrome user data directory (pass null to use system defaults)Auto-created
highlightHighlight elements before actions (for demos/debugging)false
highlightDurationDuration to highlight elements in milliseconds3000
screenshotOnFailureAuto-capture screenshot on test failuretrue

Headless Mode

Run tests without a visible browser window. Ideal for CI/CD pipelines where no display is available:

Gherkin
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:

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):

Gherkin
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:

Gherkin
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 certificates
  • moz: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:

Gherkin
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:

TypePortDescription
chrome9222Native Chrome via DevTools Protocol. Recommended for development.
playwright4444Playwright integration for cross-browser testing.
msedge9222Microsoft Edge (Chromium) via DevTools Protocol.
chromedriver9515W3C Chrome WebDriver.
geckodriver4444W3C Firefox WebDriver.
safaridriver5555W3C Safari WebDriver (macOS only).
msedgedriver9515W3C Microsoft Edge WebDriver.
mswebdriver17556Microsoft Edge Legacy WebDriver (deprecated).
iedriver5555Internet Explorer 11 WebDriver (deprecated).
android4723Android automation via Appium.
ios4723iOS automation via Appium.
winappdriver4727Windows desktop application automation.
Driver Selection

Start with type: 'chrome' for development—it's fastest and requires no additional setup. Switch to WebDriver types for cross-browser testing or CI environments.

Playwright Integration

Playwright provides cross-browser support with Chromium, Firefox, and WebKit engines.

Setup

Add the Playwright dependency before karate-core:

pom.xml
<dependency>
<groupId>io.karate</groupId>
<artifactId>karate-playwright</artifactId>
<scope>test</scope>
</dependency>

Basic Usage

Gherkin
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:

Gherkin
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'
OptionDescriptionDefault
browserTypechromium, firefox, or webkitchromium
channelBrowser channel (e.g., chrome, msedge)chrome
contextPlaywright browser context options-
installBrowsersAuto-download browsers on first runtrue

For connecting to a remote Playwright server, use playwrightUrl:

Gherkin
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):

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:

Gherkin
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.

Proxy Configuration

For Chrome, use addOptions:

Gherkin
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:

Gherkin
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:

Gherkin
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 /):

Gherkin
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:

LocatorDescription
{a}Click MeFirst <a> with exact text "Click Me"
{}Click MeFirst element (any tag) with exact text "Click Me"
{^}ClickFirst element containing text "Click"
{^span}ClickFirst <span> containing text "Click"
{div:2}Click MeSecond <div> with exact text "Click Me"
{span/a}Click MeFirst <a> inside <span> with exact text "Click Me"
Gherkin
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 Benefits

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:

MethodFinds 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)
Gherkin
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():

Gherkin
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:

PropertyReturns
parentParent element
childrenArray of child elements
firstChildFirst child element
lastChildLast child element
previousSiblingPrevious sibling element
nextSiblingNext sibling element
Gherkin
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:

locators.json
{
"login": {
"username": "#username",
"password": "#password",
"submit": "[data-testid='login-btn']"
},
"dashboard": {
"welcome": "{}Welcome",
"logout": "{a}Logout"
}
}
Gherkin
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
Alternative to Page Objects

This pattern provides the benefits of centralized locators without the complexity of traditional Page Object Models.

Element Interactions

Click and Input

Basic element interactions for filling forms and clicking buttons:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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):

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
Feature: Scrolling

Scenario: Scroll to element
* driver 'https://example.com'
* scroll('#footer')
# Chain with click
* scroll('#hidden-button').click()

Waiting Strategies

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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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()

Configure retry behavior for subsequent actions. Unlike waitFor(), retry() re-attempts the action itself:

Gherkin
Feature: Retry configuration

Scenario: Custom retry settings
* driver 'https://example.com'
# retry() with no args: use default (3 attempts, 3 second intervals)
* retry().click('#slow-button')
# retry(count): custom number of attempts
* retry(5).click('#very-slow-button')
# retry(count, interval): custom attempts AND wait time between them
* retry(5, 10000).click('#extremely-slow-button')

Default retry settings: 3 attempts with 3000ms intervals. Configure globally in karate-config.js:

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:

Gherkin
Feature: Method chaining

Scenario: Fluent chains
* driver 'https://example.com'
# Wait then click
* waitFor('#button').click()
# Retry with wait
* retry(5, 10000).waitForEnabled('#submit').click()
# Scroll then input
* scroll('#hidden-field').input('value')
# Mouse chain
* mouse('#menu').move()
* waitFor('.submenu').exists

Browser JavaScript

script()

Execute JavaScript in the browser:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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:

Gherkin
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

Control browser navigation:

Gherkin
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:

Gherkin
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:

Gherkin
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):

Gherkin
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:

Gherkin
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:

Gherkin
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):

Gherkin
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):

Gherkin
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:

Gherkin
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:

Gherkin
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:

mock-api.feature
@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

Inspecting Intercepted Requests

Access request data from the mock:

Gherkin
Feature: Inspect requests

Scenario: Verify intercepted requests
* configure driver = { type: 'chrome' }
* driver 'about:blank'
* def mock = driver.intercept({ patterns: [{ urlPattern: '*/api/*' }], mock: 'tracking-mock.feature' })
* driver 'https://example.com'
* click('#submit')
* delay(1000)
# Get saved requests from mock
* def requests = mock.get('savedRequests')
* match requests[0].path == '/api/submit'
Interception Limitations
  • driver.intercept() works only with type: 'chrome'
  • Playwright supports urlPatterns only
  • Call intercept() once per scenario (one mock feature, multiple routes)

Hybrid Tests

Combine API and UI testing in a single flow. Karate's unique strength is seamlessly mixing HTTP API calls with browser automation:

Gherkin
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:

Gherkin
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'
Performance Benefit

Pre-authenticating via API can save 5-10 seconds per test by avoiding login UI interactions.

Mobile Testing

Device Emulation

Emulate mobile devices in Chrome:

Gherkin
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:

Gherkin
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:

Gherkin
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 PrefixPlatformDescription
(none)android/iosName
@android/iosAccessibility ID
#android/iosID
:iosiOS predicate string
^iosiOS class chain
-androidAndroid UIAutomator

Screen Recording

Record test execution (Appium only):

Gherkin
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):

Gherkin
Feature: Hide keyboard

Scenario: Dismiss keyboard after input
* input('#search', 'test query')
* driver.hideKeyboard()
* click('#submit')

Docker and CI

karate-chrome Container

Run tests with the official 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:

Gherkin
Feature: Docker Chrome

Scenario: Connect to container
* configure driver = { type: 'chrome', start: false, showDriverLog: true }
* 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
VNC Debugging

Connect to localhost:5900 with a VNC client to watch tests run in real-time. On Mac: open vnc://localhost:5900

For more Docker options, see the Docker wiki.

DockerTarget

Configure Docker-based testing in karate-config.js:

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:

CustomTarget.java
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:

Gherkin
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:

Gherkin
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.

Remember to Remove

Always remove karate.stop() calls before committing tests!

highlight()

Visually highlight elements during debugging:

Gherkin
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:

Gherkin
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:

Gherkin
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):

Gherkin
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:

Gherkin
Feature: Console logs

Scenario: Check for errors
* driver 'https://example.com'
* click('#trigger-action')
* def logs = driver.logs
* match logs !contains 'ERROR'

Code Reuse

Shared Features

Create reusable feature files for common flows:

login.feature
@ignore
Feature: Login flow

Scenario:
* configure driver = { type: 'chrome' }
* driver baseUrl + '/login'
* input('#username', username)
* input('#password', password)
* click('#login-button')
* waitForUrl('/dashboard')
main-test.feature
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')
callonce Not Supported

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'):

Gherkin
Feature: Function reuse

Background:
* def deleteAllRows =
"""
function() {
var driver = karate.get('driver');
while (driver.exists('.data-row')) {
driver.click('.delete-button');
java.lang.Thread.sleep(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:

DriverExample.java
import com.intuit.karate.driver.Driver;

Driver driver = Driver.start("chrome");
driver.setUrl("https://example.com");
driver.click("button");
driver.waitForText("#result", "Success");
driver.quit();

Chrome Java API

Use Chrome directly for common tasks like HTML-to-PDF conversion or full-page screenshots:

ChromeExample.java
import com.intuit.karate.FileUtils;
import com.intuit.karate.driver.chrome.Chrome;
import java.io.File;
import java.util.Collections;

public class ChromeExample {
public static void main(String[] args) {
Chrome chrome = Chrome.startHeadless();
chrome.setLocation("https://example.com");

// Generate PDF
byte[] pdf = chrome.pdf(Collections.EMPTY_MAP);
FileUtils.writeToFile(new File("page.pdf"), pdf);

// Screenshot (visible viewport)
byte[] screenshot = chrome.screenshot();
FileUtils.writeToFile(new File("screenshot.png"), screenshot);

// Full page screenshot (entire scrollable area)
byte[] fullPage = chrome.screenshotFull();
FileUtils.writeToFile(new File("fullpage.png"), fullPage);

chrome.quit();
}
}

For custom Chrome options:

Map<String, Object> options = new HashMap<>();
options.put("executable", "/path/to/chrome");
options.put("headless", true);
options.put("maxPayloadSize", 8388608); // 8MB for large outputs
options.put("useFrameAggregation", true); // Enable if server sends multiple frames
Chrome chrome = Chrome.start(options);

The pdf() method accepts a Map of options documented in Chrome DevTools Page.printToPDF.

Driver Command Reference

CommandDescription
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

CommandDescription
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

CommandDescription
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

CommandDescription
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

CommandDescription
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

PropertyDescription
driver.urlCurrent URL
driver.titlePage title
driver.dimensionsWindow size (get/set)
driver.cookiesAll cookies
driver.logsBrowser console logs
driver.dialogTextCurrent dialog text
driver.sessionIdWebDriver session ID

Next Steps

On This Page