Documentation

Documentation versions (currently viewing)

UI Unit Testing in Quarkus-based Projects

Describes and provides examples of how to perform UI Unit Tests.

In Quarkus-based projects, views may use dependency injection to get references to service and other software components. To instantiate such views and correctly handle navigation, Vaadin needs special implementation of internal components, such as QuarkusInstantiator. Testing with UIUnitTest provides specialized base test classes that integrate with the Quarkus Testing Framework: QuarkusUIUnitTest, which is only supported for JUnit 5.

Subclasses can therefore rely on all of the features offered by the Quarkus Testing Framework by being annotated with @QuarkusTest. See Quarkus Testing documentation for additional information about Quarkus testing framework.

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

        test(helloView.name).setValue("Test");
        test(helloView.sayHello).click();

        Notification notification = $(Notification.class).first();
        Assertions.assertEquals("Hello Test", test(notification).getText());
    }
}
Note
With @QuarkusTest annotation, the testing framework starts the application and the HTTP server — although it won’t be required for UI unit testing. However, QuarkusUIUnitTest tests are still executed in a mocked environment.

A test can be annotated with @TestProfile to reference a specific test configuration. With a test profile you can, for example, override application configuration, provide bean alternatives and custom test resources. Refer to the Quarkus Testing Profiles documentation for additional information.

public class MockServiceProfile implements QuarkusTestProfile {

    @Override
    public Map<String, String> getConfigOverrides() {
        return Collections.singletonMap("app.some.config","value");
    }

    @Override
    public Set<Class<?>> getEnabledAlternatives() {
        return Collections.singleton(MockService.class);
    }
}

@QuarkusTest
@TestProfile(MockServiceProfile.class)
class ViewTest extends QuarkusUIUnitTest {
}

Additional Setup

In addition to the TestBench dependency, be sure to add the Quarkus UI Unit Testing and the Quarkus test dependencies to your project. Add the following to your pom.xml file:

<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-testbench-unit-quarkus</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5</artifactId>
    <scope>test</scope>
</dependency>

Set Up View Access Control

To apply view access control, Vaadin requires a NavigationAccessControl to be registered as a BeforeEnterListener for the UI. Currently, the Vaadin Quarkus add-on doesn’t support automatic registration of the access control feature. To enable it for UI Unit Testing, perform the setup in a QuarkusTestProfile class by providing an observer for the Vaadin ServiceInitEvent that executes this step.

public class TestViewSecurityConfig implements QuarkusTestProfile {

    @Override
    public String getConfigProfile() {
        return "test-security"; // (1)
    }

    @IfBuildProfile("test-security") // (1)
    public static class NavigationAccessControlInitializer {

        public void serviceInit(@Observes ServiceInitEvent event) { // (2)
            // @QuarkusTest starts the whole application, so we check
            // the VaadinService type to enable access control only for
            // UI Unit tests
            if (event.getSource() instanceof MockQuarkusServletService) { // (3)
                event.getSource().addUIInitListener(uiEvent -> {
                    // Customize the NavigationAccessControl as needed
                    NavigationAccessControl accessControl = new NavigationAccessControl();
                    accessControl.setLoginView(LoginView.class);

                    uiEvent.getUI().addBeforeEnterListener(accessControl);
                });
            }
        }
    }
}
  1. Sets the configuration profile to be used for the test. The class is annotated with @IfBuildProfile to make the observer only run it for tests that require this profile.

  2. Listens for Vaadin ServiceInitEvent. This is the same as implementing VaadinServiceInitListener and registering the class to be loaded by Java ServiceLoader.

  3. Checks that execution is started by the UI Unit Test. This is required because @QuarksTest causes the whole application to start when running the test.

NavigationAccessControl was introduced in Vaadin 24.3. In a project based on an earlier version, view security can be configured in the same way, but using the ViewAccessChecker component:

public class TestViewSecurityConfig implements QuarkusTestProfile {

    @Override
    public String getConfigProfile() {
        return "test-security";
    }

    @IfBuildProfile("test-security")
    public static class NavigationAccessControlInitializer {

        public void serviceInit(@Observes ServiceInitEvent event) {
            // @QuarkusTest starts the whole application, so we check
            // the VaadinService type to enable access control only
            // for UI Unit tests
            if (event.getSource() instanceof MockQuarkusServletService) {
                event.getSource().addUIInitListener(uiEvent -> {
                    ViewAccessChecker viewAccessChecker = new ViewAccessChecker();
                    viewAccessChecker.setLoginView(LoginView.class);
                    uiEvent.getUI().addBeforeEnterListener(viewAccessChecker);
                });
            }
        }
    }
}

Quarkus Test Security Features

When using QuarkusUIUnitTest, if Quarkus Security is present on the classpath, the mock environment is instructed to fetch authentication details from Quarkus SecurityIdentity.

With this support, you can use Quarkus @TestSecurity annotation to simulate different authentication scenarios with test method granularity. More information is available from the Quarkus Security Testing documentation. Authentication details are available before creating the UI instance and navigating to the default route. Redirects to the login view aren’t performed when simulating logged-in users. In the same way, custom redirect logic for authenticated users works as expected.

To use Quarkus Security test annotations, first ensure the dependency is added to the project:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-test-security</artifactId>
    <scope>test</scope>
</dependency>

Next, extend QuarkusUIUnitTest and annotate test methods to set up an authentication scenario. For the simplest situations, use @TestSecurity, providing the username and roles that should be granted.

@QuarkusTest
@TestProfile(TestViewSecurityConfig.class) // (1)
class ViewSecurityTest extends QuarkusUIUnitTest {

    @Test
    @TestSecurity(authorizationEnabled = false) // (2)
    void anonymousUser_protectedView_redirectToLogin() {
        navigate("protected", LoginView.class);
    }

    @Test
    @TestSecurity(authorizationEnabled = false) // (2)
    void anonymousUser_publicView_signInLinkPresent() {
        // public view is default page
        Assertions.assertInstanceOf(PublicView.class, getCurrentView());

        Anchor anchor = $(Anchor.class).withText("Sign in").first();
        Assertions.assertTrue(
                test(anchor).isUsable(),
                "Sign in link should be available for anonymous user");
    }

    @Test
    @TestSecurity(user = "admin", roles = "ADMIN") // (2)
    void adminUser_adminView_viewShown() {
        navigate(AdminRoleView.class);

        Assertions.assertTrue(
                $(Avatar.class).first().isVisible(),
                "Avatar should be visible for logged users");
    }
}
  1. Sets a profile to activate Vaadin access control feature.

  2. Uses Quarkus test security annotations.

61B2F8E5-448E-4C36-82E3-D492712ECE67