Docs

Component Locators

Typed component locator entry points, filters, resolution caching, custom locators, and opt-in interfaces.

A locator is a fluent object that combines a ComponentQuery filter chain with the actions of a ComponentTester. A single expression replaces the common test(find(…​).single()) pattern and the locator is reusable across UI changes — its resolution cache rewinds automatically when filters are reapplied, or explicitly via invalidate().

Note
Locator entry points are built in to BrowserlessUIContext (the multi-user/multi-window API) and to the JUnit 6 extensions (BrowserlessExtension and BrowserlessClassExtension). Tests that extend BrowserlessTest, SpringBrowserlessTest, or QuarkusBrowserlessTest don’t expose locator entry points by default — to avoid clashing with helper methods existing tests may already define. Opt in by declaring that the test class implements Locators (see Opting In below). This may become the default in a future release. For projects on commercial Vaadin components, see Commercial Components for the parallel CommercialLocators opt-in.

Generated Entry Points

For every built-in Vaadin component tester, a typed find<Component>() method is available on the window. The method name mirrors the component type, and the returned locator exposes both the filter chain and the tester’s action methods:

Source code
Java
var window = app.newUser().newWindow();
window.navigate(CartView.class);

window.findTextField().withLabel("Name").setValue("World");
window.findButton().withText("Save").click();

Assertions.assertEquals("Saved: World",
        window.findSpan().withId("echo").getText());

For testers whose value type isn’t pinned by the component (typically Grid and ComboBox), the entry point takes a witness:

Source code
Java
Person first = window.findGrid(Person.class).getRow(0);
int rows = window.findGrid(Person.class).size();

Filter Chain

Locators share their filter vocabulary with ComponentQuery. This includes withinSlot(String); see Filtering by Slot for slot ownership and nesting. Locator-specific operations are:

Method

Description

inside(Component) / inside(Locator)

Scopes the search to descendants. A locator scope resolves lazily on the first action.

atIndex(int)

Selects the n-th match, using a one-based index.

with(UnaryOperator<ComponentQuery<C>>)

Applies query operations not directly exposed by the locator, such as withPropertyValue and withResultsSize.

Note
Capability-specific filters — label, text, aria-label, placeholder, value, and theme — only appear on locators whose component actually supports the capability. They are contributed by mixin interfaces (HasLabelFilter, HasTextFilter, HasAriaLabelFilter, HasPlaceholderFilter, HasValueFilter, and HasThemeFilter) that generated locators implement based on the component’s interfaces. For example, findButton().withText(…​) compiles while findButton().withLabel(…​) is a compile error, because Button has text but no label. Custom locators can implement the mixins that match their component.
Source code
Java
window.findButton()
        .with(q -> q.withPropertyValue(Button::getText, "Save"))
        .click();

Resolution

Most locator chains end in a tester action (click(), setValue(), …​), which resolves the locator to a single component and caches the result for the rest of the chain. The base locator also exposes resolution methods directly:

Method Description

component()

Resolves to a single matching component (or the atIndex(n) pick). Caches the result; subsequent calls return the same instance until the cache is cleared.

components()

Returns all matching components. Bypasses the cache.

exists()

Returns true if the filter chain matches at least one component.

invalidate()

Rewinds the cache and clears any atIndex(n) pick. Use after a UI change that may have replaced or detached the resolved component.

Filter methods themselves clear only the resolution cache, so a locator can be re-used safely across UI mutations without re-applying its filters. atIndex(n) is sticky — it is part of the filter chain — so only invalidate() resets the pick.

Source code
Java
var save = window.findButton().withText("Save");

window.findTextField().withId("name").setValue("first");
save.click();

// Same locator instance, fresh resolution after the UI changed
window.findTextField().withId("name").setValue("second");
save.invalidate().click();

Seeding a Locator with a Direct Reference

When the test already holds a reference to a specific component (for example, an exposed field of a composite), use(component) returns a locator pinned to that instance. The locator skips the type-based search and applies any further filter on top of the identity match:

Source code
Java
PersonForm form = window.find(PersonForm.class).single();

window.use(form.nameField).setValue("Ada");
window.use(form.emailField).setValue("ada@example.com");
window.use(form.submit).click();

Custom Locators

A custom locator extends Locator<C, L> with its own type as L to preserve fluent return types. Inner locators use inside(this) to scope queries to the resolved composite. find(Supplier<L>) creates a custom locator through its factory.

For a worked example, see Test a Custom Component.

Opting in for BrowserlessTest

To use locator entry points in a test class that extends BrowserlessTest, SpringBrowserlessTest, or QuarkusBrowserlessTest, declare that the class implements Locators:

Source code
Java
class CartViewTest extends SpringBrowserlessTest implements Locators {

    @Test
    void addItem_increasesCartSize() {
        navigate(CartView.class);
        findButton().withText("Add to cart").click();

        Assertions.assertEquals("1 item",
                findSpan().withId("cart-size").getText());
    }
}

This may become the default in a future release, at which point the explicit implements clause can be dropped.

Commercial Components

CommercialLocators extends Locators and adds typed entry points for commercial component testers (Chart, GridPro, …​). The substitution is orthogonal to where you opt in: use CommercialLocators instead of Locators whenever you would otherwise reference Locators.

Source code
Java
class ChartViewTest extends SpringBrowserlessTest
        implements CommercialLocators {

    @Test
    void chart_isRendered() {
        navigate(ChartView.class);

        Assertions.assertNotNull(
                findChart().withId("sales").getComponent());
    }
}

The same substitution applies to a custom JUnit 6 extension subclass. For surfaces where you can’t substitute directly — such as the framework-constructed BrowserlessUIContext in the multi-user API — pass a commercial locator factory to the generic find(Supplier<L>) entry point: for example, window.find(ChartLocator::new).

2E7A4F31-6B98-4D2A-9C18-5F3E8A7B1C04

Updated