Serenity Ensure – Fluent Assertions in Serenity Screenplay
Assertions are an important part of any test automation framework, and Serenity gives us many options. You can of course use standard JUnit, Hamcrest or AssertJ assertions at any point in a Screenplay test. But more recent versions of Serenity Screenplay provide an alternative approach, which many developers find easier to use and faster to write: the serenity-ensure
module.
Introducing serenity-ensure
The Ensure
class produces a Performable
, so you can integrate them directly into the attemptsTo()
method. It also has a very readable DSL and lets you use code completion to discover the assertions you can use for different values, making writing assertions easier and quicker.
An example of code equivalent to the above can be seen here. Suppose you have an input field on your HTML form to enter the age, which you have identified in your Screenplay test using a Target
:
Target AGE_FIELD = Target.the("Age field").locatedBy("#age");
Using serenity-ensure
, you could check the value of this field using the Ensure.that()
method, like this:
...
sam.attemptsTo(
Ensure.that(AGE).value().isEqualTo("40")
);
Getting started with serenity-ensure assertions
To add serenity-ensure
to your project, you need to add a new dependency, as shown here for Maven:
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-ensure</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
The starting point for all serenity-ensure
assertions is the net.serenitybdd.screenplay.ensure.Ensure
class.
From here, you use the Ensure.that()
method, passing the value you want to check. This can be an actual value (String, Integer, LocalDate etc), a Screenplay Question, or a web element locator. The actual assertions available can be different for different data types, and this is one of the things that makes serenity-ensure
so convenient to use: Once you have entered Ensure.that(someValue)
in your IDE, you can use auto-complete to explore the range of available assertions for that type. There are over a hundred different assertion methods, covering web elements, Strings, Dates and Times, integer and floating point numbers, and collections. You can see the full set of assertions in the Serenity Documentation, but let's take a look at some of the highlights.
Working with assertions about web elements
The serenity-ensure
module has a rich range of assertions related to web elements. We have already seen some of these in the previous code. Other assertions include isDisplayed() and isEnabled(). We can use either a Target instance directly, or use the ElementLocated.by() method to specify a Target, a By locator, or a CSS or XPath expression. For example:
aster.attemptsTo(
Ensure.that(ElementLocated.by("#firstName")).isDisplayed()
);
You can use methods like value(), text() or textContent() to read from a web element. Once you have obtained the value, you can use a range of String assertions, such as startsWith() shown here:
aster.attemptsTo(
Ensure.that(FIRST_NAME).value().startsWith("Joe")
);
Working with assertions about collections
We often need to reason about collections of values, rather than just individual values. We can use methods like values() and textContentValues() to make assertions about collections of web elements. For example:
aster.attemptsTo(
Ensure.that(ElementLocated.by("#colors option"))
.values()
.contains("red","blue","green") );
We can also make assertions about the elements themselves. TheMatchingElement
class gives us a set of methods to make assertions about these elements, and methods such as allMatch(), anyMatch() and noneMatch() complete the picture:
aster.attemptsTo(
Ensure.thatTheSetOf(ElementsLocated.by(".train-line"))
.allMatch(TheMatchingElement.containsText("Line"))
);
Converting types
We can also use converter methods such as asAnInteger(), asADouble, or asADate() to convert the String value returned by WebDriver into a form more convenient to make assertions on. For example, we could refactor the code we saw earlier to reason about the age value as an integer like this:
... sam.attemptsTo( Ensure.that(AGE).value().asAnInteger().isGreaterThan(18) );
Alternatively, if you wanted to make an assertion about a date or a time, you could write code like the following:
aster.attemptsTo(
Ensure.that(ElementLocated.by("#currentDate"))
.value()
.asADate("dd-MM-yyyy")
.isBefore(dateLimit)
);
Want to learn more?
This is just a very brief taster of what the serenity-ensure
module can do. You can read the full documentation for the serenity-ensure
module here. If you want to learn more about Serenity Screenplay, you can follow the introductory tutorial here. Or if you prefer video tutorials and guided exercises, the Serenity Dojo Screenplay Course will be getting a module on serenity-ensure
later this week.