Docs

Documentation versions (currently viewingVaadin 25)
Documentation translations (currently viewingEnglish)

Debug a Failing Browserless Test

Read the component tree of a failing browserless test, enable failure snapshots, and fix the test.

When a browserless test fails, the error message may not show what the UI looked like at that moment. The component tree — a text representation of every component in the UI — shows exactly what was on screen. The examples use the plain Java setup; for another framework, change the base class as described in Use the Examples with Your Framework.

Read the Tree of a Failed Query

A component query that finds no match, or more matches than expected, includes the component tree in its error message. Suppose you have a view like this:

Source code
GreetingView.java
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;

@Route("greeting")
public class GreetingView extends HorizontalLayout {

    TextField name;
    Button sayHello;

    public GreetingView() {
        name = new TextField("Your name");
        sayHello = new Button("Say hello");
        sayHello.addClickListener(e -> {
            if (!name.getValue().isEmpty()) {
                Notification.show("Hello " + name.getValue());
            }
        });
        add(name, sayHello);
    }
}

And a test for it:

Source code
Java
@Test
public void clickSayHello_showsGreeting() {
    GreetingView view = navigate(GreetingView.class);
    test(view.sayHello).click();
    Notification notification = find(Notification.class).single();
    Assertions.assertEquals("Hello World", test(notification).getText());
}

The test fails because no Notification was found. The error message of the failed query includes the UI tree:

Source code
└── MockedUI[]
    └── GreetingView[@theme='spacing']
        ├── TextField[label='Your name', value='', manualValidation='true']
        └── Button[caption='Say hello']
            └── Text[text='Say hello']

Now you can see:

  • There’s no Notification in the tree — the click didn’t produce one.

  • The TextField has value='' — the name field is empty.

  • Looking back at the view code, the click handler only opens the notification when the name is nonempty. The test forgot to set the name before clicking.

Set the name before clicking the button, then rerun the test:

Source code
Java
test(view.name).setValue("World");
test(view.sayHello).click();
Notification notification = find(Notification.class).single();
Assertions.assertEquals("Hello World", test(notification).getText());

See Snapshot Format for the properties represented in the tree.

Show the Tree for Other Failures

An assertion that fails after a successful query, such as a comparison of a component’s text, doesn’t include the tree. To get the tree for every failed test in a class, add the @ExtendWith(TreeOnFailureExtension.class) annotation to the test class:

Source code
Java
@ExtendWith(TreeOnFailureExtension.class)
class GreetingViewTest extends BrowserlessTest {
    ...
}

With Java EE/CDI, add the same annotation to your AbstractCdiViewTest subclass:

Source code
Java
@ExtendWith(TreeOnFailureExtension.class)
class CdiGreetingViewTest extends AbstractCdiViewTest {
    // Keep the test methods from the CDI guide.
}

When a test in the class fails, the extension publishes the UI tree as a JUnit report entry. Tools that display report entries, such as the JUnit console launcher, show it with the failure. Maven Surefire doesn’t display report entries. The extension is in the com.vaadin.browserless package, and @ExtendWith is in org.junit.jupiter.api.extension.

Tips for Reading the Tree

  • Look for what’s missing. If a query like find(Notification.class).single() fails, the tree shows that the component isn’t there. Check the tree for clues about why it wasn’t created.

  • Check property values. When an assertion on a component’s text or value fails, find that component in the tree and compare its actual properties to what you expected.

  • Watch for unexpected components. If find(Button.class).single() fails because multiple buttons were found, the tree shows all of them so you can narrow your query.

  • Inspect the layout hierarchy. If a component appears in the tree but a scoped query like findInView(TextField.class) can’t find it, the tree helps you see whether the component is nested inside the expected parent.

7B14417A-0C9B-4B46-8945-AC2564AD5F82