First steps
TUI is a Java library that helps building and testing web UI by using Java code only.
In this chapter we will see how to create a dynamic page, how to provide it, and how to test it.
Creating a page
Here is an example to create a new page made of one section containing a paragraph:
Page page = new Page("Index", "/index");
Section chapter1 = page.append(new Section("Title for first chapter"));
chapter1.appendParagraph("Here is my text...");
Now that our page is ready, we want it to be shown. The first way to get it done is by exporting this page as a static HTML file:
Style style = new Style();
HTMLNode htmlNode = page.toHTMLNode(new Page.Resource(false, style.toCSS()), null);
String html = htmlNode.toHTML();
// 'html' string can be put in a .html file.
Note that we must instantiate a Style. This object gives the CSS content for the page to be styled in any web browser. If you want to change spaces, colors, borders, you can customize the Style instance with its methods. The Style instance is given in a Resource that tells that it is embedded into the HTML content of the page (isExternal=false). If we wanted the style to be served as a CSS file by the backend of our application, then we would have set the Resource as external.
An other way to provide our page is to use a server application. You may already have your favorite backend solution, but here we will see how it goes using TUI's backend which is initially design for test purpose.
final TUIBackend backend = new TUIBackend(8000);
backend.registerPage(page);
backend.start();
If you run this program, you will be able to see our page by browsing to http://localhost:8000/index
Making it interactive
Now we want to make our page adapt its content against user's actions. Let's say we want our page to help finding pricing data from a large number of items located by their cities.
A page is made of components. Almost any component has the ability to be refreshed within the page without the need for reloading the entire page. One thing more, some components handle the user's actions to trigger updates.
Let's create a new page, which will display a list of items from the database. We don't want to see all the items at once, so the page gives a field that can be used to filter the items.
Page page = new Page("Items", "/items");
Search search = page.append(new Search("Search of items", "Go", "nameContains"));
Table table = page.append(new Table("Found items", List.of("Reference", "Name", "Price")));
Note how components are created and added to the page at the same time.
The constructor of Search component takes 3 parameters: the title, the label of the button, and the name of the parameter that will be sent to the backend.
Now we add what will make our page really dynamic:
table.setSource("/table");
search.connectListener(table);
The first line tells that the table can be refreshed, its content given by web service '/table'. The second line tells that the table will be refreshed each time the user validates the search.
Because the refresh of the table is triggered by the Search component, the '/table' web service will be called with additional parameter 'nameContains' which value will be the string entered by the user in the Search input.
Let's put some data into our backend:
record Item(String reference, String name, double price_Euro) {}
final List<Item> allItems = new ArrayList<>();
for(int i = 0; i < 50; i++) {
allItems.add(new Item(String.format("I%012d", (int) (Math.random() * 1_000_000_000.0)), TestUtils.getRandomCityName(),
Math.random() * 10_000.0));
}
The list 'allItems' will act as a database. Now we implement the web service that is expected to refresh the table component:
backend.registerWebService("/table",
(uri, request, response) -> {
final RequestReader reader = new RequestReader(request);
final String nameContains = reader.getStringParameter("nameContains", "");
final Table filteredTable = new Table(table.getTitle(), table.getColumns());
allItems.stream()
.filter((item) -> nameContains.trim().isEmpty() || item.name.contains(nameContains))
.forEach((item) -> filteredTable.append(
Map.of("Reference", item.reference, "Name", item.name, "Price",
String.format("%.2f €", item.price_Euro))));
return filteredTable.toJsonMap();
});
Our page is ready to run. Launch the main of the class OverviewExample and try it by yourself.
Automated testing
Let's summarize. Our page contains a table that aims at displaying information of a list of items, and a 'search' component that acts like a filter for the table.
We will see now how to perform this test case:
- ARRANGE: prepare a complete list of items.
- ACT: enter some value in the 'search' and submit.
- ASSERT: check that only filtered items are displayed in the table.
We have already coded how to create a bunch of items, we will re-use that code for the ARRANGE phase.
Now in the ACT phase, we want to use the 'search' component. First of all, we need to open the page, and we do that with a TClient:
final TClient client = new TClient(8000);
client.open(page.getSource());
The TClient will replace a web browser in our test. It is a light client implementation that almost behaves like a real browser running the TUI's javascript. The main difference is that the TClient doesn't manage any style.
Let's try the filter with an empty value. We will expected to get all the items.
final TSearch search = client.getSearch("Search of items");
search.enterInput("nameContains", ""); // will select all items
search.submit();
We can then add a simple assertion to check that now the table is loaded with all the items:
TTable table = client.getTable("Found items");
assertEquals(50, table.size());
And we can go further and check the filtering functionality of our page by checking that all items of the table match the filter (the following code may not be accurate for a real test, but it shows capabilities):
// Testing with one filter -> the table should only contain filtered values
search.enterInput("nameContains", "al");
search.submit();
table = client.getTable("Found items");
assertFalse(table.isEmpty());
for(List<Object> row : table.getRows()) {
final String name = row.get(1).toString();
assertTrue(name.contains("al"));
}
You can find a running version of that code in the test class OverviewExample.