vaadinvaadin24vaadin-testbench

Changes during UI.access() are not pushed during Unit Test


I have the following view class:

@Route(value = NewsAdminView.ROUTE)
@RequiredArgsConstructor
public class NewsAdminView extends VerticalLayout {
    public static final String ROUTE = "";
    private final NewsService service;
    final Grid<News> grid = new Grid<>(News.class);

    @Override
    protected void onAttach(AttachEvent attachEvent) {
        addComponents();

        service.getNews().subscribe(items -> updateItems(attachEvent.getUI(), items));
    }

    private void updateItems(final UI ui, final List<News> news) {
        ui.access(() -> {
            grid.setItems(news);
            grid.setEnabled(true);
        });
    }

    // Some details are omitted, like setting up the components and handling security, locale & URL parameters
}

The service executes a GraphQL query, which returns a Mono<List>, which adds the news entries to the page once it completes. The AppShellConfigurator has the necessary @Push annotation and this whole setup works once deployed and tested in browser.

But I also have this unit test, extending Vaadin TestBench unit tests:

class NewsAdminViewTest extends VaadinUnitTest { // VaadinUnitTest extends Vaadin's SpringUIUnitTest
    @MockBean
    private NewsService service;

    @BeforeEach
    void setUp() {
        news = News.builder().build();
        when(service.getNews()).thenReturn(Mono.just(List.of(news)));
    }

    @Test
    void openWithNoParameters() {
        final NewsAdminView view = navigate(NewsAdminView.ROUTE, NewsAdminView.class);

        assertThat(view.grid.isVisible()).isTrue();
        assertThat(view.grid.isEnabled()).isTrue();
        assertThat(view.grid.getDataProvider().size(new Query<>())).isEqualTo(1);
    }

When debugging I can see that my updateItems() method is called, the mocked service returned the mocked list of news entries and the items are set and the grid enabled. But the step once the access() call finishes, and the changes should be pushed to the client, is skipped. VaadinSession.unlock() is called, but VaadinSession.getUIs() is empty. And the assertions for the enabled state and the number of displayed grid rows fail.

Is this something the unit tests do not yet support, or am I missing something in my app or testing setup?


Solution

  • the reason for this is that the test method holds the UI lock. The UI lock is only released when the test function ends, which basically postpones all ui.access() calls after the test function ends, which is too late by then.

    The solution is to temporarily release the UI lock in the test function, then acquire it back. You can do it yourself by calling appropriate Vaadin functions, but there's a better way. Vaadin UI testing is based on Karibu-Testing, and you may be able to call Karibu's functions as well.

    Please see the Karibu-Testing async documentation for more details; the MockVaadin.clientRoundtrip() is the key.