Robot Framework Java GUI Library
Automate Java desktop apps — Swing, SWT, and Eclipse RCP — straight from Robot Framework. A Rust + PyO3 core does the heavy lifting so you write plain, readable test cases with inline assertions. Real widgets, real clicks, real screenshots. No brittle pixel-matching, no vendor lock-in.
The Swiss Army knife for Java GUI testing: one library, three toolkits, human-readable tests.
📖 Keyword Documentation — every keyword, with a runnable example: Swing · SWT · Eclipse RCP
Features
- High Performance: Core library written in Rust with PyO3 bindings for Python
- Multi-Toolkit Support: Java Swing, SWT, and Eclipse RCP — see the maturity table below for the support level of each
- Inline Assertions: Browser Library-style assertions with automatic retry (via
robotframework-assertion-engine) - CSS-like Selectors: Intuitive element locators similar to web testing
- XPath Support: XPath-style locator syntax for complex queries
- Comprehensive Component Support: Buttons, text fields, tables, trees, lists, menus, and more
- Java Agent: Non-invasive instrumentation via Java agent
- Cross-Platform: Designed for Windows, macOS, and Linux
Toolkit Support & Maturity
The three toolkits are not at the same level of maturity. Support level reflects how thoroughly each is verified against real applications:
| Toolkit | Import | Keywords | Maturity | Notes |
|---|---|---|---|---|
| Swing | JavaGui.Swing |
~108 | Stable | Fully implemented and exercised end-to-end against real Swing apps. Recommended for production use. |
| SWT | JavaGui.Swt |
~71 | Stable | Fully implemented and exercised end-to-end against a real SWT app (widgets, shells, tables, trees, text, selection). |
| Eclipse RCP | JavaGui.Rcp |
~75 | Beta — validated on real Eclipse & DBeaver | Introspection (workbench, perspectives, views, editors) plus actions (show/close view, open perspective, execute command) run against a live Eclipse workbench — and are proven headless against DBeaver Community Edition, a real public RCP product, in the Docker harness under tests/docker/rcp. State-changing actions run on the SWT UI thread; generic widget keywords (Find Widget, Input Text, Check Button, type: locators) reach the workbench window. Needs a running Eclipse RCP app; not usable against non-Eclipse targets. |
Note: Keyword counts include deprecated aliases retained for backward compatibility. RCP targets applications built on the Eclipse Rich Client Platform — validate against your specific app before production. Want proof it works on a real product? Run
docker build -t rcp-dbeaver-harness tests/docker/rcp && docker run --rm -v "$PWD":/work rcp-dbeaver-harnessand read the embedded screenshots inresults/dbeaver/log.html.
Table of Contents
- 📖 Keyword Documentation (GitHub Pages)
- 🔎 Spy Tool — javagui-spy
- Installation
- Quick Start
- Attach to a Running Application
- Libraries
- Locator Syntax
- Assertion Engine
- Keywords Reference
- Examples
- Architecture
- Development
- Troubleshooting
- License
Installation
Prerequisites
- Python 3.8 or higher
- Java 11 or higher (for running Java applications)
- Rust toolchain (for building from source)
- Maven (for building the Java agent)
Install from PyPI
# Install the library with pip
pip install robotframework-javagui
# Or install with uv (recommended)
uv pip install robotframework-javagui
Install from Source
# Clone the repository
git clone https://github.com/manykarim/robotframework-javaui.git
cd robotframework-javaui
# Install with uv (recommended)
uv pip install -e .
# Or install with pip
pip install -e .
Dependencies
The library automatically installs these dependencies:
| Package | Version | Purpose |
|---|---|---|
robotframework |
>=4.0 | Test automation framework |
robotframework-assertion-engine |
>=3.0.0 | Inline assertions with retry |
docutils |
>=0.20.1 | Documentation generation |
Build the Java Agent
The Java agent is required for instrumenting Java applications:
cd agent
mvn package
This creates agent/target/javagui-agent.jar.
Build the Demo Application (Optional)
A demo Swing application is included for testing:
cd demo
mvn package
Quick Start
1. Start Your Java Application with the Agent
# For Swing applications
java -javaagent:path/to/javagui-agent.jar=port=5678 -jar your-swing-app.jar
# For SWT applications
java -javaagent:path/to/javagui-agent.jar=port=5678 -jar your-swt-app.jar
# For Eclipse RCP applications
eclipse -vmargs -javaagent:path/to/javagui-agent.jar=port=5678
2. Create a Robot Framework Test
*** Settings ***
Library JavaGui.Swing # For Swing applications
# Library JavaGui.Swt # For SWT applications
# Library JavaGui.Rcp # For Eclipse RCP applications
*** Test Cases ***
Example Login Test
Connect To Application main_class=com.example.MyApp host=localhost port=5678
Input Text [name='username'] admin
Input Text [name='password'] secret
Click JButton[text='Login']
# Using inline assertion with retry
Get Text JLabel[name='status'] == Welcome
[Teardown] Disconnect
3. Run the Test
robot my_test.robot
Attach to a Running Application
Connect To Application needs the target started with -javaagent:javagui-agent.jar=port=…. Sometimes you cannot do that — the app is already running, someone else launched it, or it comes up through a launcher (Java Web Start) that will not let you add JVM args. Attach To Application handles those cases: it finds the target JVM, loads the agent at runtime through the JDK Attach API, and connects — no -javaagent on the command line.
*** Settings ***
Library JavaGui.Swing
*** Test Cases ***
Automate An Already-Running Swing App
Attach To Application main_class=testapp.SwingTestApp
Click JButton[text='OK']
[Teardown] Disconnect
You point it at exactly one JVM. Selection is unambiguous or it errors — if 0 or >1 processes match, the keyword raises with the candidate list instead of guessing.
| Argument | Selects by |
|---|---|
pid |
Process ID — the most explicit. |
main_class |
Regex matched against the target's main class / entry jar / command line. |
title |
Window-title pattern (* wildcards; needs wmctrl). |
Not sure what is running? List Applications returns the discovered JVMs so you can pick one:
${apps}= List Applications
Log ${apps}
Attach To Application pid=${apps}[0][pid]
Each entry is a dict with pid, main_class, command_line, display_name, is_launcher, and markers. Launchers (javaws, an IDE bootstrap, etc.) are filtered out by default; pass include_launchers=True to see them too.
SWT and Eclipse RCP work the same way — the toolkit just defaults differently:
*** Settings ***
Library JavaGui.Swt
*** Test Cases ***
Attach To A Running SWT App
Attach To Application main_class=MySwtApp toolkit=auto
Click Button[text='Save']
[Teardown] Disconnect
toolkit=auto detects Swing vs SWT from the classes loaded in the target, so it is a safe default when you are not sure. List Applications and Attach To Application are available on JavaGui.Swing, JavaGui.Swt, and JavaGui.Rcp (SWT/RCP default toolkit=swt; Swing defaults toolkit=swing).
When to use it vs Connect To Application
| Use | When |
|---|---|
Connect To Application |
You launch the app yourself and can add -javaagent:…. Lowest overhead, works on any JVM. |
Attach To Application |
The app is already running, you cannot relaunch it, or it starts via Java Web Start. |
Requirements
- A JDK on the machine running the tests. Runtime attach uses the JDK Attach API (
jdk.attach). A plain JRE has no attach support — install a JDK, or provide ajattachbinary (setJAVAGUI_JATTACH, or put it onPATH). - Same-user access to the target. The OS only lets you attach to JVMs owned by your user.
- JDK 21+ prints a one-line "dynamic agent loading" warning on the target — harmless. JDK 24+ additionally requires the target to be launched with
-XX:+EnableDynamicAgentLoading; that flag is set at the target's launch, not by the test.
Java Web Start (JNLP)
Web Start apps are started by javaws (OpenWebStart, IcedTea-Web), which builds the JVM command line itself. You cannot add -javaagent at launch — it is not on the JNLP secure vm-args whitelist, so the launcher strips it. Runtime attach is the way in. Launch Web Start Application starts the .jnlp, finds the application JVM (whether it runs in-process in the launcher or in a forked child), attaches the agent, and connects:
*** Settings ***
Library JavaGui.Swing
*** Test Cases ***
Automate A Web Start App
Launch Web Start Application https://example.com/app.jnlp toolkit=auto
Click JButton[text='Start']
[Teardown] Disconnect
Point launcher= at a specific javaws binary or an IcedTea-Web image directory (or set JAVAGUI_JAVAWS); omit it to use javaws on PATH. settle (default 8s) controls how long to wait for the app JVM to appear before attaching.
What works, and what does not:
| Target | Runtime attach |
|---|---|
Plain running app (java -jar app.jar, no -javaagent) |
✅ Works |
| JNLP under modern OpenWebStart / JDK 24+ | ✅ Works |
JNLP under IcedTea-Web (legacy SecurityManager) |
❌ Blocked |
The IcedTea-Web block is structural, not a permissions setting: ITW installs a JNLPSecurityManager that cannot classify the foreign code an attach-loaded agent brings in, so it denies the agent's initialization. This is independent of the app's permission level — an all-permissions, signed JNLP is blocked exactly the same way. When this happens, Launch Web Start Application raises a clear AttachError naming the SecurityManager, rather than hanging. Use a launcher without the legacy SecurityManager (OpenWebStart, or a JDK 24+ javaws) for Web Start automation.
See docs/runtime-attach.md for the injection model, the full JDK/launcher matrix, troubleshooting, and the javagui-spy --attach-pid flags.
Spy Tool — javagui-spy
Point it at a running Swing/SWT/RCP app and it hands you unique, verified Robot Framework locators — no guessing, no sleep-and-hope. Every candidate is checked through the same matcher your tests run, so a suggested locator cannot fail to parse in a suite. A UI is coming; the agentic CLI is here today.
It ships in the wheel: pip install robotframework-javagui gives you the javagui-spy command. Attach to a live app on its agent port, or --launch app.jar to start one under the bundled agent.
The five-call workflow:
javagui-spy dump-tree --visible-only # 1. orient
javagui-spy find "text:Save" # 2. shortlist
javagui-spy suggest --node-id 7 # 3. ranked verified locators
javagui-spy validate "JButton[name='save']" # 4. exit 0 = unique, done
javagui-spy screenshot -o proof.png # 5. visual confirmation
suggest returns ranked candidates plus ready-to-paste rf_snippets (Click JButton[name='toolbarNewButton']). Deep, nameless widgets get nearest-stable-ancestor >> chains; --strip-names simulates off-the-shelf apps with no names. Connection flags (--host, --port, --toolkit, --timeout) sit on every verb.
Also: a web inspector (javagui-spy ui — click a widget on a live screenshot, get ranked verified locators with a live match-count bar), click-to-pick (pick --at X,Y, in-JVM hit-test), highlight, and an MCP server (javagui-spy mcp) exposing the same verbs as tools.
Libraries
This package provides three libraries for different Java GUI frameworks:
| Library | Import | Use Case |
|---|---|---|
| Swing | Library JavaGui.Swing |
Java Swing applications (JButton, JTable, etc.) |
| Swt | Library JavaGui.Swt |
SWT applications (Eclipse widgets) |
| Rcp | Library JavaGui.Rcp |
Eclipse RCP applications (views, editors, perspectives) |
Full keyword reference (GitHub Pages): every keyword, with a runnable example —
Swing ·
SWT ·
Eclipse RCP.
Hosted from docs/keywords/ — regenerate with uv run invoke docs.
Library Import Options
*** Settings ***
# Basic import
Library JavaGui.Swing
# With options
Library JavaGui.Swing timeout=30 screenshot_dir=screenshots
# Multiple libraries (if needed)
Library JavaGui.Swing WITH NAME Swing
Library JavaGui.Rcp WITH NAME Rcp
Locator Syntax
The library supports multiple locator strategies for finding UI elements.
CSS-like Selectors
| Selector | Description | Example |
|---|---|---|
Type |
Match by component type | JButton |
[attr='value'] |
Exact attribute match | [name='loginBtn'] |
[attr*='value'] |
Attribute contains | [text*='Submit'] |
[attr^='value'] |
Attribute starts with | [name^='btn_'] |
[attr$='value'] |
Attribute ends with | [text$='...'] |
Type[attr='value'] |
Type with attribute | JButton[name='ok'] |
Parent > Child |
Direct child | JPanel > JButton |
Ancestor Descendant |
Descendant | JFrame JButton |
:enabled |
Enabled elements | JButton:enabled |
:visible |
Visible elements | JLabel:visible |
:first-child |
First child | JButton:first-child |
:nth-child(n) |
Nth child | JButton:nth-child(2) |
XPath-style Selectors
| Selector | Description | Example |
|---|---|---|
//Type |
Any descendant | //JButton |
//Type[@attr='value'] |
With attribute | //JButton[@name='ok'] |
//Type[n] |
By index (1-based) | //JButton[1] |
Combined Selectors
# Multiple attributes
JButton[name='submit'][text='OK']:enabled
# Nested with pseudo-selectors
JPanel[name='form'] JTextField:visible
# XPath with multiple predicates
//JTable[@name='data']//JButton[@text='Edit']
Assertion Engine
This library integrates robotframework-assertion-engine (v3.0.0+) to provide inline assertions with automatic retry, following the Browser Library pattern. This enables more concise and readable tests.
Basic Usage
Get keywords can optionally perform assertions with automatic retry:
*** Test Cases ***
Example With Assertions
# Without assertion - returns value
${text}= Get Text JLabel[name='status']
# With assertion - asserts with automatic retry (5s default)
Get Text JLabel[name='status'] == Ready
# With custom timeout
Get Text JLabel[name='status'] == Ready timeout=10
# With custom message
Get Text JLabel[name='status'] == Ready message=Status not ready
Assertion Operators
| Operator | Aliases | Description | Example |
|---|---|---|---|
== |
equal, equals, should be |
Exact equality | Get Text loc == Hello |
!= |
inequal, should not be |
Not equal | Get Text loc != Error |
< |
less than |
Less than (numeric) | Get Element Count JButton < 10 |
> |
greater than |
Greater than (numeric) | Get Table Row Count loc > 0 |
<= |
Less or equal | Get Element Count loc <= 5 |
|
>= |
Greater or equal | Get Table Row Count loc >= 1 |
|
*= |
contains |
Contains substring/item | Get Text loc contains success |
^= |
starts |
Starts with | Get Text loc starts Hello |
$= |
ends |
Ends with | Get Text loc ends world |
matches |
Regex match | Get Text loc matches \\d{3}-\\d{4} |
|
validate |
Custom expression | Get Text loc validate len(value) > 5 |
|
then |
Return value only (no assert) | ${v}= Get Text loc then |
Formatters
Apply text transformations before assertion:
*** Test Cases ***
Using Formatters
# Normalize spaces and strip whitespace
Get Text JLabel[name='title'] == Hello World formatters=['normalize_spaces', 'strip']
# Case-insensitive comparison
Get Text JLabel[name='status'] == ready formatters=['lowercase']
| Formatter | Description |
|---|---|
normalize_spaces |
Collapse multiple whitespace to single space |
strip |
Remove leading/trailing whitespace |
lowercase |
Convert to lowercase |
uppercase |
Convert to uppercase |
Element States
The Get Element States keyword returns element states that can be asserted:
*** Test Cases ***
Assert Element States
# Check element is visible and enabled
Get Element States JButton[name='submit'] contains enabled
Get Element States JButton[name='submit'] contains visible
# Check multiple states
${states}= Get Element States JButton[name='submit']
Should Contain ${states} enabled
Should Contain ${states} visible
Available States: visible, hidden, enabled, disabled, focused, unfocused, selected, unselected, checked, unchecked, editable, readonly, expanded, collapsed, attached, detached
Configuration
Configure assertion behavior globally or per-keyword:
*** Test Cases ***
Configure Assertions
# Set default timeout for all assertions
Set Assertion Timeout 10
# Set retry interval
Set Assertion Interval 0.2
# Override per keyword call
Get Text JLabel[name='status'] == Ready timeout=30
Validate Operator (Custom Expressions)
The validate operator allows custom Python expressions:
*** Test Cases ***
Custom Validation
# Validate with custom expression (value is the retrieved value)
Get Text JLabel[name='count'] validate int(value) > 10
Get Text JLabel[name='email'] validate '@' in value and '.' in value
Get Element Count JButton validate value % 2 == 0 # Even number
Security Note: The validate operator uses a secure expression evaluator that blocks dangerous operations like eval, exec, file access, and attribute manipulation.
Keywords Reference
Swing Keywords
Assertion-Enabled Get Keywords
These keywords support inline assertions with automatic retry:
| Keyword | Arguments | Description |
|---|---|---|
Get Text |
locator, assertion_operator=, expected=, message=, timeout=, formatters= |
Get element text with optional assertion |
Get Value |
locator, assertion_operator=, expected=, message=, timeout= |
Get input field value with optional assertion |
Get Element Count |
locator, assertion_operator=, expected=, message=, timeout= |
Count matching elements with optional numeric assertion |
Get Element States |
locator, assertion_operator=, expected=, message=, timeout= |
Get element states (visible, enabled, etc.) with optional assertion |
Get Property |
locator, property_name, assertion_operator=, expected=, message=, timeout= |
Get element property with optional assertion |
Get Properties |
locator, assertion_operator=, expected=, message= |
Get dict of common properties |
Table Keywords with Assertions
| Keyword | Arguments | Description |
|---|---|---|
Get Table Cell Value |
locator, row, column, assertion_operator=, expected=, message=, timeout= |
Get cell value with optional assertion |
Get Table Row Count |
locator, assertion_operator=, expected=, message=, timeout= |
Get row count with optional numeric assertion |
Get Table Column Count |
locator, assertion_operator=, expected=, message=, timeout= |
Get column count with optional numeric assertion |
Get Table Row Values |
locator, row, assertion_operator=, expected=, message= |
Get all values from a row |
Get Table Column Values |
locator, column, assertion_operator=, expected=, message= |
Get all values from a column |
Tree Keywords with Assertions
| Keyword | Arguments | Description |
|---|---|---|
Get Tree Node Count |
locator, path, assertion_operator=, expected=, message=, timeout= |
Get child node count with optional assertion |
Get Tree Node Children |
locator, path, assertion_operator=, expected=, message=, timeout= |
Get child nodes with optional assertion |
List Keywords with Assertions
| Keyword | Arguments | Description |
|---|---|---|
Get List Items |
locator, assertion_operator=, expected=, message= |
Get list items with optional assertion |
Get List Item Count |
locator, assertion_operator=, expected=, message=, timeout= |
Get item count with optional numeric assertion |
Configuration Keywords
| Keyword | Arguments | Description |
|---|---|---|
Set Assertion Timeout |
timeout |
Set default assertion retry timeout (seconds) |
Set Assertion Interval |
interval |
Set retry interval between attempts (seconds) |
SWT Keywords
Assertion-Enabled Get Keywords
| Keyword | Arguments | Description |
|---|---|---|
Get Widget Text |
locator, assertion_operator=, expected=, message=, timeout= |
Get SWT widget text with optional assertion |
Get Widget Count |
locator, assertion_operator=, expected=, message=, timeout= |
Count SWT widgets with optional assertion |
Get Widget Property |
locator, property_name, assertion_operator=, expected=, message=, timeout= |
Get SWT property with optional assertion |
Is Widget Enabled |
locator, assertion_operator=, expected=, message=, timeout= |
Check widget enabled state |
SWT Table Keywords with Assertions
| Keyword | Arguments | Description |
|---|---|---|
Get SWT Table Cell Value |
locator, row, column, assertion_operator=, expected=, message=, timeout= |
Get SWT table cell value |
Get SWT Table Row Count |
locator, assertion_operator=, expected=, message=, timeout= |
Get SWT table row count |
Get SWT Table Column Count |
locator, assertion_operator=, expected=, message=, timeout= |
Get SWT table column count |
SWT Tree Keywords with Assertions
| Keyword | Arguments | Description |
|---|---|---|
Get SWT Tree Node Count |
locator, path, assertion_operator=, expected=, message=, timeout= |
Get SWT tree node count |
Get SWT Tree Node Children |
locator, path, assertion_operator=, expected=, message=, timeout= |
Get SWT tree node children |
SWT Configuration Keywords
| Keyword | Arguments | Description |
|---|---|---|
Set SWT Assertion Timeout |
timeout |
Set SWT assertion retry timeout |
Set SWT Assertion Interval |
interval |
Set SWT retry interval |
RCP Keywords
Assertion-Enabled RCP Keywords
| Keyword | Arguments | Description |
|---|---|---|
Get Open View Count |
assertion_operator=, expected=, message=, timeout= |
Get count of open views with optional assertion |
Get Open Editor Count |
assertion_operator=, expected=, message=, timeout= |
Get count of open editors with optional assertion |
Get Active Perspective Id |
assertion_operator=, expected=, message=, timeout= |
Get active perspective ID with optional assertion |
Get Editor Dirty State |
title, assertion_operator=, expected=, message=, timeout= |
Check if editor has unsaved changes |
Common Keywords (All Libraries)
Connection Keywords
| Keyword | Arguments | Description |
|---|---|---|
Connect To Application |
main_class=, title=, host=, port=, timeout= |
Connect to an app launched with -javaagent |
Attach To Application |
pid=, main_class=, title=, host=, port=, toolkit=, timeout= |
Inject the agent into an already-running JVM and connect (no -javaagent needed) — see Attach to a Running Application |
List Applications |
include_launchers= |
List discovered Java processes you can attach to |
Launch Web Start Application |
jnlp, launcher=, host=, port=, toolkit=, settle=, timeout= |
Launch a JNLP app, attach at runtime, and connect |
Disconnect |
Disconnect from the application | |
Is Connected |
Returns connection status |
Element Finding
| Keyword | Arguments | Description |
|---|---|---|
Find Element |
locator |
Find single element |
Find Elements |
locator |
Find all matching elements |
Element Should Exist |
locator |
Assert element exists |
Element Should Not Exist |
locator |
Assert element doesn't exist |
Mouse Actions
| Keyword | Arguments | Description |
|---|---|---|
Click |
locator |
Single click |
Double Click |
locator |
Double click |
Right Click |
locator |
Context menu click |
Click Button |
locator |
Click a button |
Text Input
| Keyword | Arguments | Description |
|---|---|---|
Input Text |
locator, text, clear=True |
Enter text (optionally clear first) |
Type Text |
locator, text |
Type text character by character |
Clear Text |
locator |
Clear text field |
Get Element Text |
locator |
Get element's text content |
Table Operations
| Keyword | Arguments | Description |
|---|---|---|
Get Table Row Count |
locator |
Get number of rows |
Get Table Column Count |
locator |
Get number of columns |
Get Table Cell Value |
locator, row, column |
Get cell value |
Get Table Data |
locator |
Get all table data as list |
Select Table Cell |
locator, row, column |
Select a cell |
Select Table Row |
locator, row |
Select a row |
Tree Operations
| Keyword | Arguments | Description |
|---|---|---|
Expand Tree Node |
locator, path |
Expand a tree node |
Collapse Tree Node |
locator, path |
Collapse a tree node |
Select Tree Node |
locator, path |
Select a tree node |
Get Tree Nodes |
locator |
Get all tree nodes |
List Operations
| Keyword | Arguments | Description |
|---|---|---|
Get List Items |
locator |
Get all list items |
Select From List |
locator, value |
Select item by value |
Select List Item By Index |
locator, index |
Select item by index |
Form Controls
| Keyword | Arguments | Description |
|---|---|---|
Select From Combobox |
locator, value |
Select dropdown value |
Check Checkbox |
locator |
Check a checkbox |
Uncheck Checkbox |
locator |
Uncheck a checkbox |
Select Radio Button |
locator |
Select radio button |
Select Tab |
locator, tab_name |
Select tab in tabbed pane |
Verification
| Keyword | Arguments | Description |
|---|---|---|
Element Should Be Visible |
locator |
Assert element is visible |
Element Should Be Enabled |
locator |
Assert element is enabled |
Element Should Be Selected |
locator |
Assert element is selected |
Element Text Should Be |
locator, expected |
Assert exact text match |
Element Text Should Contain |
locator, expected |
Assert text contains |
Wait Operations
| Keyword | Arguments | Description |
|---|---|---|
Wait For Element |
locator, timeout= |
Wait for element to exist |
Wait Until Element Visible |
locator, timeout= |
Wait for visibility |
Wait Until Element Enabled |
locator, timeout= |
Wait for enabled state |
Wait Until Element Contains |
locator, text, timeout= |
Wait for text content |
UI Tree Inspection
The library provides powerful component tree inspection with advanced filtering capabilities:
| Keyword | Arguments | Description |
|---|---|---|
Get Component Tree |
locator=, format=text, max_depth=, types=, exclude_types=, visible_only=False, enabled_only=False, focusable_only=False |
Get component hierarchy with depth control, type filtering, and state filtering. Supports multiple output formats: text, json, xml, yaml, csv, markdown |
Get Component Subtree |
locator, format=text, max_depth=, types=, exclude_types=, visible_only=, enabled_only=, focusable_only= |
Get subtree starting from specific component (faster for large UIs) |
Log Component Tree |
locator=, format=text, level=INFO |
Log component tree to Robot Framework log |
Refresh Component Tree |
Refresh cached component tree | |
Get Ui Tree |
format=text |
(Legacy) Get component hierarchy - use Get Component Tree instead |
Log Ui Tree |
(Legacy) Log UI tree - use Log Component Tree instead | |
Refresh Ui Tree |
(Legacy) Refresh tree - use Refresh Component Tree instead |
Component Tree Features:
- 6 Output Formats:
text(default),json,xml,yaml,csv,markdown - Type Filtering: Include/exclude by component type with wildcard support (
J*Button,JText*) - State Filtering: Filter by visible, enabled, or focusable state
- Depth Control: Limit tree depth for performance (recommended for large UIs)
- Performance: 50x faster subtree retrieval vs. full tree on large applications
Quick Examples:
# Get tree with multiple formats
${text}= Get Component Tree format=text
${json}= Get Component Tree format=json max_depth=5
${xml}= Get Component Tree format=xml
# Advanced filtering
${buttons}= Get Component Tree types=J*Button visible_only=${True}
${inputs}= Get Component Tree types=JButton,JTextField enabled_only=${True}
${tree}= Get Component Tree exclude_types=JLabel,JPanel max_depth=10
# Subtree for performance
${form}= Get Component Subtree JPanel[name='loginForm'] format=json
See Component Tree Documentation for complete guide.
Screenshots
| Keyword | Arguments | Description |
|---|---|---|
Capture Screenshot |
filename= |
Capture window screenshot |
Set Screenshot Directory |
directory |
Set output directory |
Properties
| Keyword | Arguments | Description |
|---|---|---|
Get Element Property |
locator, property |
Get specific property |
Get Element Properties |
locator |
Get all properties |
Examples
Swing Examples
Login Test with Assertions
*** Settings ***
Documentation Login functionality test suite with assertion engine
Library JavaGui.Swing
Library Process
Suite Setup Start Application
Suite Teardown Stop Application
*** Variables ***
${APP_JAR} path/to/myapp.jar
${AGENT_JAR} path/to/javagui-agent.jar
${PORT} 5678
*** Keywords ***
Start Application
${cmd}= Set Variable java -javaagent:${AGENT_JAR}=port=${PORT} -jar ${APP_JAR}
Start Process ${cmd} shell=True alias=app
Sleep 3s
Connect To Application main_class=com.example.MyApp port=${PORT}
Stop Application
Disconnect
Terminate Process app kill=True
*** Test Cases ***
Valid Login Should Succeed
[Documentation] Test login with inline assertions
Input Text JTextField[name='username'] admin
Input Text JPasswordField[name='password'] password123
Click JButton[text='Login']
# Inline assertion with automatic retry
Get Text JLabel[name='status'] == Welcome, admin! timeout=5
Invalid Login Should Show Error
[Documentation] Test error handling with assertions
Input Text [name='username'] invalid
Input Text [name='password'] wrong
Click JButton[text='Login']
# Assert text contains with retry
Get Text JLabel[name='status'] contains Invalid credentials
Verify Button States
[Documentation] Test element states with assertions
# Check submit button is enabled
Get Element States JButton[name='submit'] contains enabled
# Check login form is visible
Get Element States JPanel[name='loginForm'] contains visible
Table Operations with Assertions
*** Test Cases ***
Verify Table Data With Assertions
[Documentation] Table verification using assertion engine
# Assert minimum row count
Get Table Row Count JTable[name='dataTable'] >= 5
# Assert cell values with retry
Get Table Cell Value JTable[name='dataTable'] 0 1 == John Doe
Get Table Cell Value JTable[name='dataTable'] 0 2 contains @example.com
# Assert column count
Get Table Column Count JTable[name='dataTable'] == 5
Process Table Rows With Validation
[Documentation] Iterate and validate table rows
# First verify we have data
Get Table Row Count JTable[name='users'] > 0
# Get row values and validate
${row}= Get Table Row Values JTable[name='users'] 0
Should Not Be Empty ${row}
Tree Navigation with Assertions
*** Test Cases ***
Navigate And Validate Tree
[Documentation] Tree operations with assertion engine
# Expand and verify node count
Expand Tree Node JTree[name='fileTree'] Root
Get Tree Node Count JTree[name='fileTree'] Root > 0
# Verify children exist
Get Tree Node Children JTree[name='fileTree'] Root contains Documents
SWT Examples
SWT Application Testing
*** Settings ***
Documentation SWT application test suite
Library JavaGui.Swt
Suite Setup Connect To SWT Application
Suite Teardown Disconnect
*** Keywords ***
Connect To SWT Application
Connect To Application main_class=com.example.SwtApp port=5678
*** Test Cases ***
Verify SWT Widget Text
[Documentation] Test SWT text retrieval with assertions
# Assert label text
Get Widget Text Label[name='status'] == Ready
# Assert with formatters
Get Widget Text Label[name='title'] == application name formatters=['lowercase', 'strip']
# Assert text contains
Get Widget Text Text[name='description'] contains Welcome
Verify SWT Widget States
[Documentation] Test SWT widget states
# Check widget is enabled
Is Widget Enabled Button[name='submit'] == ${True}
# Get widget count
Get Widget Count Button > 5
SWT Table Verification
[Documentation] SWT table testing with assertions
# Assert table has data
Get SWT Table Row Count Table[name='data'] >= 1
# Assert cell value
Get SWT Table Cell Value Table[name='data'] 0 0 == First Row
SWT Tree Navigation
[Documentation] SWT tree testing
# Verify tree has children
Get SWT Tree Node Count Tree[name='nav'] Root > 0
# Verify specific children exist
Get SWT Tree Node Children Tree[name='nav'] Root contains Settings
SWT Property Assertions
[Documentation] Assert widget properties
# Check specific property
Get Widget Property Button[name='submit'] enabled == true
Get Widget Property Text[name='input'] editable == true
RCP Examples
Eclipse RCP Application Testing
*** Settings ***
Documentation Eclipse RCP application test suite
Library JavaGui.Rcp
Suite Setup Connect To RCP Application
Suite Teardown Disconnect
*** Keywords ***
Connect To RCP Application
# Start Eclipse with agent
# eclipse -vmargs -javaagent:path/to/agent.jar=port=5678
Connect To Application main_class=org.eclipse.ui.PlatformUI port=5678
*** Test Cases ***
Verify Perspective
[Documentation] Test RCP perspective with assertions
# Assert active perspective
Get Active Perspective Id == org.eclipse.ui.resourcePerspective
# Or use contains for partial match
Get Active Perspective Id contains resource
Verify Open Views
[Documentation] Test RCP views with assertions
# Assert at least one view is open
Get Open View Count >= 1
# Assert specific number of views
Get Open View Count == 3 message=Expected 3 views to be open
Verify Open Editors
[Documentation] Test RCP editors with assertions
# Assert editors are open
Get Open Editor Count > 0
# After opening specific file
Get Open Editor Count == 2
Test Editor Dirty State
[Documentation] Test unsaved changes detection
# Verify editor has no unsaved changes
Get Editor Dirty State MyFile.java == ${False}
# After making changes
Input Text StyledText[name='editor'] // new code
Get Editor Dirty State MyFile.java == ${True}
Complete RCP Workflow
[Documentation] Full RCP workflow with assertions
# Verify starting state
Get Active Perspective Id contains Java
# Open a view and verify count increases
${initial_views}= Get Open View Count
Click JMenuItem[text='Show View']
Click JMenuItem[text='Console']
Get Open View Count > ${initial_views}
# Open editor and verify
Double Click TreeItem[text='MyProject/src/Main.java']
Get Open Editor Count >= 1
Get Editor Dirty State Main.java == ${False}
Advanced Examples
Using Formatters
*** Test Cases ***
Text Formatting Examples
[Documentation] Using formatters for flexible assertions
# Normalize whitespace before comparison
Get Text JLabel[name='formatted'] == Hello World formatters=['normalize_spaces']
# Case-insensitive comparison
Get Text JLabel[name='status'] == success formatters=['lowercase']
# Chain multiple formatters
Get Text JLabel[name='message'] == hello formatters=['strip', 'lowercase']
Custom Validation
*** Test Cases ***
Custom Validation Examples
[Documentation] Using validate operator for complex assertions
# Validate numeric range
Get Text JLabel[name='count'] validate 10 <= int(value) <= 100
# Validate email format
Get Text JTextField[name='email'] validate '@' in value and '.' in value
# Validate string length
Get Text JTextField[name='code'] validate len(value) == 6
# Validate with regex
Get Text JLabel[name='phone'] matches ^\\d{3}-\\d{3}-\\d{4}$
Handling Dynamic Content
*** Test Cases ***
Dynamic Content With Assertions
[Documentation] Handle async updates with assertion retry
Click JButton[name='loadData']
# Assertions auto-retry until timeout
Get Element States JLabel[name='loading'] contains hidden timeout=10
Get Table Row Count JTable[name='results'] > 0 timeout=10
Get Text JLabel[name='status'] == Data loaded timeout=15
Architecture
robotframework-javagui/
├── python/ # Python package
│ └── JavaGui/ # Robot Framework library
│ ├── __init__.py # Library exports (Swing, Swt, Rcp)
│ ├── assertions/ # Assertion engine integration
│ │ ├── __init__.py # Retry wrappers, ElementState
│ │ ├── formatters.py # Text formatters
│ │ └── security.py # Secure expression evaluator
│ └── keywords/ # Keyword implementations
│ ├── getters.py # Swing Get* keywords
│ ├── tables.py # Swing Table/Tree/List keywords
│ ├── swt_getters.py # SWT Get* keywords
│ ├── swt_tables.py # SWT Table keywords
│ ├── swt_trees.py # SWT Tree keywords
│ └── rcp_keywords.py # RCP-specific keywords
├── src/ # Rust source code
│ ├── lib.rs # PyO3 bindings
│ ├── locator/ # Locator parsing (pest grammar)
│ ├── connection/ # RPC client
│ └── element/ # Element operations
├── agent/ # Java agent
│ └── src/ # Agent source
├── demo/ # Demo Swing application
└── tests/ # Test suites
└── robot/ # Robot Framework tests
How It Works
- Java Agent: Attaches to the JVM and provides RPC endpoints for UI inspection and control
- Rust Core: High-performance element matching, locator parsing, and RPC communication
- Python Bindings: PyO3-based interface exposing Robot Framework keywords
- Assertion Engine: Integration with
robotframework-assertion-enginefor inline assertions with retry - Robot Framework: Test execution and reporting
Assertion Flow
Get Text keyword called with assertion operator
↓
Retry wrapper starts (default 5s timeout, 0.1s interval)
↓
Get value from Java agent via Rust core
↓
Apply formatters (if specified)
↓
AssertionEngine.verify_assertion() checks condition
↓
Pass: Return value | Fail: Retry until timeout
Development
Building from Source
# Install development dependencies
uv pip install -e ".[dev]"
# Build Rust extension
maturin develop
# Build Java agent
cd agent && mvn package
# Build demo app
cd demo && mvn package
Running Tests
# Run Robot Framework tests
uv run robot tests/robot/
# Run Python unit tests
uv run pytest tests/python/
# Run specific test suite
uv run robot tests/robot/02_locators.robot
Project Structure
| Directory | Description |
|---|---|
python/ |
Python Robot Framework library |
src/ |
Rust core library |
agent/ |
Java instrumentation agent |
demo/ |
Demo Swing application |
tests/robot/ |
Robot Framework test suites |
tests/python/ |
Python unit tests |
docs/ |
Documentation |
schemas/ |
JSON/YAML schemas |
Configuration
Agent Configuration
The Java agent accepts these JVM arguments:
java -javaagent:swing-agent.jar=port=5678,debug=true -jar app.jar
| Option | Default | Description |
|---|---|---|
port |
5678 | RPC server port |
debug |
false | Enable debug logging |
Library Configuration
*** Settings ***
# Swing library with options
Library JavaGui.Swing timeout=30 screenshot_dir=screenshots
# SWT library
Library JavaGui.Swt timeout=30
# RCP library
Library JavaGui.Rcp timeout=30
| Option | Default | Description |
|---|---|---|
timeout |
10 | Default wait timeout (seconds) |
screenshot_dir |
. | Screenshot output directory |
Assertion Configuration
Configure assertion behavior in your test:
*** Test Cases ***
Configure Assertion Defaults
# Set default assertion retry timeout (seconds)
Set Assertion Timeout 10
# Set retry interval between attempts (seconds)
Set Assertion Interval 0.2
# For SWT library
Set SWT Assertion Timeout 10
Set SWT Assertion Interval 0.2
| Setting | Default | Description |
|---|---|---|
| Assertion Timeout | 5.0 | How long to retry assertion before failing |
| Assertion Interval | 0.1 | Time between retry attempts |
Timeout Priority (highest to lowest):
- Keyword argument:
Get Text loc == value timeout=30 - Library configuration:
Set Assertion Timeout 10 - Global default: 5.0 seconds
Troubleshooting
Connection Issues
SwingConnectionError: Connection refused
- Ensure the application is running with the agent loaded
- Verify the port matches between agent and library
- Check firewall settings
Element Not Found
ElementNotFoundError: Element not found: JButton[name='xyz']
- Use
Log Ui Treeto inspect available elements - Verify element names and attributes
- Check if element is visible/enabled
EDT Threading Errors
SwingConnectionError: EDT callable failed
- Some operations require visible components
- Use wait keywords before interacting
- Ensure proper tab/window focus
Assertion Timeout Errors
AssertionError: Get Text: Timeout 5.0s exceeded
- Increase timeout:
Get Text loc == value timeout=30 - Check if element exists and has the expected value
- Use
Log Ui Treeto verify element state - Consider if the value changes dynamically (use longer timeout)
Assertion Value Mismatch
AssertionError: Get Text: 'Actual Value' should be 'Expected Value'
- Check for whitespace issues - use
formatters=['strip', 'normalize_spaces'] - Check for case sensitivity - use
formatters=['lowercase'] - Verify the expected value matches exactly (or use
containsoperator)
Validate Expression Errors
SecurityError: Expression contains blocked operation
- The
validateoperator blocks dangerous operations for security - Only use allowed builtins:
len,int,str,bool,float, etc. - Avoid:
eval,exec,open,__import__, attribute access like__class__
SWT/RCP Specific Issues
SWTException: Widget is disposed
- The widget was destroyed before the operation completed
- Add wait for the widget to be ready
- Check if a dialog or view was closed unexpectedly
WorkbenchException: View not found
- Verify the view ID is correct
- Ensure the perspective allows the view
- Check if the view is available in the current product
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
License
Apache License 2.0. See LICENSE for details.
Acknowledgments
- Robot Framework - Test automation framework
- robotframework-assertion-engine - Inline assertion library
- Browser Library - Inspiration for inline assertion pattern
- PyO3 - Rust bindings for Python
- pest - Parser library for Rust
Metadata
Release files for robotframework-javagui 0.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| robotframework_javagui-0.8.0-cp38-abi3-win_amd64.whl | CPython 3.8 | abi3 | Windows x86-64 | Details |
| robotframework_javagui-0.8.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.8 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| robotframework_javagui-0.8.0-cp38-abi3-macosx_11_0_arm64.whl | CPython 3.8 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 5.6 MB
Release files / robotframework_javagui-0.8.0-cp38-abi3-win_amd64.whl
| Download URL | robotframework_javagui-0.8.0-cp38-abi3-win_amd64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | CPython 3.8 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
9b2e3360d03f201ddd50125d9d75f3d68899cbae85cb9cfc71710afcf84d3d8c
|
|
BLAKE2b-256 checksum How to use checksums |
0e0c4f5bbf2508af1350e26e6beb5680eb4008b8c24abac9ff4f54c40186a19d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|
Release files / robotframework_javagui-0.8.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | robotframework_javagui-0.8.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | CPython 3.8 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
f8a24240535123b0ab5e91636716a12e72f49df88fc02e23fe772aad718f7bc7
|
|
BLAKE2b-256 checksum How to use checksums |
a6f2298fe8b5577ac032c3d71511471e354afbdf0efb4ded844220d2d16e52a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|
Release files / robotframework_javagui-0.8.0-cp38-abi3-macosx_11_0_arm64.whl
| Download URL | robotframework_javagui-0.8.0-cp38-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.8 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c45d8e56df5c1b3d4ff999d05ab9a04f542f4eace251028cac44ab6b4e10dcdd
|
|
BLAKE2b-256 checksum How to use checksums |
e9d40b46a1c0a9acde0050e7b759fc7c69304aae834794bd47f5bc3630e4877f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|