Docs

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

Set Up Browserless Tests with Quarkus

Configure Quarkus browserless tests, create a test class, and substitute services using test profiles.

Use this guide for a Quarkus application with Flow views. Tests run with @QuarkusTest, and create the Vaadin environment with QuarkusBrowserlessApplicationContext. For a Java EE application that uses Vaadin CDI and Weld, use the separate CDI setup.

Add Dependencies

With the Vaadin BOM imported, add these test dependencies to your pom.xml file:

Source code
pom.xml
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>browserless-test-junit6</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>browserless-test-quarkus</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit</artifactId>
    <scope>test</scope>
</dependency>

Create a Test

Create this view:

Source code
HelloWorldView.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("")
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());
        });
        add(name, sayHello);
    }
}

Create a test class in the same Java package as the view under src/test/java:

Source code
HelloWorldViewTest.java
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.vaadin.browserless.BrowserlessApplicationContext;
import com.vaadin.browserless.BrowserlessUIContext;
import com.vaadin.browserless.quarkus.QuarkusBrowserlessApplicationContext;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
class HelloWorldViewTest {

    private BrowserlessApplicationContext app;
    private BrowserlessUIContext window;

    @BeforeEach
    void setUp() {
        app = QuarkusBrowserlessApplicationContext.create(
                HelloWorldView.class); 1
        window = app.newUser().newWindow(); 2
    }

    @AfterEach
    void tearDown() {
        app.close(); 3
    }

    @Test
    void setText_clickButton_notificationIsShown() {
        window.navigate(HelloWorldView.class); 4

        window.findTextField().withLabel("Your name").setValue("Test");
        window.findButton().withText("Say hello").click();

        Assertions.assertEquals("Hello Test",
                window.findNotification().getText());
    }
}
  1. Creates the application context, which creates views through Quarkus dependency injection. It scans the package of HelloWorldView and its sub-packages for routes; if your views are in several packages, pass a class from each.

  2. Creates a user with its own Vaadin session, and opens a window for that user. The window shows the root route.

  3. Closes the application context, together with every user and window created from it.

  4. The test drives the UI through the window: it finds components by their label or text, and types and clicks, as a user does.

See How a Browserless Test Works for what each line of the test method does.

Note
@QuarkusTest starts the application and its HTTP server, which browserless tests don’t use. The browserless tests still run in a mocked Vaadin environment.

Run the Test

Run the test from your IDE or with mvn test. The test passes when entering a name and clicking the button shows the expected notification.

Replace a Service with a Test Profile

Annotate a test with @TestProfile to run it with a specific test configuration. A test profile can, for example, override application configuration, enable bean alternatives, and provide custom test resources. See the Quarkus Testing Profiles documentation for all options.

This example replaces a GreetingService with a test implementation. It assumes a WelcomeView that shows the result of greetingService.greet("Quarkus") in a span stored in its greeting field. The test implementation is a CDI bean annotated with @Alternative:

Source code
MockService.java
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Alternative;

@Alternative
@ApplicationScoped
public class MockService implements GreetingService {
    @Override
    public String greet(String name) {
        return "Hello " + name + " from the mock service";
    }
}

The profile enables the alternative and also overrides the app.some.config property:

Source code
MockServiceProfile.java
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import io.quarkus.test.junit.QuarkusTestProfile;

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);
    }
}

A test that uses the profile gets the alternative injected into the view:

Source code
MockServiceViewTest.java
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.vaadin.browserless.BrowserlessApplicationContext;
import com.vaadin.browserless.BrowserlessUIContext;
import com.vaadin.browserless.quarkus.QuarkusBrowserlessApplicationContext;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.TestProfile;

@QuarkusTest
@TestProfile(MockServiceProfile.class)
class MockServiceViewTest {

    private BrowserlessApplicationContext app;
    private BrowserlessUIContext window;

    @BeforeEach
    void setUp() {
        app = QuarkusBrowserlessApplicationContext.create(WelcomeView.class);
        window = app.newUser().newWindow();
    }

    @AfterEach
    void tearDown() {
        app.close();
    }

    @Test
    void view_usesMockService() {
        WelcomeView view = window.navigate(WelcomeView.class);
        Assertions.assertEquals("Hello Quarkus from the mock service",
                view.greeting.getText());
    }
}

Extend a Base Class Instead

A test can also extend QuarkusBrowserlessTest, which creates the Vaadin environment with one user and one window before each test method, and closes it afterwards. The test then calls the window methods on itself:

Source code
HelloWorldViewTest.java
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.vaadin.browserless.quarkus.QuarkusBrowserlessTest;
import com.vaadin.flow.component.notification.Notification;
import io.quarkus.test.junit.QuarkusTest;

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

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

        Notification notification = find(Notification.class).single();
        Assertions.assertEquals("Hello Test", test(notification).getText());
    }
}

The base class scans the whole classpath for routes, unless the test class has a @ViewPackages annotation. It applies the Quarkus @TestSecurity annotation to its user; see Use Quarkus Test Security. See Base Classes for when to choose a base class.

Next Steps

09A26994-97AB-4877-AEB1-717BE02E348D