Тесты экранов
Экран Vaadin — это Java-объект, поэтому его можно проверить обычным JUnit-тестом, без браузера. Библиотека browserless-test создаёт поддельную сессию Vaadin, открывает экран, находит на нём компоненты и «нажимает» их. Такие тесты работают за секунды и ловят большинство ошибок в логике экранов.
Зависимости
<!-- 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>Версию browserless-test-spring задаёт BOM Vaadin. Последняя зависимость нужна, чтобы запускать тесты от имени пользователя с нужной ролью.
Тест списка статей
// 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("Привет, Vaadin", test(grid).getCellText(0, 0));
}
@Test
void filtersByTitle() {
navigate(PostListView.class);
test(findInView(TextField.class).withPlaceholder("Поиск по заголовку").single()).setValue("табл");
assertEquals(1, test(findInView(Grid.class).single()).size());
}
@Test
void newPostButtonOpensForm() {
navigate(PostListView.class);
test(findInView(Button.class).withText("Новая статья").single()).click();
assertTrue(getCurrentView() instanceof PostFormView);
}
}| Метод | Что делает |
|---|---|
navigate(Экран.class) | Открывает экран, как переход в браузере |
findInView(Класс.class) | Ищет компоненты внутри текущего экрана (find(...) — во всём UI) |
.withText(...), .withCaption(...), .withPlaceholder(...) | Фильтр по тексту кнопки, подписи или подсказке поля |
.single() | Ровно один найденный компонент, иначе ошибка |
test(компонент) | Даёт «тестер»: click(), setValue(...), size() |
getCurrentView() | Экран, открытый сейчас |
@SpringBootTest поднимает всё приложение со Spring и базой H2, поэтому в таблице те же три статьи из DataLoader. @WithMockUser(roles = "ADMIN") выполняет тест от имени администратора.
Тест формы
// src/test/java/com/example/blog/views/PostFormViewTest.java (тестовый метод)
@Test
void todoInTitleIsRejected() {
navigate(PostFormView.class);
TextField title = findInView(TextField.class).withCaption("Заголовок").single();
test(title).setValue("TODO написать введение");
test(findInView(TextField.class).withCaption("Автор").single()).setValue("Олег");
test(findInView(Button.class).withText("Сохранить").single()).click();
assertTrue(title.isInvalid());
assertEquals("Уберите TODO из заголовка", title.getErrorMessage());
}Класс устроен так же, как PostListViewTest. Тест вводит запрещённый заголовок, жмёт «Сохранить» и проверяет, что поле подсвечено ошибкой с нашим текстом.
Запуск
./mvnw test# вывод сокращён
[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Первый тест идёт около 15 секунд — поднимается Spring, остальные — доли секунды. Проверить внешний вид, CSS и работу в настоящем браузере такие тесты не могут; для этого есть платный Vaadin TestBench или Playwright.
Частая ошибка
Забыли @WithMockUser, а экран закрыт @PermitAll. Тест падает:
java.lang.IllegalArgumentException: Navigation resulted in unexpected class com.example.blog.views.LoginView instead of com.example.blog.views.PostListViewБез пользователя Vaadin перенаправил тест на страницу входа, как настоящего посетителя. Добавьте @WithMockUser с нужной ролью на класс или на метод теста.