The pages the tests drive
A UI test needs a screen to drive. In DomUI those screens are not hidden in the
test sources: they are pages of the demo application, in
to.etc.domui.demo, reachable from its home page under "JUnit/Selenium Test
pages".
That is on purpose. The pages have two jobs, and they do both well:
- they put a component in the exact situation a test wants to check - a mandatory field that is empty, two bindings that depend on each other, a dialog inside a dialog;
- they are the worked examples of what a testable page looks like, next to the test that drives them. Every code fragment in this section comes from them.
The groups
Package under pages/test |
What it holds | Tests |
|---|---|---|
uitest |
the order entry page this documentation is written around | ITOrderEntry, ITOrderEntryPageObject |
proxies |
one page with every component that has a page object proxy | ITTestProxiesPage1 |
binding |
pages where data binding has to do something exactly right | ITTestBindingOrder, ITTestBuildOrder, ITBindValidationError, ITBindErrors1 |
componenterrors |
components in their error and layout states | ITTestText2Layout, ITTestText2Behavior, ITTestForm4Layout, ITTestLookupInput2, ITTestLookupInput2Layout, ITTestSearchPanel, ITTestHtmlEditorComponent |
msgbox |
the message box in each of its shapes | ITTestMsgBox |
rxjava |
a page-bound rxjava subscription and its disposal | - |
The last one has no test of its own: it is driven by hand, because what it checks is what happens when you walk away from the page.
Two of them are worth reading before writing a test of your own.
Build order. DomUI builds nodes lazily: createContent() of a component
runs while the page is being rendered. If a binding were evaluated at the
moment its component is built, a binding reading a property of a component that
is not yet built would read a value that is about to change.
BuildOrderPage sets that situation up and ITTestBuildOrder asserts that
bindings run after every build is done.
Binding order. TestBindingOrder1 has a country and a city combo that
depend on each other: changing the country must change the city, and the
binding that then runs for the city must not undo it. The test changes each of
them and checks that the other followed.
The page the tests here are written against
OrderEntryTestPage in pages/test/uitest: a form of three controls, a basket
as a DataTable with a link button per row, and an answer that changes when
something is ordered.
public class OrderEntryTestPage extends UrlPage {
@Override
public void createContent() throws Exception {
ContentPanel cp = new ContentPanel();
add(cp);
cp.add(new HTag(1, "Order entry"));
Div answer = new Div("dm-tut", NOTHING);
answer.setTestID("answer");
Text2<String> customer = new Text2<>(String.class);
customer.setMandatory(true);
ComboFixed2<Shipping> shipping = ComboFixed2.createEnumCombo(Shipping.class);
shipping.setValue(Shipping.Standard);
Text2<Integer> copies = new Text2<>(Integer.class);
copies.setValue(1);
FormBuilder fb = new FormBuilder(cp);
fb.label("Customer").control(customer);
fb.label("Shipping").control(shipping);
fb.label("Copies").control(copies);
...
DataTable<BasketLine> table = new DataTable<>(new SimpleListModel<>(basket), rr);
table.setTestID("basket");
cp.add(table);
}
}
Everything a test asserts on is fixed: three albums with fixed prices, a shipping cost per option, one copy to start with. The page never queries the database.
Adding one
- Put it in the demo, in the package of the group it belongs to, and link
it from
JUnitTestMenuPageso it can be reached by hand. A fixture nobody can open is a fixture nobody can debug. - Make it deterministic. Fixed data, no
new Date(), no random order, no dependency on how many rows a query happens to return today. The demo database is there when a test needs one, but a page that can do without it is a test that cannot break on the data. - Set a testid on everything the test must find and that has no obvious
calculated name - the containers especially, since a
Divnever gets one by itself. - Keep it small and one-subject. A page that shows one thing going wrong is worth more than a page that shows twelve things at once, because the screenshot of a failing test on it is readable.
- Follow the ordinary page rules: content inside a
ContentPanel, controls in local variables and not in fields, current components only. A fixture page is read as an example whether it was meant as one or not.
