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.
No Comments