Karate UI — Browser Automation Basics

8 min read

Karate's UI module lets you drive a browser from the same .feature file as your API tests. No Selenium, no WebDriver server to start manually, no separate test framework. The same Given/When/Then syntax that sends HTTP requests can also click buttons, fill in forms, and assert on page content. This lesson is an introduction to Karate UI's capabilities and, equally important, to when you should use it and when you should reach for a dedicated UI tool instead.

The driver keyword — opening a browser

To start a browser and navigate to a URL:

Given driver 'https://myapp.com/login'

Karate launches a Chrome instance using the WebDriver protocol (or Chrome DevTools Protocol, depending on configuration). The driver keyword replaces a url + method get pair — it's the entry point for browser sessions.

By default Karate uses Chrome in headed mode locally. For CI, add a driver configuration in karate-config.js:

// karate-config.js
function fn() {
    var config = { baseUrl: 'https://api.myapp.com' };
 
    if (karate.env == 'ci') {
        karate.configure('driver', { type: 'chrome', headless: true });
    }
 
    return config;
}

Core UI actions

Karate UI provides a set of built-in step keywords for the most common browser interactions:

# Type text into an element
And input('#email', 'alice@test.com')
And input('#password', 'password123')
 
# Click a button or link
And click("button[type='submit']")
And click('.nav-link[href="/logout"]')
 
# Select from a dropdown
And select('#role-dropdown', 'Admin')
 
# Wait for an element to appear
And waitFor('#dashboard-header')
 
# Wait for URL to change
And waitForUrl('/dashboard')
 
# Assert on visible text
And match text('#welcome-message') contains 'Welcome, Alice'
 
# Assert on the page title
And match driver.title contains 'Dashboard'
 
# Take a screenshot (useful for debugging)
And screenshot()

Selectors are CSS selectors — the same format used in Playwright and Cypress. If you've written UI tests with either of those tools, the selector syntax is immediately familiar.

A complete browser login flow

Feature: Login UI — Smoke Check
 
Scenario: Admin can log in and reach the dashboard
  Given driver webAppUrl + '/login'
  And input('#email', 'admin@test.com')
  And input('#password', 'AdminPass1')
  When click("button[type='submit']")
  Then waitForUrl('/dashboard')
  And match driver.title contains 'Dashboard'
  And waitFor('.user-menu')
  And match text('.user-menu') contains 'Alice'

webAppUrl comes from karate-config.js — the same pattern as baseUrl for the API. The scenario is readable: open the login page, type credentials, click submit, wait for the dashboard, assert the title and a welcome element.

Combining API and UI in one scenario

The most distinctive Karate UI capability: API and browser steps in the same scenario, sharing variables:

Scenario: API creates a user, UI confirms they appear in the admin panel
  # API step — create the user
  Given url baseUrl
  And path 'users'
  And request { name: 'Alice Smith', email: 'alice@test.com', role: 'admin' }
  When method post
  Then status 201
  * def userId = response.id
 
  # UI step — verify the user appears in the admin panel
  Given driver webAppUrl + '/admin/users'
  And waitFor("[data-testid='user-row-" + userId + "']")
  Then match text("[data-testid='user-row-" + userId + "']") contains 'Alice Smith'

userId from the API response is used directly in the browser selector. No test framework bridge, no shared state mechanism — it's one variable in one scenario.

This pattern is useful for end-to-end verification: the API creates data, the UI confirms it renders correctly. It exercises the full stack from write to read to display.

When to use Karate UI vs dedicated UI tools

Karate UI vs dedicated browser automation frameworks

Karate UI

  • Same .feature file as API tests

    Mix API calls and browser steps — share variables between them

  • Zero extra framework setup

    If you already have Karate, browser automation is one config line

  • Good for: smoke checks, UI verification after API writes

    Login smoke, user appears in admin, dashboard loads

  • Not ideal for: deep UI coverage, complex interactions

    No component testing, no visual regression, limited assertion set

Playwright / Cypress

  • Purpose-built for browser testing

    Network mocking, auto-wait, component isolation, visual diffs

  • Richer selector and assertion model

    getByRole, getByText, toBeVisible, toHaveText, screenshots on failure

  • Better tooling for large UI suites

    Trace viewer, video recording, parallel workers, test sharding

  • Good for: comprehensive UI testing, full regression suites

    The right tool when UI coverage is a first-class requirement

Use Karate UI when the team is already on Karate and needs a handful of browser smoke checks alongside API tests. Use Playwright or Cypress when UI testing is a significant part of the test strategy — they have deeper tooling, better debugging, and a richer assertion model for complex interactions.

Karate UI is a bonus, not a replacement. It exists because some test scenarios naturally span both API and UI, and it handles those elegantly without requiring a separate framework.

⚠️ Common mistakes

  • Using Karate UI as the primary UI testing tool for a large application. For 5 browser smoke checks, Karate UI is convenient. For 200 end-to-end UI scenarios, you'll hit its limits: no visual diff, no network interception, limited debugging tools compared to Playwright's trace viewer or Cypress's time-travel debugger. Choose the right tool for the scale.
  • Not setting headless: true in CI. Karate UI opens a real browser window by default. CI runners (GitHub Actions, Jenkins) don't have a display — running headed Chrome in CI fails immediately. Always add karate.configure('driver', { type: 'chrome', headless: true }) in the ci environment branch of karate-config.js.
  • Sharing the browser session across scenarios. Karate UI creates a new browser session per scenario by default. If Scenario 1 logs in and sets a session cookie, Scenario 2 starts fresh — it's not logged in. This is the correct and safe behaviour. If you need a persistent session, use Background to open the browser and log in before each scenario, or investigate Karate's configure(driver) session options for advanced cases.

🎯 Practice task

Write a browser smoke check and combine it with an API call. 35–45 minutes.

  1. Add * def webAppUrl = 'https://the-internet.herokuapp.com' to karate-config.js (a free public demo site for UI testing practice).
  2. Write a scenario: Given driver webAppUrl + '/login'. Type admin into #username and admin into #password. Click button[type='submit']. Assert waitForUrl('/secure') and match driver.title contains 'The Internet'. Run it. This is your first Karate UI test.
  3. Add And screenshot() after the assertion. Open the screenshot file from the console output path. Confirm it shows the logged-in page.
  4. Write a scenario on https://the-internet.herokuapp.com/dropdown. Select option 'Option 2' using select('#dropdown', 'Option 2'). Assert text('#dropdown option:checked') == 'Option 2'.
  5. Write a combined scenario: GET https://jsonplaceholder.typicode.com/users/1 (API call), extract response.name into def userName. Then open driver webAppUrl + '/login' and add a comment showing where you would assert userName appears in a UI element — proving the variable is available in the browser step.
  6. Add karate.configure('driver', { type: 'chrome', headless: true }) to karate-config.js under a ci environment branch. Run with -Dkarate.env=ci. Confirm the browser runs without a visible window (no Chrome opens on your desktop).
  7. Stretch: read the Karate UI documentation and find three actions you haven't used yet — scroll, focus, or value. Write a short scenario that demonstrates each one against the Herokuapp demo pages.

Next chapter: reporting and CI/CD — reading the HTML report in detail, integrating with Cucumber reports, and running Karate in GitHub Actions.

// tip to track lessons you complete and pick up where you left off across devices.