Web UI tests reinforcement with webtau framework (Selenium based)
Tags: selenium, testing, groovy, java
Published: 2019-08-13 14:22:40

---
title: Web UI tests reinforcement with webtau framework (Selenium based)
published: true
description: 
tags: selenium, testing, groovy, java
---

One of the biggest problem with Web UI tests is their brittleness. Moving a page element around or replacing an input box with a drop down can cause a ripple effect that breaks dozens of your tests.

In this article I will show you how to encapsulate your UI implementation details so your tests can focus on testing features.

I will be using the [webtau framework](https://github.com/twosigma/webtau) that has primitives designed to help with tests brittleness

# First test attempt

Let’s test a search feature of an imaginary app.

```groovy
scenario('search by specific query') {
    browser.open('/search')

    $('#search-box').setValue('search this')
    $('#search-box').sendKeys("\n")

    $('#results .result').count.shouldBe > 1
}
```

Test:

* open a search page
* set a value to an input box that can be located by search-box id
* simulate enter key and check that there are some results

I claim that there should be only one reason to change this test and that is if the actual functionality of your search experience changes ([Single Responsibility Principle anyone?](https://en.wikipedia.org/wiki/Single_responsibility_principle)).

However there are four non functional reasons that can force our test to change:

* search page url changes
* the way we initiate the search changes: enter key vs mouse click
* ids/classes/attributes associated with elements are changed
* server response time becomes slower

Let’s address them one by one.

# Extract elements definition

In [webtau](https://github.com/twosigma/webtau) `$(css)` creates an instance of `PageElement` that you use to simulate user actions and query values.

Created instances are lazy and can be defined before the browser is even opened.

```groovy
def searchBox = $('#search-box')
def numberOfResults = searchBox.count

scenario('search by specific query') {
    browser.open('/search')

    searchBox.setValue('search this')
    searchBox.sendKeys("\n")

    numberOfResults.shouldBe > 1
}
```

This is a step in a right direction, but we still have exposed page url and hardcoded *Enter* key press.

# Extract user actions

Let’s create a submit method to encapsulate the way users are supposed to initiate the search.

```groovy
def searchBox = $('#search-box')
def numberOfResults = searchBox.count

scenario('search by specific query') {
    submit('search this')
    numberOfResults.shouldBe > 1
}

def submit(query) {
    browser.open("/search")

    searchBox.setValue(query)
    searchBox.sendKeys("\n")
}
```

I think the changes we made make the test easier to reason about. But I still want to give it a final touch: move definitions out of a test file so they can be potentially used by other test scenarios.

# Encapsulation

Let’s move the action and page elements definitions to a separate class. You may have heard of the [PageObject](https://martinfowler.com/bliki/PageObject.html) concept before.

In [webtau](https://github.com/twosigma/webtau) page objects are simple class instances. It is the lazy nature of `PageElement` that makes this simplicity possible.

```groovy
package pages

import static com.twosigma.webtau.WebTauDsl.*

class SearchPage {
    def searchBox = $('#search-box')
    def numberOfResults = $('#results .result').count

    def submit(query) {
        browser.open("/search")

        searchBox.setValue(query)
        searchBox.sendKeys("\n")
    }
}
```

It doesn’t matter when we create the instance of the class since `searchBox` and `numberOfResults` will be lazily initiated.

Let’s create the `Pages` class with static page object instances to make it convenient to access them from different scenarios.

```groovy
package pages

class Pages {
    static final def search = new SearchPage()
    static final def calculation = new CalculationPage()
    static final def form = new FormPage()
}
```

Our page object is one import away.

```groovy
import static pages.Pages.*

scenario("search by specific query") {
    search.submit("search this")
    search.numberOfResults.shouldBe > 1
}
```

# Dealing with asynchronous brittleness

Our test is now reinforced and can sustain UI non-functional changes. But there is one unprotected area left uncovered.

During local development our server is blazingly fast and search results are produced in under 5ms. Weeks later we will run the tests in QA environment and most likely we will be dealing with the failed assertion.

Let’s do a final test reinforcement.

```groovy
import static pages.Pages.*

scenario("search by specific query") {
    search.submit("search this")
    search.numberOfResults.waitToBe > 1
}
```

We replaced `shouldBe` with `waitToBe`. As a result, instead of failing the assertion right away waitTo will re-query `numberOfResults` multiple times until it times out (driven by configuration).

# Groovy, Java and beyond

I have been using [Groovy](http://groovy-lang.org/) for testing for the last decade and I think it is perfect for the job. But if you are not a [Groovy](http://groovy-lang.org/) fan, you can use Java or other JVM languages.

If you are interested in Java or other JVM examples, please hit me in the comments and I will be happy to help.

# Links

[GitHub](https://github.com/twosigma/webtau)

[Introduction to REST API testing with webtau](https://dev.to/mykolagolubyev/introduction-to-concise-and-expressive-rest-api-testing-framework-webtau-56m1)