Skip to main content

E2E Testing

For End-to-end testing we use Selenium.  

Before building and running the test, for running tests with Chrome make sure you have the Chrome/Chrmoium driver installed. See Installing Chrome driver.

Page Object Models

Make sure you understand Page Object Models clearly before starting writing tests. This will make the code much more modular and easier to test.

Writing tests

Naming tests

For tests, we follow the format

UNIT_UNDER_TEST should RESULT when CONDITION

For example

 @RepeatedTest(NUMBER_OF_TESTS)
 fun `bill should be set paid when set paid button is clicked`()

All tests names should have this format. Use back-tick (`)  in function name to be able to enter spaces.

What to test

End-to-end tests should NOT test everything in the system. They should test the critical path (most common case) and corner cases. Google 70-20-10 rule is a good guide to follow.

Resting the Database

For big projects like Medico, to reset the database, we have API endpoints in the main project to set the database in a known condition. If you do not have access to the main project, ask the tech lead for the changes you need.

Write stable tests

E2E can be very flickering. To minimise this, before doing any action in a test (simulate a click on a button), wait for a (reasonable) condition to happen, e.g. waif for button to be clickable.

Tests should be fast

While you need to wait for a condition to be met, NEVER wait for an arbitrary time without a condition, for example, wait for 1 second after opening a page to load a list. Instead, in this case you should for the list root view or for the something unique to the list to be clickable (or visible).

Use IDs and Classes correctly

HTML IDs are unique (only 1 item should have the ID) while classes are not. As such, normally IDs will contain the item ID. For example, invoices in list would have IDs such as invoice-list-item-<INVOICE_ID>.    

Be careful that items might seem to be preset only once but they are not. For example a dismiss button in a dialog is present once, but there might be multiple dialogs at the same time. As such, the button should have a class instead of an ID.

Our DSL

We have a few helper functions to make testing easier. Some of these are 

fun WebDriver.findByIdWaiting(id: String, timeOutInSeconds: Long = 3)

Find an element by ID and wait until it is clickable.

fun WebDriver.findByClassWaiting(className: String, timeOutInSeconds: Long = 3)

Find an element by Class and wait until it is clickable. Will return only 1 element.

fun WebDriver.waitForStalenessOf(element: WebElement)

Wait until an element is invisible.

fun WebDriver.waitUntilClickable(locator: By)

Wait until an element is clickable.