Docs

Documentation versions (currently viewingVaadin 25.4 (pre-release))

Test User Interactions

Learn how a browserless test works, then fill in forms, select Grid rows, confirm dialogs, and test navigation, shortcuts, and menus.

The examples in this guide use the plain Java setup, where a @BeforeEach method creates the application context and a window field, as in the plain Java setup guide. For another framework, create the application context as described in Use the Examples with Your Framework. Each example belongs inside a test method unless shown otherwise.

How a Browserless Test Works

Each setup guide ends with a test for the same HelloWorldView. The test navigates to the view, enters a name, clicks a button, and checks the notification that appears:

Source code
Java
window.navigate(HelloWorldView.class);

window.findTextField().withLabel("Your name").setValue("Test");
window.findButton().withText("Say hello").click();

Assertions.assertEquals("Hello Test", window.findNotification().getText());

The test does everything through window, a BrowserlessUIContext that represents one browser window of one user. The following sections explain each step. They work the same way with every setup; only the code that creates the application context differs.

The navigate() method opens a view in the window, as a user would navigate to it in the browser. It returns the view instance so you can interact with it directly.

Source code
Java
HelloWorldView view = window.navigate(HelloWorldView.class);

Find and Use Components with Locators

A user finds a field by its label and a button by its text, and then types or clicks. A test does the same with a locator. The window has a locator method for each Vaadin component, such as findTextField(), findButton(), and findNotification(). Filters such as withLabel(), withText(), and withId() narrow down the search, and an action such as setValue(), click(), or getText() acts on the one component that matches:

Source code
Java
// Simulate typing into a text field
window.findTextField().withLabel("Your name").setValue("Test");

// Simulate clicking a button
window.findButton().withText("Say hello").click();

// Read the text a user would see
String text = window.findNotification().getText();

The locator looks up the component when the action runs, and fails the test if the filters match no component or more than one. Like a user, an action works only on a component that is visible, enabled, and attached to the UI; otherwise, it fails the test as well.

Each locator offers the actions that fit its component. For example, findCheckbox() has click() to toggle the checked state, findComboBox() has selectItem(), and findGrid() has getRow(). The filters fit the component too: findButton().withText() compiles, but findButton().withLabel() doesn’t, because a button has text but no label. A locator can be kept in a variable and reused after the UI changes. See Component Locators for the filters, reuse rules, and custom locators.

A test that extends a base class gets the locator methods by implementing Locators, as in class CartViewTest extends BrowserlessTest implements Locators. With Java EE/CDI, add implements Locators to your AbstractCdiViewTest subclass.

Use the Java API Directly

Since the test runs on the server side, it also has direct access to the Java component API. Use it to read state that the locator actions don’t cover. The component() method returns the component that a locator finds. The view that navigate() returns gives access to its fields: the TextField and Button fields of HelloWorldView are package-private, so a test in the same Java package can read them — for example, if the view is in src/main/java/com/example/app/, put the test in src/test/java/com/example/app/.

Source code
Java
// Read a component's value through its locator
String currentValue = window.findTextField().withLabel("Your name")
        .component().getValue();

// Check component state through the view's fields
boolean isEnabled = view.sayHello.isEnabled();
boolean isVisible = view.name.isVisible();

To change a value, use a locator or a tester rather than the component’s own setter. They act the way a user does, so value change events report isFromClient() as true, and listeners that react only to user changes run as they would in the browser.

Wrap a Component in a Tester

When the test already holds a component — for example, from a view field — wrap it with test() to get a tester with the same actions as the locator:

Source code
Java
window.test(view.name).setValue("Test");
window.test(view.sayHello).click();

Locators offer the actions of these testers, and a custom component can have a tester of its own; see Test a Custom Component. See Component Testers for the actions of each component.

Query for Components

The find() method returns a component query, for when the test needs the components themselves rather than an action — for example, all the buttons in a toolbar:

Source code
Java
List<Button> buttons = window.find(Button.class).all();

Locators are built on these queries and share their filters. See Querying Components for details.

Find the Component to Exercise

Use a label or visible text when it identifies the component unambiguously. When the same field appears more than once, scope the locator with inside(). For a ProfileView whose First name field also appears in a dialog that the view opens, scope the locator to the view:

Source code
Java
var view = window.navigate(ProfileView.class);
var firstName = window.findTextField().withLabel("First name").inside(view);
firstName.setValue("Ada");
Assertions.assertEquals("Ada", firstName.component().getValue());

inside() also accepts another locator, such as one for the dialog. A component inside a Grid renderer may need to be obtained through the Grid locator’s getCellComponent(…​) before it can be exercised. If a locator finds nothing, the component may be inside a renderer or a closed overlay, which locators and queries don’t reach. See Query Boundaries and Component Queries for the full behavior.

Fill In and Submit a Form

