Selenium Plugin
The Webswing Selenium Plugin is a Node.js helper for testing Swing and JavaFX applications rendered by Webswing. Because the application UI is drawn on a canvas, its buttons, fields, and other components are not HTML elements that Selenium can locate with ordinary DOM selectors. The plugin uses the Webswing component tree to locate a desktop component and performs the requested action at its canvas coordinates.
The easiest way to get started is to record a test with the Webswing Test Tool, export the recording as Selenium, and run the generated script. You can then edit the script or use the helper API in your own Selenium tests.
Prerequisites
- a running Webswing server and application;
- Enable Test Mode = ON in the tested application's configuration;
- Node.js and npm;
- Google Chrome or Chromium.
Test Mode exposes the component-tree API used by the plugin. If it is disabled, component lookups and all selector-based actions fail.
Export a recording from Test Tool
- Record and finish a test case in Webswing Test Tool.
- Select Download Test Case in the recording view or file explorer.
- Select the Selenium tab.
- Download
webswing-selenium-plugin.jsfrom the Required helper/plugin section. - Enter the Webswing application URL, login username, login password, and timeout in milliseconds.
- Select Download Selenium to generate the test script.
All export fields are required. The URL must be an absolute http:// or https:// URL, and the timeout must be a positive integer. The generated filename includes the generator name, for example login-test-selenium.js.
The generated script contains the application URL and login credentials as plain text. Store it securely and avoid committing secrets to source control.
The helper is also available in the Test Tool distribution at:
selenium-plugin/webswing-selenium-plugin.js
When Test Tool is deployed, it can be downloaded from:
<test-tool-url>/selenium-plugin/webswing-selenium-plugin.js
Use the helper from the same Webswing version as the Test Tool that generated the test.
Set up the Selenium project
Create a Node.js project and install the dependencies:
mkdir webswing-selenium-test
cd webswing-selenium-test
npm init -y
npm install selenium-webdriver chromedriver
Place the generated script and helper next to each other. The generated script uses a local require('./webswing-selenium-plugin') import.
webswing-selenium-test/
├── node_modules/
├── package.json
├── webswing-selenium-plugin.js
└── generated-test-selenium.js
Run the test with Node.js:
node ./generated-test-selenium.js
For headless Chrome, set HEADLESS to true:
HEADLESS=true node ./generated-test-selenium.js
The generated script creates a Chrome WebDriver, opens the exported Webswing URL, signs in, waits for the Webswing canvas, replays the recording, and closes the driver in a finally block. Before running it, review the URL, credentials, timeout, and Chrome options for your environment.
Recorded web elements use DOM CSS selectors. The generated script calls webswingWebAssertion(driver, selector, actionScript, validationScript, click) to run the action script, require a truthy validation script result, and then perform a recorded click.
Text, parameter, and delay steps inserted in Test Tool are included in the generated script. Parameter values are emitted in the insertParameters object near the beginning of the script, where you can replace their defaults or connect them to your test configuration.
Component selectors
The plugin accepts Webswing's CSS-like component selectors. Prefer stable properties such as component type, name, and value:
JButton[name="saveButton"]
JTextField[name="username"]
JDialog[value="Confirm"] > JButton[value="OK"]
JTable[columnheader="Name"][rownumber="1"]
Selectors should normally identify exactly one component. The generated tests use the selectors stored in the recording. Test Tool automatically tries to save the shortest selector that uniquely identifies the recorded component; if stable attributes are unavailable, it can include parent components and :nth-child(...) positions.
Common attribute operators include =, !=, *=, ^=, and $=. Direct-child (>), descendant (space), adjacent-sibling (+), and general-sibling (~) relationships can be used to disambiguate components.
Avoid coordinates and dimensions in selectors unless necessary, because layout changes can make them unstable.
Use the helper API
Import the helper and pass the Selenium driver as the first argument to every assertion or action:
const { Builder } = require('selenium-webdriver')
const chrome = require('selenium-webdriver/chrome')
const webswing = require('./webswing-selenium-plugin')
async function run() {
const driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(new chrome.Options())
.build()
try {
await driver.get('http://localhost:8080/webswing-demo/')
// Complete login and wait for the Webswing canvas first.
await webswing.webswingShouldExist(driver, 'JButton[name="saveButton"]')
await webswing.webswingClick(driver, 'JButton[name="saveButton"]')
await webswing.webswingType(driver, 'JTextField[name="username"]', 'alice')
await webswing.webswingCheckValue(driver, 'JTextField[name="username"]', 'alice')
} finally {
await driver.quit()
}
}
run().catch(console.error)
All functions are asynchronous and must be awaited.
| Function | Purpose |
|---|---|
webswingGet(driver, selector) |
Returns the raw array of matching component data, including zero or multiple matches. |
webswingWaitFor(driver, selector, timeoutMs = 30000) |
Waits for exactly one match and returns its component data; ambiguous selectors fail. |
webswingSetSelected(driver, selector, selected) |
Sets a checkbox or toggle to the requested boolean state and waits for that state. |
webswingShouldExist(driver, selector) |
Requires exactly one matching component. |
webswingShouldExistCount(driver, selector, count) |
Requires exactly the specified number of matches. |
webswingShouldNotExist(driver, selector) |
Requires zero matching components. |
webswingShouldVisible(driver, selector) |
Requires exactly one match with effective visible area. |
webswingShouldNotVisible(driver, selector) |
Requires exactly one match with no effective visible area. |
webswingCheckValue(driver, selector, value) |
Requires exactly one match whose value equals the expected value. |
webswingClick(driver, selector) |
Clicks the center of the visible part of one matched component. |
webswingMove(driver, selector, moveX, moveY) |
Performs a move/drag from the component by the specified pixel offsets. |
webswingType(driver, selector, text) |
Focuses the component, moves the caret to the end, and types text or Selenium key values. |
webswingClearInput(driver, selector) |
Focuses the component and clears its current value with keyboard input. |
setWebswingInstanceName(name) |
Changes the global Webswing instance name used by the helper. |
The helper performs a fresh component query for each call. Use webswingWaitFor when a component appears asynchronously, or webswingGet when inspecting raw state or match counts. Await queries sequentially: a Webswing browser instance has one pending query response at a time. A lookup error fails immediately rather than being treated as a missing component.
State queries do not require a rendered canvas, so they also work in a linked view with suspended rendering. Actions require a visible component and its own rendered window canvas. Coordinates account for the window's backend origin, clipping, and canvas scaling; the helper does not click an unrelated first canvas.
The default Webswing instance name is webswingInstance0. Change it before the first lookup when the tested page exposes a different instance:
webswing.setWebswingInstanceName('myWebswingInstance')
Existence and visibility
Existence and visibility are intentionally different. A component can exist in the Swing component tree and have visible: true, but be completely clipped by a JScrollPane or JViewport. Visibility assertions use the effective on-screen geometry returned by Webswing:
- visible:
visibleWidth > 0andvisibleHeight > 0; - not visible: the component exists, but has no effective visible area;
- not existing: the selector matches no component.
For example, a component with visible: true and visibleHeight: 0 exists but is not visible to the user.
Troubleshooting
requestComponentTreeElement is not available: enable Test Mode for the application and reload it.- Webswing instance is not available: wait for the application to initialize, or configure the correct instance name with
setWebswingInstanceName. - Expected one match but found zero or multiple components: inspect the recorded selector and add stable attributes or parent context.
- The component exists but an action fails: ensure it has effective visible area and is not clipped or outside the canvas.
- Login or canvas timeout: verify the exported URL and credentials, and increase the positive timeout value when application startup is slow.
- Helper import fails: keep
webswing-selenium-plugin.jsnext to the generated test, or update therequire(...)path.