Small files. Repeatable checks.

UI testing with
the .bru DSL.

Describe a browser flow in a few readable lines. Bruster runs the actions, waits for your assertions, and captures evidence when a test fails.

A testing language built around browser actions.

A domain-specific language, or DSL, gives you a small vocabulary for one job. In a .bru file, commands such as navigate, fill, click, and expect describe a UI check. Run the file with bruster test.

Less test plumbing

The runner handles browser startup, JSON-lines request/response matching, deadlines, and shutdown. No Node.js, Python, or separate test framework is needed to execute the tests.

Useful failure evidence

Failures identify the file and line. The runner attempts a screenshot, DOM snapshot, and console capture, and records test results in JSON.

Will it save time?

It can reduce the time spent writing and debugging repeated smoke tests: setup is reusable, assertions wait for the UI, and diagnostics are automatic. Browser execution still uses the same native webview. Each test starts a fresh browser and profile for isolation, which has a startup cost.

The DSL is available in source builds from main. Older release binaries may not include bruster test yet. See the installation and source-build instructions.

For a hands-on walkthrough, read the web automation testing tutorial, try the interactive form demo, and run the website and component example tests.

Starting without programming experience? Learn website testing in twenty small lessons, from a manual test plan to your first automated project.

Run your first UI test.

From a source checkout with Bruster’s build dependencies installed, build the executable:

Build from source
cargo build --release --locked

Start the included greeting page in one terminal. This example uses Python only to serve the HTML:

Terminal 1 · demo server
python3 -m http.server 8000 --directory examples/testing

In another terminal, run the example suite:

Terminal 2 · run tests
target/release/bruster test examples/testing/greeting.bru

On Windows, use target\release\bruster.exe. Linux needs WebKitGTK and a display or Xvfb. Add --visible to watch the browser.

The example suite greets a visitor and checks that the next test starts with an empty greeting:

greeting.bru
base_url "http://127.0.0.1:8000"
timeout 5000

before_each
  navigate "/"
end

test "greets a visitor"
  fill "#name" "Ada"
  click "button"
  expect text "#result" "Hello, Ada!"
  screenshot "greeting.png"
end

test "starts with an empty greeting"
  expect title "Greeting demo"
  expect visible "#name"
  expect text "#result" ""
end

Readable syntax. Reusable setup.

Common actions cover clicking, filling, typing, key presses, selecting options, checking boxes, uploading a file, taking screenshots, and browser history. eval "JavaScript" executes application-specific setup once. Uploaded file paths are relative to the .bru file; screenshot paths are relative to the test’s artifact directory.

Run multiple files in order, and override their base URL for a different environment:

bruster test login.bru checkout.bru --base-url https://staging.example.com
bruster test tests/*.bru --timeout 15000 --viewport 1280x800
bruster test --help

The shell expands *.bru. Pass individual files when your shell does not expand globs. The runner validates all input files before starting a browser.

Wait for the result you care about.

Assertions retry observations until the step deadline, including while an element is still appearing. The default deadline is five seconds; set timeout in the file or --timeout on the command line.

expect visible "#dashboard"
expect hidden "#loading"
expect attached "#email"
expect text "h1" "Dashboard"
expect contains "#notice" "Saved"
expect title "My account"
expect url "/dashboard"
expect url_contains "/dashboard"
expect count ".result" 3
expect attr "#save" "aria-label" "Save changes"
expect js "document.querySelector('#terms').checked === true"

expect text compares exact, whitespace-normalized element text. expect contains checks a substring. expect js requires the boolean true; keep its expression side-effect free because it may execute several times.

Actions execute once using Bruster’s existing actionability checks. A failure stops that test and the runner continues with the next one. Entire tests are not automatically retried.

Reports and evidence for CI.

Start your application server before the suite. Run tests with an explicit artifact parent directory:

CI command
bruster test login.bru checkout.bru --output artifacts/ui

Each invocation creates a unique run directory and prints its location. Retain that directory as a CI artifact:

Each test owns a fresh browser process and profile, isolating cookies, storage, and page state. Startup, requests, shutdown, and failure capture all have deadlines.

Test runner exit codes
Exit codeMeaning
0Every test passed.
1A test or browser failed.
2Invalid input, or report setup/write failure.

A focused tool for native-webview tests.

The DSL fits smoke tests and straightforward flows such as forms, login, navigation, and asynchronous page updates. Bruster uses WKWebView on macOS, WebKitGTK on Linux, and WebView2 on Windows.

Input is synthetic. CSS :hover, native OS controls, and cross-origin iframe interaction are outside its current capabilities. The runner is sequential and has a small grammar; loops and general-purpose control flow are available through your own client around the JSON-lines API. Screenshots are evidence, with no built-in visual-diff assertions.

For selectable browser engines, tracing, parallel test orchestration, and a broader testing ecosystem, compare Bruster and Playwright. See the browser limitations and complete DSL command reference before choosing a test strategy.