Documentation

Documentation versions (currently viewingVaadin 23)
Check out the new styling guides

Getting Started with UI Unit Testing

Create and run your first UI unit test.

To start unit testing your Vaadin UIs, create a class that extends UIUnitTest (for JUnit 5) or UIUnit4Test (for JUnit 4). The base class instantiates a UI along with all the necessary Vaadin environment, which will be available to your test methods.

Tip
Testing with Spring
This guide shows how to implement UI unit tests in plain Java projects. For information about testing with Spring or Spring Boot, consult the UI Unit Testing with Spring.
class HelloWorldViewTest extends UIUnitTest {

    @Test
    public void setText_clickButton_notificationIsShown() {
        final HelloWorldView helloView = navigate(HelloWorldView.class);

        // TextField and Button are available as package protected in the view
        // So we can use those simply from there
        test(helloView.name).setValue("Test");
        test(helloView.sayHello).click();

        // Notification is not referenced in the view so we need to use the component
        // query API to find the notification that opened
        Notification notification = $(Notification.class).first();
        Assertions.assertEquals("Hello Test", test(notification).getText());
    }

}

By default, the base class scans whole classpath for routes and error views, but this behavior can be changed for a faster bootstrap. To restrict the scan to specific packages and their sub-packages, annotate the test class with ViewPackages and specify the package by filling the classes() array with classes that are members of the desired packages, or by providing the packages with fully qualified names in the packages() property. Using classes() is the preferred way, since it plays well with IDEs refactoring when moving classes to different packages.

@ViewPackages(classes={ MyView.class, OtherView.class })
class MyViewTest extends UIUnitTest {
}

@ViewPackages(packages={ "com.example.app.pgk1", "com.example.app.pgk2" })
class MyViewTest extends UIUnitTest {
}

@ViewPackages(
    classes={ MyView.class, OtherView.class },
    packages={ "com.example.app.pgk1", "com.example.app.pgk2" }
)
class MyViewTest extends UIUnitTest {
}

Using the annotation without providing classes() or packages() acts as a shortcut for restricting the scan to the current test class package and sub-packages.

@ViewPackages // same as @ViewPackages(classes=MyViewTest.class)
class MyViewTest extends UIUnitTest {
}

Running Tests

Testing with UIUnitTest does do not require any particular setup to be executed. Just run the test directly from your IDE or use Maven, for example by typing mvn test on the terminal.

On test initialization, the loaded view will be the root view.

To navigate to another registered view, the UIUnitTest base class contains navigate() methods that support navigation to different supported views.

  • For a normal view with only a path defined

    navigate(MyView.class)

    navigate("myView", MyView.class)

  • For a view with HasUrlParameter

    navigate(MyParam.class, "parameter")

    navigate("myParam/parameter", MyParam.class)

  • For a view with URL template @Route("template/:param")

    navigate(Template.class, Collections.singletonMap("param", PARAMETER))

    navigate("template/myParam", Template.class)

All navigation methods will return the instantiated view, so that the package private fields can be used directly from the view for testing.

Note
Navigation by location string takes in the view class, so that the initialized view can be automatically validated to be the expected one.
// Navigate to InputView
InputView input = navigate(InputView.class);

//Get the nameField TextField from InputView and then obtain the Tester to operate on it
TextFieldTester nameField_ = test(input.nameField);

// use the tester to set the value, to do required checks and fire expected events
nameField_.setValue("User input");

// Assert in another component that the change event fired and it has the correct value
Assertions.assertEquals("User input", input.changeText.getText());

Testing Components

The aim of browser-less testing is not to test the components as is, but to simulate user actions and data "seen" on the client side.

To help with actions and getting data, there are testers for components that have methods for use with components. In a UIUnitTest class, you can obtain a tester for a component with test(component) or test(Tester.class, component).

  • test(component) will return a component-specific tester, if one can be determined for the given component, or the ComponentTester generic tester.

  • test(Tester.class, component) always returns an instance of the given tester.

For each method call, where it is applicable, the tester methods check that the component is in a state where it could be used by the user. This means that the component should be visible, enabled, attached to the UI, and not behind a modal component.

Note
Only server modality is checked
The modality check only works when the modal component is server-side modal, as client modality is not defined on the server.

Sample test of the HelloWorld view.

@Route(value = "", layout = MainLayout.class)
public class HelloWorldView extends HorizontalLayout {

    TextField name;
    Button sayHello;

    public HelloWorldView() {
        name = new TextField("Your name");
        sayHello = new Button("Say hello");
        sayHello.addClickListener(e -> {
            Notification.show("Hello " + name.getValue());
        });

        setMargin(true);
        setVerticalComponentAlignment(Alignment.END, name, sayHello);

        add(name, sayHello);
    }
}
Note
The components are package-protected, so that we can use them directly in the UIUnitTest.
class HelloWorldViewTest extends UIUnitTest {

    @Test
    public void setText_clickButton_notificationIsShown() {
        final HelloWorldView helloView = navigate(HelloWorldView.class);

        // TextField and Button are available as package protected in the view
        // So wwe can use those simply from there
        test(helloView.name).setValue("Test");
        test(helloView.sayHello).click();

        // Notification is not referenced in the view so we need to use the component
        // query API to find the notification that opened
        Notification notification = $(Notification.class).first();
        Assertions.assertEquals("Hello Test", test(notification).getText());
    }
}

7F423DA0-1C41-44BA-B832-55C269FA9311