Docs

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

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, with a window field created in a @BeforeEach method; for another framework, create the application context as described in Use the Examples with Your Framework.

Read the Tree of a Failed Query

A locator or 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
void clickSayHello_showsGreeting() {
    window.navigate(GreetingView.class);
    window.findButton().withText("Say hello").click();
    Assertions.assertEquals("Hello World",
            window.findNotification().getText());
}

The test fails because no Notification was found. The error message of the failed lookup 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
window.findTextField().withLabel("Your name").setValue("World");
window.findButton().withText("Say hello").click();
Assertions.assertEquals("Hello World", window.findNotification().getText());

See Snapshot Format for the properties represented in the tree.

Show the Tree for Other Failures

An assertion that fails after a successful lookup, 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 {
    // Create the application context in @BeforeEach,
    // and close it in @AfterEach.
}

The extension prints the UI of the window that the test used last. It runs before @AfterEach methods, so it works when the application context is closed in an @AfterEach method, but not when the test closes it itself, for example with try-with-resources. With a base class, add the annotation to the test class in the same way. With Java EE/CDI, add it 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 lookup like window.findNotification() 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 window.findButton().withText("Save") fails because several buttons match, the tree shows all of them so you can narrow your filters.

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

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