What is Serenity BDD?
Serenity BDD is an open source library that aims to make the idea of living documentation a reality.
Serenity BDD helps you write cleaner and more maintainable automated acceptance and regression tests faster. Serenity also uses the test results to produce illustrated, narrative reports that document and describe what your application does and how it works. Serenity tells you not only what tests have been executed, but more importantly, what requirements have been tested.
One key advantage of using Serenity BDD is that you do not have to invest time in building and maintaining your own automation framework.
Serenity BDD provides strong support for different types of automated acceptance testing, including:
- Rich built-in support for web testing with Selenium.
- REST API testing with Rest Assured.
- Highly readable, maintainable and scalable automated testing with the Screenplay pattern.
Getting started Cucumber 6 with Serenity BDD
Cucumber is a popular tool for automating BDD-style acceptance criteria.
Serenity seamlessly supports for Cucumber 2.x, Cucumber 5 and Cucumber 6. However, this flexibility requires a little tweaking in the build dependencies.
If you are using Maven, you need to do the following:
- exclude the default cucumber-core dependency from your serenity-core dependency
- Replace your serenity-cucumber dependency with the serenity-cucumber5 dependency
- Add dependencies on the Cucumber 5.x version of cucumber-java and cucumber-junit into your project
Serenity BDD Cucumber 5 sample scenario
Project Structure

Relationship between Web Application, Serenity BDD, Cucumber and Selenium

Scenario
- Launch new Browser and open – https://opensource-demo.orangehrmlive.com
- Enter valid Username and Password in Login Page
- Click on Login Button in Login Page to move to next DashBoard Page
- Verify DashBoard page is open
- Enter invalid credentials and verify the error message
Sample Feature File
Feature: Login to HRM
@ValidCredentials
Scenario: Login with valid credentials
Given User is on Home page
When User enters username as "Admin"
And User enters password as "admin123"
Then User should be able to login successfully
@InValidCredentials
Scenario Outline: Login with invalid credentials
Given User is on Home page
When User enters username as '<username>'
And User enters password as '<password>'
Then User should be able to see error message '<errorMessage>'
Examples:
|username |password |errorMessage |
|admin |admin |Invalid credentials |
| |admin123 |Username cannot be empty |
|Admin | |Password cannot be empty |
| | |Username cannot be empty |
Lean Page Objects and Action Classes
The glue code shown below uses Serenity step libraries as action classes to make the tests easier to read, and to improve maintainability.
These classes declare using the Serenity @Steps annotation. The @Steps annotation tells Serenity to create a new instance of the class, and inject any other steps or page objects that this instance might need.
Each action class models a particular facet of user behavior: navigating to a particular page, performing a search, or retrieving the results of a search. These classes design to be small and self-contained, which makes them more stable and easier to maintain.
HomePageDefinition contains the steps to open the web browser, enter username, enter password and click on Login Button
import net.thucydides.core.annotations.Step;
import net.thucydides.core.annotations.Steps;
public class HomePageDefinition {
@Steps
StepLoginPage loginPage;
@Steps
StepDashboardPage dashPage;
@Given("User is on Home page")
public void openApplication() {
loginPage.open();
System.out.println("Page is opened");
}
@When("User enters username as {string}")
public void enterUsername(String userName) {
System.out.println("Enter Username");
loginPage.inputUserName(userName);
}
@When("User enters password as {string}")
public void enterPassword(String passWord) {
loginPage.inputPassword(passWord);
loginPage.clickLogin();
}
@Then("User should be able to login successfully")
public void clickOnLoginButton() {
dashPage.loginVerify();
}
@Then("User should be able to see error message {string}")
public void unsucessfulLogin(String expectedErrorMessage) throws InterruptedException {
String actualErrorMessage = loginPage.errorMessage();
Assert.assertEquals(expectedErrorMessage, actualErrorMessage);
}
}
This annotation lets you define a URL or a set of URLs that work with a particular page.
@DefaultUrl("https://opensource-demo.orangehrmlive.com/")
StepHomePage is created by extending it from PageObject class. In this class, $() method used below, which locates a web element using a By locator or an XPath or CSS expression. This class is responsible for uniquely locating elements on the page, and it does this by defining locators or occasionally by resolving web elements dynamically.
import net.serenitybdd.core.annotations.findby.By;
import net.serenitybdd.core.pages.PageObject;
import net.thucydides.core.annotations.DefaultUrl;
@DefaultUrl("https://opensource-demo.orangehrmlive.com/")
public class StepLoginPage extends PageObject {
@Step("Enter Username")
public void inputUserName(String userName) {
$(By.name("txtUsername")).sendKeys((userName));
}
@Step("Enter Password")
public void inputPassword(String passWord) {
$(By.name("txtPassword")).sendKeys((passWord));
}
@Step("Click Submit Button")
public void clickLogin() {
$(By.name("Submit")).click();
}
@Step("Error Message on unsuccessful login")
public String errorMessage() {
String actualErrorMessage = $(By.id("spanMessage")).getText();
return actualErrorMessage;
}
}
StepDashboardPage is also created by extending Page Object Model. Here, we are verifying the Dasboard page
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import org.openqa.selenium.By;
import net.serenitybdd.core.pages.PageObject;
public class StepDashboardPage extends PageObject {
public void loginVerify() {
String dashboardTitle = $(By.id("welcome")).getText();
assertThat(dashboardTitle, containsString("Welcome"));
}
}
WebDriver Configuration
Serenity uses the serenity.conf file in the src/test/resources directory to configure test execution options. serenity.config can also contain WebDriver binaries that you need to run Selenium tests in the src/test/resources/webdriver directories.
webdriver {
driver = firefox
use.driver.service.pool = false
}
drivers {
windows {
webdriver.chrome.driver = "src/test/resources/webdriver/window/chromedriver.exe"
webdriver.gecko.driver = "src/test/resources/webdriver/window/geckodriver.exe"
webdriver.ie.driver = "src/test/resources/webdriver/window/IEDriverServer.exe"
}
mac {
webdriver.chrome.driver = "src/test/resources/webdriver/mac/chromedriver"
webdriver.gecko.driver = "src/test/resources/webdriver/mac/geckodriver"
}
linux {
webdriver.chrome.driver = "src/test/resources/webdriver/linux/chromedriver"
webdriver.gecko.driver = "src/test/resources/webdriver/linux/geckodriver"
}
}
Test Runner – CucumberRunnerTest
We cannot run a Feature file by its own in cucumber based framework. We need to create a Java class, which will run the Feature File. It is the starting point for JUnit to start executing the tests. TestRunner class creates under src/ test/java. When you run the tests with serenity, you use the CucumberWithSerenity test runner. If the feature files are not in the same package as the test runner class, you also need to use the @CucumberOptions class to provide the root directory where the feature files found
import org.junit.runner.RunWith;
import io.cucumber.junit.CucumberOptions;
import net.serenitybdd.cucumber.CucumberWithSerenity;
@RunWith(CucumberWithSerenity.class)
@CucumberOptions(plugin = { "pretty" }, features = "src/test/resources/features/LoginPage.feature")
public class CucumberRunnerTest {
}
Executing the tests
You can run the tests from CucumberRunnerTest or from command line by
mvn clean verify
By default, the tests will run using Chrome. You can run them in Firefox by overriding the driver system property, e.g.
$ mvn clean verify -Ddriver=firefox
The test execution status looks like something this

