Component Locators
- Generated Entry Points
- Filter Chain
- Resolution
- Seeding a Locator with a Direct Reference
- Custom Locators
- Opting In for
BrowserlessTest - Commercial Components
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().withId("name").setValue("World");
window.findButton().withCaption("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:
| Method | Description |
|---|---|
| Matches the component with the given |
| Matches by exact caption or by caption substring. |
| Matches by exact text content or by substring. |
| Matches components carrying all (or none) of the given CSS class names. |
| Matches components with (or without) the given theme value. |
| Matches by attribute presence and value. |
| Matches |
| Matches components satisfying a custom predicate. |
| Scopes the search to descendants of the given component (or of the component matched by the given locator — resolved lazily on first action). |
| Picks the n-th match (1-based) when the filter chain yields more than one. |
| Escape hatch for filters not exposed on the locator (for example, |
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 |
|---|---|
| Resolves to a single matching component (or the |
| Returns all matching components. Bypasses the cache. |
| Returns |
| Rewinds the cache and clears any |
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().withCaption("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
For composites, page objects, or domain-specific widgets, subclass Locator with the recursive self-type so filter steps stay chainable, and expose the actions you want the test to see. Scope inner queries with inside(this) so they only match descendants of the resolved composite:
Source code
Java
public class PersonFormLocator
extends Locator<PersonForm, PersonFormLocator> {
public PersonFormLocator() {
super(PersonForm.class);
}
public PersonFormLocator fillIn(String name, String email) {
new TextFieldLocator().withId("pf-name").inside(this).setValue(name);
new TextFieldLocator().withId("pf-email").inside(this).setValue(email);
return this;
}
public void submit() {
new ButtonLocator().withId("pf-submit").inside(this).click();
}
}Tests reach the custom locator through find(Supplier<L>):
Source code
Java
window.find(PersonFormLocator::new)
.fillIn("Ada", "ada@example.com")
.submit();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