Set each field through its locator, then click the submit button. For a SignUpView with a Name text field, an Email email field, and a Sign up button that shows a welcome notification:

Source code
Java
window.navigate(SignUpView.class);
window.findTextField().withLabel("Name").setValue("Ada");
window.findEmailField().withLabel("Email").setValue("ada@example.com");
window.findButton().withText("Sign up").click();

Assertions.assertEquals("Welcome, Ada", window.findNotification().getText());

A locator sets the value the way a user does, so the field’s validation runs as it would in the browser:

Source code
Java
var email = window.findEmailField().withLabel("Email");
email.setValue("not an email");
Assertions.assertTrue(email.component().isInvalid());

Check the Outcome in the Backend

What the view shows doesn’t prove that the action reached the backend. Assert both: what the user is told, and the state that the action changed. In a Spring Boot test, autowire the service that the view uses, and query it after the action. For a BookingView that books a berth for the boat named in its Boat field:

Source code
Java
window.navigate(BookingView.class);
window.findTextField().withLabel("Boat").setValue("S/Y Alice");
window.findButton().withText("Book B12").click();

Assertions.assertEquals("B12 is yours", window.findNotification().getText());
Assertions.assertEquals("S/Y Alice", bookingService.boatIn("B12"));

The view runs on the test’s own thread, so when the service stores the change in a database, @Transactional on the test class rolls back the changes made through the window, too.

Select a Grid Row

Use the Grid locator to read rows and select items. Pass the item type of the grid, so that the locator knows the type of the rows. For a PersonListView with a grid of Person items and a details span that shows the selected person:

Source code
Java
var view = window.navigate(PersonListView.class);
var grid = window.findGrid(Person.class);
Assertions.assertEquals(3, grid.size());
Assertions.assertEquals("Ada", grid.getCellText(0, 0));

grid.select(0);
Assertions.assertEquals("Selected: Ada", view.details.getText());

The locator also has clickRow() for views that react to item clicks, and getRow() for reading the item on a row. See Component Testers for the other Grid operations.

Confirm a Dialog

An open dialog is attached to the UI, so a locator finds it. For an AccountView whose Delete account button opens a ConfirmDialog, and whose status span reports the result:

Source code
Java
var view = window.navigate(AccountView.class);
window.findButton().withText("Delete account").click();

var dialog = window.findConfirmDialog();
Assertions.assertEquals("Delete account?", dialog.getHeader());
dialog.confirm();

Assertions.assertEquals("Account deleted", view.status.getText());

Call cancel() or reject() on the locator to click the dialog’s other buttons. For a Dialog, find its buttons with window.findButton() while the dialog is open.

Use Test IDs

Use Component.setTestId() to assign a stable identifier to a component for use in tests. This sets the data-testid HTML attribute on the component’s element, which can also be used by browser-based testing frameworks:

Source code
Java
Button submitButton = new Button("Submit");
submitButton.setTestId("submit-button");

// Later, retrieve the test ID
String testId = submitButton.getTestId(); // "submit-button"

Use a test ID when a label or visible text would be ambiguous or would change with translations. Keep the identifier independent of styling and layout.

Browserless tests can use the same identifier: the withTestId() filter looks up components by their test ID:

Source code
Java
window.findButton().withTestId("submit-button").click();

Component queries also have a testId() terminal operator; see Querying Components for details.

Test Navigation

Navigate by location when the outcome may be a redirect, and pass the view class you expect to end up in. The call fails if navigation ends in another view:

Source code
Java
window.navigate("protected", LoginView.class);

A location can also carry a query string and fragment; for example, navigate("orders/123?tab=history#details", OrderView.class). Assert the state selected by those parameters after navigation.

For route parameters and other navigation forms, see Navigation.

Test Keyboard Shortcuts

Fire a shortcut with window.fireShortcut(), then assert the same outcome as the matching button click. For a form with a Ctrl+S save shortcut:

Source code
Java
window.fireShortcut(Key.KEY_S, KeyModifier.CONTROL);
// Assert the saved state or the confirmation shown by your view.

Test Menu Actions

Use a menu tester to reach overlay content. A context menu stays hidden until the test opens it, so a locator can’t find it; wrap the view’s field in a tester instead. For a view exposing a contextMenu field with a checkable Bold item:

Source code
Java
var view = window.navigate(EditorView.class);
var menu = window.test(view.contextMenu);
menu.open();
menu.clickItem("Bold");
Assertions.assertTrue(menu.isItemChecked("Bold"));

Open the menu before clicking items or reading their state; the tester throws an exception for a closed menu. For nested actions, pass a text path such as clickItem("Share", "Email"). For a menu containing custom components, call find(…​) on the menu tester, such as menu.find(Button.class). This query also works while the menu is closed, but the components it returns stay detached until the menu opens. See Overlay Component Testers for indexing and attachment semantics.

BDC6250E-E9D6-44DD-9B67-777C0F7E98AA