Docs

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

Set Up Browserless Tests with Spring Boot

Set up a Spring Boot project, write a browserless test for a Flow view, and run it from your IDE or Maven.

Use this guide for a Spring Boot application. Tests run with @SpringBootTest, and share a browserless application context that a test configuration defines as a Spring bean. For another application framework, choose its guide in Browserless Testing.

Add Dependencies

Assuming you’ve imported the Vaadin Bill-of-Materials (BOM) and have a Maven project, add the browserless-test-spring dependency with a test scope. Spring Boot’s test starter is also required; Spring Boot projects typically have it already:

Source code
XML
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>browserless-test-spring</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Create a Test

Views in Spring Boot applications typically get their services through dependency injection. @SpringBootTest starts the Spring application context for the test, and SpringBrowserlessApplicationContext creates views through it, so that views get the same beans as in the running application.

Define the Application Context Once

Define the browserless application context as a bean in a test configuration class. Put the class in src/test/java, in the package of your @SpringBootApplication class, so that the component scan of @SpringBootTest finds it:

Source code
BrowserlessContextConfiguration.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.vaadin.browserless.BrowserlessApplicationContext;
import com.vaadin.browserless.SpringBrowserlessApplicationContext;

@Configuration
public class BrowserlessContextConfiguration {

    @Bean
    BrowserlessApplicationContext browserlessApplicationContext(
            ApplicationContext applicationContext) {
        return SpringBrowserlessApplicationContext.create(applicationContext,
                Application.class); 1
    }
}
  1. Creates the browserless application context on top of the Spring one. It scans the package of your Application class and its sub-packages for routes, which covers the views and layouts of the whole application.

Spring creates the bean once, when it starts the Spring application context, and every test that uses the same Spring application context shares it. Spring also closes it when it closes the Spring application context. If the application uses Spring Security, define the bean with createSecured() instead; see Test View Access Control.

Write the Test

Given a simple view like this:

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

A browserless test for it looks like this:

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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.browserless.BrowserlessApplicationContext;
import com.vaadin.browserless.BrowserlessUIContext;

@SpringBootTest
class HelloWorldViewTest {

    @Autowired
    private BrowserlessApplicationContext app; 1

    private BrowserlessUIContext window;

    @BeforeEach
    void openWindow() {
        window = app.newUser().newWindow(); 2
    }

    @AfterEach
    void closeUser() {
        window.getUser().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. Spring injects the shared browserless application context.

  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 user and its window after the test. This ends the user’s session, and clears the Vaadin state, such as UI.getCurrent(), from the test thread, so that the next test starts clean.

  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.

Place the test in src/test/java, in the same Java package as the view. See How a Browserless Test Works for what each line of the test method does.

The tests share one Vaadin service, as the users of a running application do, and each test has a user and a session of its own. The application context is bound to the thread that creates it, so the tests must run on that thread, as they do with JUnit’s default sequential execution.

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.

Access Session-Scoped Beans

A Spring test field is injected before the test opens its window, so before the user’s Vaadin session exists. If a test needs an application bean with @VaadinSessionScope, inject an ObjectProvider and resolve the bean after the window exists:

Source code
CartViewSessionTest.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 org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.browserless.BrowserlessApplicationContext;
import com.vaadin.browserless.BrowserlessUIContext;

@SpringBootTest
class CartViewSessionTest {

    @Autowired
    private BrowserlessApplicationContext app;

    @Autowired
    private ObjectProvider<Cart> cartProvider;

    private BrowserlessUIContext window;

    @BeforeEach
    void openWindow() {
        window = app.newUser().newWindow();
    }

    @AfterEach
    void closeUser() {
        window.getUser().close();
    }

    @Test
    void addItem_cartContainsItem() {
        window.navigate(CartView.class);
        Cart cart = cartProvider.getObject();

        window.findButton().withText("Add to cart").click();

        Assertions.assertEquals(1, cart.getItems().size());
    }
}

This example assumes a session-scoped Cart service and a CartView whose Add to cart button adds an item to the cart. The provider resolves the bean for the user whose window is active — here the only window, which the preceding navigate() call used. Each test has a user of its own, so each test gets an empty cart. In a test with several users, call activate() on a window of the intended user before resolving the bean. The same approach works for a bean with Spring’s @SessionScope, which can also be injected directly. See Spring Session-Scoped Beans for scope guarantees and other deferred-lookup options.

Create an Application Context for Each Test

Some tests need an application context of their own instead of the shared one:

Such a test creates the context from the Spring application context before each test, and closes it afterwards:

Source code
Java
@Autowired
private ApplicationContext applicationContext;

private BrowserlessApplicationContext app;

@BeforeEach
void setUp() {
    app = SpringBrowserlessApplicationContext.create(applicationContext,
            CartView.class);
}

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

Closing the application context closes every user and window created from it. The context scans only the packages of the classes passed to create(), and their sub-packages.

Extend a Base Class Instead

A test can also extend SpringBrowserlessTest, 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 org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.browserless.SpringBrowserlessTest;
import com.vaadin.flow.component.notification.Notification;

@SpringBootTest
class HelloWorldViewTest extends SpringBrowserlessTest {

    @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 Spring Security test annotations, such as @WithMockUser, to its user; see Use Spring Security Test Annotations. See Base Classes for when to choose a base class.

Next Steps

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