Webtau browser. module lets you interact with a browser. It provides higher level abstractions to locate elements, encapsulate page implementation details and deal with async nature of modern UIs. Groovy package scenarios.ui import static org.testingisdocumenting.webtau.WebTauGroovyDsl.* import static pages.Pages.* scenario("search by specific query") { search.submit("search this") search.numberOfResults.waitToBe > 1 } package pages import static org.testingisdocumenting.webtau.WebTauDsl.* class SearchPage { def welcomeMessage = $("#welcome") def searchMessage = $("#message") def box = $("#search-box") def results = $("#results .result") def numberOfResults = results.count def submit(query) { browser.open("/search") box.setValue(query) box.sendKeys(browser.keys.enter) } } package pages class Pages { static final def search = new SearchPage() } Java package com.example.tests.junit5; import org.junit.jupiter.api.Test; import org.testingisdocumenting.webtau.junit5.WebTau; import static com.example.tests.junit5.pages.Pages.*; import static org.testingisdocumenting.webtau.WebTauDsl.*; @WebTau public class WebSearchJavaTest { @Test public void searchByQuery() { search.submit("search this"); search.numberOfResults.waitToBe(greaterThan(1)); } } package com.example.tests.junit5.pages; import org.testingisdocumenting.webtau.browser.page.PageElement; import org.testingisdocumenting.webtau.browser.page.PageElementValue; import static org.testingisdocumenting.webtau.WebTauDsl.*; public class SearchPage { private final PageElement box = $("#search-box"); private final PageElement results = $("#results .result"); public final PageElementValue<Integer> numberOfResults = results.getCount(); public void submit(String query) { browser.open("/search"); box.setValue(query); box.sendKeys(browser.keys.enter); } } package com.example.tests.junit5.pages; public class Pages { public static SearchPage search = new SearchPage(); }