#GivenWhenThenWithStyle

How to write good UI interaction tests?

This time, we’re looking into one of the most common pain points with Given-When-Then: writing automated tests that interact with a user interface. People new to behaviour driven development often misunderstand what kind of behaviour the specifications should describe, and they write detailed user interactions in Given-When-Then scenarios. This leads to feature files that are very easy to write, but almost impossible to understand and maintain.

Here is the challenge

Here’s a typical example:

Scenario: Signed-in users get larger capacity

Given a user opens https://www.example.com using Chrome
And the user clicks on "Upload Files"
And the page reloads
And the user clicks on "Spreadsheet Formats"
Then the buttons "XLS" and "XLSX" show
And the user clicks on "XLSX"
And the user selects "500kb-sheet.xlsx"
Then the upload completes
And the table "Uploaded Files" contains a cell with "500kb-sheet.xlsx" 
And the user clicks on "XLSX"
And the user selects "1mb-sheet.xlsx"
Then the upload fails
And the table "Uploaded Files" does not contain a cell with "1mb-sheet.xlsx" 
And the user clicks on "Login"
And the user enters "testuser123" into the "username" field
And the user enters "$Pass123" into the "password" field
And the user clicks on "Sign in"
And the page reloads
Then the table "Uploaded Files" contains a cell with "500kb-sheet.xlsx" 
And the table "Uploaded Files" does not contain a cell with "1mb-sheet.xlsx" 
And the user clicks on "spreadsheet formats"
Then the buttons "XLS" and "XLSX" show
And the user clicks on "XLSX"
And the user selects "1mb-sheet.xlsx"
Then the upload completes
And the table "Uploaded Files" contains a cell with "1mb-sheet.xlsx" 
And the table "Uploaded Files" contains a cell with "500kb-sheet.xlsx"

A common way to avoid such issues is to rewrite the specification to avoid the user interface completely. We’ve looked into that option several times in this article series. However, that solution only applies if the risk we’re testing is not in the user interface, but somewhere below. To make this challenge more interesting, let’s say that we actually want to include the user interface in the test, since the risk is in the UI interactions.

Solving: How to write good UI interaction tests?

Last week, you voted on options for fixing a broken user-interface interaction test.

We’re very glad to have a guest expert this time. Andy Knight, blogging as Automation Panda, took the challenge on and provided a comprehensive answer on his blog.

The community had some great ideas as well this week. Here are some of the best responses.

Ken Pugh suggested to “Think in terms of user functionality, not specific clicks”, and abstracting away individual user interface actions that could be then implemented using step definitions. He provided an example of how that could look.

Gaspar Nagy proposed something similar, particularly looking at the causes of the risks that the tests are supposed to be protecting against:

I definitely would dig deeper into that risk. The risk is in the UI integrations, but in what nature?

A: Is it that fragileness of the UI interaction solution causes our users to not be able to get the business value (e.g. they cannot register, because of a js glitch). In this case I would use (some) business-language scenarios and automate them through the UI (or to the UI as well). But other non-BDD tests, like UI smoke tests or approval tests would work also fine.

B: If the risk is if we understood the UI interaction properly and whether our solution solves the right expectation (E.g. the validation of the new user name happens instantly even before submitting the registration form.), then UI interaction terms can sneak into the scenario. But even in this case I would try to focus on the UI concepts, not the individual HTML elements, so I would say “When I provide my user name as ‘foobar’” instead of “When I type ‘foobar’ into the text box ‘tbUserName’”.

Christian Quirós proposed “You re-write the specification layer (feature file) to avoid implementation details and to describe the system behavior instead, then, you have multiple implementations of the automation layer.” He suggested applying Hexagonal Architecture, a pattern to isolate the business domain and provide abstractions for interactions, where a feature file can be “driving the application through the UI by using another step definition implementation”. This is an excellent approach for situations when we want to hide UI details from the specification but still execute tests through the UI. Christian also proposed applying the Screen Play pattern to restructure the user interactions in terms of required behaviours.