The test report generated by Serenity places under target/site/serenity/index.html.

An example of the correctly configured dependencies shown below:
<name>Sample Serenity BDD project using Cucumber</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<serenity.version>2.2.0</serenity.version>
<serenity.maven.version>2.2.0</serenity.maven.version>
<serenity.cucumber.version>2.2.0</serenity.cucumber.version>
<encoding>UTF-8</encoding>
<tags></tags>
<parallel.tests>4</parallel.tests>
<webdriver.base.url></webdriver.base.url>
</properties>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>bintray</name>
<url>https://jcenter.bintray.com</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>bintray-plugins</name>
<url>https://jcenter.bintray.com</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<!--
- To use Cucumber 4, exclude the old Cucumber 2 cucumber-core dependency from the serenity-core dependency
- and include the Cucumber 4 cucumber-java and cucumber-junit dependencies.
-->
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-junit</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-screenplay</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-screenplay-webdriver</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-cucumber5</artifactId>
<version>${serenity.cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<includes>
<include>**/Test*.java</include>
</includes>
<systemPropertyVariables>
<webdriver.base.url>${webdriver.base.url}</webdriver.base.url>
</systemPropertyVariables>
<parallel>classes</parallel>
<threadCount>${parallel.tests}</threadCount>
<forkCount>${parallel.tests}</forkCount>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>net.serenity-bdd.maven.plugins</groupId>
<artifactId>serenity-maven-plugin</artifactId>
<version>${serenity.maven.version}</version>
<configuration>
<tags>${tags}</tags>
</configuration>
<dependencies>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>${serenity.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>serenity-reports</id>
<phase>post-integration-test</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Informative blog on Serenity. Great example
LikeLike
Thank You. There are other posts on Serenity using SpringBoot testing and Rest Assured. Please have a look
LikeLike
Hello Vibha ,
Kindly I am using serenity framework , i have issue with my project , can’t execute my tests via feature file , or test runner , the console doesn’t show a clear description of the error , can you share your email so i can send you screenshots of my POM ?
Best regards
LikeLike
Sure. You can send screenshots at qaautomation.expert@hotmail.com
LikeLike