Missing blur-event simulation API in browserless-test

Hi,

browserless-test provides a Clickable mixin (click(), middleClick(), rightClick(), …) that lets testers simulate a DOM click by firing the corresponding Vaadin ComponentEvent server-side. There doesn’t seem to be an equivalent for the blur DOM event. Any component whose production logic is wired to BlurNotifier/BlurEvent - a common pattern for “commit value only when the field loses focus” - can’t be exercised through the public tester API.

Affected version: com.vaadin:browserless-test-shared - checked 1.0.0 through 1.2.0-alpha2 (latest released), and the main branch on GitHub as of 2026-08. None expose blur simulation.

Environment: Vaadin 25.2.2 (Flow), Spring Boot 4.1.0, JUnit 5, browserless-test-shared / browserless-test-junit6 / browserless-test-spring.

Problem description

Several Vaadin field components (TextField, NumberField, custom subclasses) implement Focusable, which extends BlurNotifier. Production code frequently attaches business logic - validation, persistence (“save on blur”), or dialog triggers - to addBlurListener(…), deliberately keeping it separate from addValueChangeListener(…) (which may fire on every keystroke or on ON_CHANGE). This mirrors real browser behavior, where an fires change and then blur together when focus leaves the field after an edit.

In our application, a field’s save() method - the sole path to persisting its value and, in some cases, opening a follow-up confirmation dialog - is invoked exclusively from a BlurListener, not from the ValueChangeListener.

When testing this with browserless-test:

  • ComponentTester/TextFieldTester/NumberFieldTester provide setValue(…), which fires a ComponentValueChangeEvent - but nothing fires a BlurEvent.
  • Focusable.blur() (Vaadin Flow core, not part of the test library) only calls element.executeJs(“this.blur()”). Since there’s no real client attached in a browserless/server-side unit test, this JS call is a no-op and never produces a server-side BlurEvent. Verified by decompiling Focusable.blur() in flow-server - it unconditionally schedules a JS snippet and returns; there’s no synchronous or fallback server-side event dispatch.
  • ComponentTester internally already has everything needed to fix this: a protected fireDomEvent(String eventType) method that fires an arbitrary DOM event server-side - exactly the mechanism Clickable.click() builds on for clicks (via ComponentUtil.fireEvent(component, new ClickEvent<>(…))). However, fireDomEvent is protected, so it isn’t usable from test code, and there’s no public wrapper for blur.

As a result, the only way to simulate a blur from test code today is ComponentUtil.fireEvent(field, new BlurNotifier.BlurEvent<>(field, true)) directly, bypassing the tester API entirely - undiscoverable, easy to get wrong (e.g. forgetting fromClient=true), and duplicated at every call site since no shared helper exists.

Expected behavior

A Blurable-style mixin (parallel to Clickable), implemented by ComponentTester (or at least by testers for Focusable components), exposing something like:

public interface Blurable<T extends Component & Focusable> {
T getComponent();
void ensureComponentIsUsable();

default void blur() {
    ensureComponentIsUsable();
    T component = getComponent();
    ComponentUtil.fireEvent(component, new BlurNotifier.BlurEvent<>(component, true));
}

}

Actual behavior

No public API exists to simulate a blur event. Test authors must manually call ComponentUtil.fireEvent(…), working around the tester abstraction.

Reproduction

  1. Create a TextField with a BlurListener that performs an observable action (sets a flag, saves a value, etc.).
  2. In a browserless-test/SpringBrowserlessTest-based test, call test(textField).setValue(“x”).
  3. Assert the blur-triggered action happened - it doesn’t, because only a ComponentValueChangeEvent was fired, never a BlurEvent.
  4. Calling textField.blur() (Flow’s own Focusable.blur()) doesn’t help either - it emits a JS call with no client to execute it.

Current workaround

test(textField).setValue(“100”);
ComponentUtil.fireEvent(textField, new BlurNotifier.BlurEvent<>(textField, true));

Works, but undocumented, duplicated at every call site, and easy to get wrong.

Suggested fix

Add a Blurable mixin analogous to Clickable, and have ComponentTester (or component-specific testers for Focusable types) implement it - giving test code a discoverable test(field).blur() call that fires a proper server-side BlurEvent, matching how click() already works.

This is indeed the case. There is difference between old Vaadin 8 and Flow framework’s UI class. In Vaadin 8 the currently focused component is known by UI in the server state, but that is not the case with Flow. This is why e.g. in Vaadin 8 version of the UI Unit Test, the thing you are asking for is being implemented. But in Flow version implementing this not probably possible without refactoring the focus handling to be more similar to what it is in Vaadin 8. Thus the best you can do is to fire explicit blur event when you need it.

1 Like

Thank you for the fast feedback!

Although I find it bit “interesting” way how you use blur listener in your application code (instead of value changes listeners), to me this sounds like a bug that we should definitely try to fix in browserless-test. I’ll file a bug atleast and see what we could do.

Thanks, it will be nice

Bug, repro code and a fix:

Check it out and let us know if you think that would solve the issue for you (without workarounds). Our best browserless-test expert is still on vacay, so it might take a while until somebody dares to land that.

2 Likes