> Markdown version of [Getting Started](https://vaadin.com/docs/v24/flow/testing/ui-unit/getting-started). Section index: [llms.txt](https://vaadin.com/docs/v24/flow/llms.txt)

# Getting Started with UI Unit Testing

To start creating UI unit tests in an existing project, you need to add the TestBench UI Unit Testing dependency (`com.vaadin`/`vaadin-testbench-unit`) with a `test` scope. Assuming you have imported the Vaadin Bill-of-Materials (BOM) and have a Maven project, all you need to do is add the following:

**JUnit 4**

```xml
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-testbench-unit</artifactId>
    <scope>test</scope>
</dependency>
```

JUnit 5 support is added in Vaadin 24.

**JUnit 5**

```xml
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-testbench-unit-junit5</artifactId>
    <scope>test</scope>
</dependency>
```

> **Note:** As UI Unit Test has a tester for the Chart component, it is required on the class path. If your application is not using the Chart component, you need to add a test scope dependency to it, otherwise a \[classname]\` ClassNotFoundException\` will be thrown.

```xml
    <dependency>
      <groupId>com.vaadin</groupId>
      <artifactId>vaadin-charts-flow</artifactId>
      <scope>test</scope>
    </dependency>
```

## <a id="first-ui-unit-test"></a>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 is 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](https://vaadin.com/docs/v24/flow/testing/ui-unit/spring.md).

```java
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 from there
        test(helloView.name).setValue("Test");
        test(helloView.sayHello).click();

        // Notification isn't 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.

Package Scan Examples

```java
@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.

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

## <a id="running-tests"></a>Running Tests

Testing with `UIUnitTest` does don’t require any particular setup to be executed. Run the test directly from your IDE or use Maven, for example by typing `mvn test` on the terminal.

## <a id="navigating-in-unit-tests"></a>Navigating in Unit Tests

On test initialization, the loaded view is 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 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.

Using `TextField` from view

```java
// Navigate to InputView
InputView input = navigate(InputView.class);

// Get the nameField TextField from InputView and then get 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());
```

### <a id="testing-components"></a>Testing Components

The aim of browser-less testing isn’t 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 get a tester for a component with `test(component)` or `test(Tester.class, component)`.

- `test(component)` returns 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’s 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 Checked**
>
> The modality check only works when the modal component is [server-side modal](https://vaadin.com/docs/v24/flow/advanced/server-side-modality.md), as client modality isn’t defined on the server.

Sample test of the HelloWorld view.

`HelloWorld.java`

```java
@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`.

`HelloWorldViewTest.java`

```java
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 from there
        test(helloView.name).setValue("Test");
        test(helloView.sayHello).click();

        // Notification isn't 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`
