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);
}
}| Method | What 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 SUCCESSThe 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.PostListViewWithout 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.