Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Testing views

A Vaadin view is a Java object, so you can check it with an ordinary JUnit test, without a browser. The browserless-test library creates a fake Vaadin session, opens the view, finds components on it and "clicks" them. Such tests run in seconds and catch most errors in view logic.

Dependencies

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>browserless-test-spring</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

The Vaadin BOM sets the browserless-test-spring version. The last dependency lets tests run as a user with the needed role.

Testing the post list

// src/test/java/com/example/blog/views/PostListViewTest.java
package com.example.blog.views;
 
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
 
import com.example.blog.Post;
import com.vaadin.browserless.SpringBrowserlessTest;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.textfield.TextField;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
 
@SpringBootTest
@WithMockUser(roles = "ADMIN")
class PostListViewTest extends SpringBrowserlessTest {
 
    @Test
    void showsAllPosts() {
        navigate(PostListView.class);
        Grid<Post> grid = findInView(Grid.class).single();
        assertEquals(3, test(grid).size());
        assertEquals("Hello, Vaadin", test(grid).getCellText(0, 0));
    }
 
    @Test
    void filtersByTitle() {
        navigate(PostListView.class);
        test(findInView(TextField.class).withPlaceholder("Search by title").single()).setValue("grid");
        assertEquals(1, test(findInView(Grid.class).single()).size());
    }
 
    @Test
    void newPostButtonOpensForm() {
        navigate(PostListView.class);
        test(findInView(Button.class).withText("New post").single()).click();
        assertTrue(getCurrentView() instanceof PostFormView);
    }
}
MethodWhat it does
navigate(View.class)Opens a view, like navigating in the browser
findInView(Type.class)Finds components inside the current view (find(...) searches the whole UI)
.withText(...), .withCaption(...), .withPlaceholder(...)Filters by button text, field label or placeholder
.single()Exactly one component found, otherwise an error
test(component)Gives a "tester": click(), setValue(...), size()
getCurrentView()The view open right now

@SpringBootTest starts the whole application with Spring and the H2 database, so the grid has the same three posts from DataLoader. @WithMockUser(roles = "ADMIN") runs the test as an administrator.

Testing the form

// src/test/java/com/example/blog/views/PostFormViewTest.java (test method)
@Test
void todoInTitleIsRejected() {
    navigate(PostFormView.class);
    TextField title = findInView(TextField.class).withCaption("Title").single();
    test(title).setValue("TODO write intro");
    test(findInView(TextField.class).withCaption("Author").single()).setValue("Oleg");
    test(findInView(Button.class).withText("Save").single()).click();
 
    assertTrue(title.isInvalid());
    assertEquals("Remove TODO from the title", title.getErrorMessage());
}

The class is set up the same way as PostListViewTest. The test types a forbidden title, clicks "Save" and checks that the field is marked with our error text.

Running

./mvnw test
# output shortened
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 -- in com.example.blog.views.PostFormViewTest
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 -- in com.example.blog.views.PostListViewTest
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS

The first test takes about 15 seconds while Spring starts, the rest take fractions of a second. These tests cannot check the look, CSS or behavior in a real browser; for that there is the paid Vaadin TestBench or Playwright.

Common mistake

You forgot @WithMockUser, and the view is closed with @PermitAll. The test fails:

java.lang.IllegalArgumentException: Navigation resulted in unexpected class com.example.blog.views.LoginView instead of com.example.blog.views.PostListView

Without a user, Vaadin redirected the test to the login page, like a real visitor. Add @WithMockUser with the needed role to the test class or method.

Thanks for reading!

Donate to the site — we work hard for you.