Cypress Plugin
The Webswing Cypress Plugin registers custom Cypress commands for testing Swing and JavaFX applications rendered by Webswing. Because the application UI is drawn on a canvas, its desktop components are not HTML elements that Cypress can locate with ordinary DOM queries. The plugin queries the Webswing component tree, resolves a desktop component, and performs actions at its canvas coordinates.
The easiest way to get started is to record a test with the Webswing Test Tool, export the recording as a Cypress spec, and run it in a Cypress project. You can then edit the generated spec or use the commands in your own tests.
Prerequisites
- a running Webswing server and application;
- Enable Test Mode = ON in the tested application's configuration;
- Node.js and npm;
- Cypress and a Cypress-supported browser, typically Chrome or Chromium.
Test Mode exposes the component-tree API used by the plugin. If it is disabled, component lookups and all selector-based commands 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 Cypress tab.
- Download
webswing-cypress-plugin.jsfrom the Required helper/plugin section. - Enter the Webswing application URL, login username, login password, and timeout in milliseconds.
- Select Download Cypress to generate the test spec.
Recorded web elements use DOM CSS selectors. The generated spec calls cy.webswingWebAssertion(selector, actionScript, validationScript, click) to run the action script, require a truthy validation script result, and then perform a recorded click.
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-cypress.spec.js.
The generated spec 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:
cypress-plugin/webswing-cypress-plugin.js
When Test Tool is deployed, it can be downloaded from:
<test-tool-url>/cypress-plugin/webswing-cypress-plugin.js
Use the helper from the same Webswing version as the Test Tool that generated the spec.
Set up the Cypress project
Create a project and install Cypress:
mkdir webswing-cypress-test
cd webswing-cypress-test
npm init -y
npm install cypress --save-dev
Use the following structure:
webswing-cypress-test/
├── cypress/
│ ├── e2e/
│ │ └── generated-test-cypress.spec.js
│ └── support/
│ ├── e2e.js
│ └── webswing-cypress-plugin.js
├── cypress.config.js
├── node_modules/
└── package.json
Import the helper from the Cypress support file so its commands are registered before a spec runs:
// cypress/support/e2e.js
import './webswing-cypress-plugin'
Configure the support file and set baseUrl to the Webswing Admin Console URL used by cy.webswingLogin(...):
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:8080/admin',
supportFile: 'cypress/support/e2e.js'
}
})
Place the generated spec in cypress/e2e/. It does not import the helper directly.
Open Cypress interactively:
npx cypress open
Or run the E2E tests from the command line:
npx cypress run --browser chrome
The generated spec signs in with cy.webswingLogin(...), visits the exported Webswing application URL, waits for the configured startup timeout, and replays the recording. Review the URL, credentials, timeout, and Cypress configuration before running it.
Text, parameter, and delay steps inserted in Test Tool are included in the generated spec. Parameter values are emitted in the insertParameters object in the test, where you can replace their defaults or connect them to Cypress environment 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 used for actions and single-component assertions must identify exactly one component. The generated specs 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 custom commands
Start a lookup with cy.webswingGet(selector), then chain an assertion or action:
describe('Webswing form', () => {
beforeEach(() => {
cy.webswingLogin('admin', 'pwd')
cy.visit('http://localhost:8080/webswing-demo/')
})
it('enters and verifies a value', () => {
cy.webswingGet('JTextField[name="username"]')
.webswingShouldVisible()
.webswingType('alice')
cy.webswingGet('JTextField[name="username"]')
.webswingCheckValue('alice')
cy.webswingGet('JButton[name="saveButton"]')
.webswingClick()
})
})
| Command | Purpose |
|---|---|
cy.webswingLogin(username, password) |
Creates a cached Cypress login session through the Webswing Admin Console. |
cy.setWebswingInstanceName(name) |
Changes the global Webswing instance name used by subsequent lookups. |
cy.webswingGet(selector) |
Queries the component tree and creates the subject required by the commands below. |
cy.webswingWaitFor(selector, timeoutMs = 30000) |
Waits for exactly one match and creates the same chainable subject; ambiguous selectors fail. |
.webswingShouldExist() |
Requires exactly one matching component. |
.webswingShouldExistCount(count) |
Requires exactly the specified number of matches. |
.webswingShouldNotExist() |
Requires zero matching components. |
.webswingShouldVisible() |
Requires exactly one match with effective visible area. |
.webswingShouldNotVisible() |
Requires exactly one match with no effective visible area. |
.webswingCheckValue(value) |
Requires exactly one match whose value equals the expected value. |
.webswingClick() |
Clicks the center of the visible part of one matched component. |
.webswingMove(moveX, moveY) |
Performs a move/drag from the component by the specified pixel offsets. |
.webswingType(text) |
Focuses the component, moves the caret to the end, and types text or Cypress key sequences. |
.webswingClearInput() |
Focuses the component and clears its current value with keyboard input. |
Except for webswingShouldExistCount and webswingShouldNotExist, the chained assertions and actions require exactly one match. Start a new cy.webswingGet(...) when you need a fresh view of the component tree after the application UI changes.
Use cy.webswingWaitFor('JButton[name="saveButton"]').webswingClick() when the component appears asynchronously. A lookup error fails immediately rather than being treated as a missing component. Queries run sequentially because a Webswing browser instance has one pending query response at a time.
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, canvas scaling, and Cypress's application iframe; the helper does not click an unrelated first canvas.
cy.webswingLogin(...) targets the standard Webswing Admin Console login page and verifies the standard post-login routes. If your deployment uses a custom security flow or embeds Webswing in another application, replace this command with login setup appropriate for that environment.
The default Webswing instance name is webswingInstance0. Change it before the first lookup when the tested page exposes a different instance:
cy.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
cy.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 validation fails: verify that
baseUrlpoints to the Webswing Admin Console and that the supplied credentials can access it. - Commands are not defined: confirm that
webswing-cypress-plugin.jsis imported by the configured Cypress support file.