Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Тесты экранов

Экран 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 с нужной ролью на класс или на метод теста.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.