DEV Community

cuongld2
cuongld2

Posted on • Edited on

Serenity automation framework - Part 2/4 - Automation Test with UI using Cucumber

Hi folks, I'm back with another post.

Please check out this for previous post about Serenity.

At its core, Serenity is all about BDD.
The philosophy of Serenity is to make the test like a live documentation.
In this blog post I will share you guys how to implement UI test in Serenity with Cucumber and ScreenPlay Pattern.

And don't forget, how to create beautiful and detailed report like this:

Alt Text

I.Why Cucumber

Cucumber is a software tool used by computer programmers that supports behavior-driven development (BDD). Central to the Cucumber BDD approach is its plain language parser called Gherkin. It allows expected software behaviors to be specified in a logical language that customers can understand.

By using cucumber, we separate the intent of the tests from how it will be implemented.

Non-technical guys like BA or PO can easily understand what we are testing from feature file like


Feature: Allow users to login to quang cao coc coc website

  @Login
  Scenario Outline: Login successfully with email and password
    Given Navigate to quang cao coc coc login site
    When Login with '<email>' and '<password>'
    Then Should navigate to home page site
    Examples:
      |email|password|
      |xxxxxxxxxx|xxxxxxxxxx|

  @Login
  Scenario Outline: Login failed with invalid email
    Given Navigate to quang cao coc coc login site
    When Login with '<email>' and '<password>'
    Then Should prompt with '<errormessage>'
    Examples:
      |email|password|errormessage|
      |a|FernandoTorres12345#|abc@example.com|

```



II.Implementation

We will go through the needed setup for implement test using Cucumber with Serenity.

1.POM file

We would need to use serenity-cucumber for our project.
So make sure to add dependency for that:



````javascript

        <!-- https://mvnrepository.com/artifact/net.serenity-bdd/serenity-cucumber -->
        <dependency>
            <groupId>net.serenity-bdd</groupId>
            <artifactId>serenity-cucumber</artifactId>
            <version>1.9.45</version>
        </dependency>

```
{% endraw %}


Also we need to add some plugins to build serenity report with maven
{% raw %}


````javascript

<plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.0</version>
                <configuration>
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.18</version>
                <configuration>
                    <includes>
                        <include>**/features/**/When*.java</include>
                    </includes>
                    <systemProperties>
                        <webdriver.driver>${webdriver.driver}</webdriver.driver>
                    </systemProperties>
                </configuration>
            </plugin>
            <plugin>
                <groupId>net.serenity-bdd.maven.plugins</groupId>
                <artifactId>serenity-maven-plugin</artifactId>
                <version>${serenity.maven.version}</version>
                <executions>
                    <execution>
                        <id>serenity-reports</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>aggregate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>

```



2.Serenity config file

In order to set the default config for serenity, we can use serenity.conf file or serenity.properties

In this example I would like to show you about serenity.conf:



````javascript

webdriver {
  base.url = "https://cp.qc.coccoc.com/sign-in?lang=vi-VN"
  driver = chrome
}

headless.mode=false
serenity {
  project.name = "Serenity Guidelines"
  tag.failures = "true"
  linked.tags = "issue"
  restart.browser.for.each = scenario
  take.screenshots = AFTER_EACH_STEP
  console.headings = minimal
  browser.maximized = true
}

jira {
  url = "https://jira.tcbs.com.vn"
  project = Auto
  username = username
  password = password
}

drivers {
  windows {
    webdriver.chrome.driver = src/main/resources/webdriver/windows/chromedriver.exe
  }
  mac {
    webdriver.chrome.driver = src/main/resources/chromedriver
  }
  linux {
    webdriver.chrome.driver = src/main/resources/webdriver/linux/chromedriver
  }
}


```
{% endraw %}

We defined some common thing like where to store driver for each environment:
{% raw %}


````javascript
drivers {
  windows {
    webdriver.chrome.driver = src/main/resources/webdriver/windows/chromedriver.exe
  }
  mac {
    webdriver.chrome.driver = src/main/resources/chromedriver
  }
  linux {
    webdriver.chrome.driver = src/main/resources/webdriver/linux/chromedriver
  }
}

```



or take screenshot after each step:



````javacript

serenity {
  take.screenshots = AFTER_EACH_STEP
}


```
{% endraw %}


3.Page Object

An experienced automation test is the one who can implement the tests in an abstracted ways for better understanding and maintenaince.

For best practices of implement test in UI, we should always define page object class for the web page we are interacting with.

In the case, the web page has a lot of functions and elements, we should separate the page object into multiple one according to the features it cover for better maintenaince.

 For example with LoginPage of qcCocCoc site:
{% raw %}


````javascript

@DefaultUrl("https://cp.qc.coccoc.com/sign-in?lang=vi-VN")
public class LoginPage extends PageObject {

    @FindBy(name = "email")
    private WebElementFacade emailField;

    @FindBy(name = "password")
    private WebElementFacade passwordField;

    @FindBy(css = "button[data-track_event-action='Login']")
    private WebElementFacade btnLogin;

    @FindBy(xpath = "//form[@method='post'][not(@name)]//div[@class='form-errors clearfix']")
    private WebElementFacade errorMessageElement;

    public void login(String email, String password) {
        waitFor(emailField);
        emailField.sendKeys(email);
        passwordField.sendKeys(password);
        btnLogin.click();
    }

    public String getMessageError(){
        waitFor(errorMessageElement);
        return errorMessageElement.getTextContent();
    }


}

```



Here we define how to find the web element, and what method we would need to use in that page.

Usually, we should get rid of Thread.sleep , and find more fluent wait like in the example



````javascript

public void login(String email, String password) {
        waitFor(emailField);
        emailField.sendKeys(email);
        passwordField.sendKeys(password);
        btnLogin.click();
    }

```
{% endraw %}

In the above, we would wait for the emailField to appear, after that, we will run the next script.
If that field does not appear, a timeout error will happen.

4.Implement the test followed Cucumber:
First you need to declare the features file.
Features file should be located in test/resources/features folder:
{% raw %}


````javascript

  @Login
  Scenario Outline: Login successfully with email and password
    Given Navigate to quang cao coc coc login site
    When Login with '<email>' and '<password>'
    Then Should navigate to home page site
    Examples:
      |email|password|
      |xxxxxxxxxx|xxxxxxxxxx|

```



IntelliJ offered us the way to automatically create the function for each step
You can click on the step and press "Alt + Enter", then follow the guide

I usually put the cucumber tests in test/ui/cucumber/qc_coccoc, and define the tests in the step package:



````javascript

public class LoginPage extends BaseTest {

    @Steps
    private pages.qcCocCoc.LoginPage loginPage_pageobject;

    @cucumber.api.java.en.Given("^Navigate to quang cao coc coc login site$")
    public void navigateToQuangCaoCocCocLoginSite() {


        loginPage_pageobject.open();

    }

    @When("^Login with '(.*)' and '(.*)'$")
    public void loginWithEmailAndPassword(String email, String password) {

        loginPage_pageobject.login(email,password);

    }

    @Then("^Should navigate to home page site$")
    public void shouldNavigateToHomePageSite() {
        WebDriverWait wait = new WebDriverWait(getDriver(),2);
        wait.until(ExpectedConditions.urlContains("welcome"));
        softAssertImpl.assertAll();

    }

    @Then("^Should prompt with '(.*)'$")
    public void shouldPromptWithErrormessage(String errorMessage) {

        softAssertImpl.assertThat("Verify message error",loginPage_pageobject.getMessageError().contains(errorMessage),true);
        softAssertImpl.assertAll();


    }
}

```
{% endraw %}

Here we extend BaseTest for the benefit of using assertion
The value for email and password we put in the feature file can be gotten by using regex like @When("^Login with '(.*)' and '(.*)'$") and define input value for the function (String email, String password)
{% raw %}




````javascript

@RunWith(CucumberWithSerenity.class)
@CucumberOptions(features = "src/test/resources/features/qcCocCoc/", tags = { "@Login" }, glue = { "ui.cucumber.qc_coccoc.step" })
public class AcceptanceTest {
}

```


We should create the AcceptanceTest class for more flexible way to run tests with tags.
We need to specify the path to the features file "src/test/resources/features/qcCocCoc/", and the path to the step file: "ui.cucumber.qc_coccoc.step"

5.How to run the test

- You can run the test from feature file by right click on the scenario and choose run in the IDE

- Or you can run from command line:

mvn clean verify -Dtest=path_to_the_AcceptanceTest

6.Serenity report

To create beautiful Serenity report, just run the following command line

mvn clean verify -Dtest=path_to_the_AcceptanceTest serenity:aggregate

The test report will be index.html and located in target/site/serenity/index.html by default

The summary report will look like this:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zqf694axapezebrhcfm6.PNG)

With screenshot capture after each step in Test Results tab:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ga7v14qjt2jiyy5mivgt.PNG)


As usual, you can always checkout the sourcode from github: [serenity-guideline](https://github.com/cuongld2/serenityguideline)


Yay. That's it for today.
If you like the blog post, leave a heart or a comment.

I will write another post for screenplay pattern with UI test in a couple of days.
Take care~~

Notes: If you feel this blog help you and want to show the appreciation, feel free to drop by :

[<img src="https://thepracticaldev.s3.amazonaws.com/i/cno42wb8aik6o9ek1f89.png">](https://www.buymeacoffee.com/dOaeSPv
)

This will help me to contributing more valued contents.


Enter fullscreen mode Exit fullscreen mode

Top comments (5)

Collapse
 
luongquynh profile image
LuongQuynh

Hi Cường, I love your post.I'm a tester, I begin the study of serenity. I feel the document about serenity is a little hard to understand. Can you suggest for me the way I learn and practice proficiency the serenity? Thank you so much!

Collapse
 
cuongld2 profile image
cuongld2

Hello,
I'm really glad that my posts could help you in some way.
I feel you too. When I started learning serenity, it's a little bit hard to understand but it will get easier as you move on.
If you got the time, I strongly suggest you to checkout "BDD in action" book by Ferguson (the author of serenity). In the book, he covered the philosophy about BDD and also real world problem for Serenity to handle.
Also there are some practical example written by the serenity team, you might want to checkout : github.com/serenity-bdd/screenplay....
Happy coding!!!

Collapse
 
luongquynh profile image
LuongQuynh

Thanks a lot. I hope you have a great day :d

Collapse
 
duongnguyen271192 profile image
duongnguyen271192

Hi, really appreciate your effort. I have a question, if I have 2 test suit runners AcceptanceTest1.java and AcceptanceTest2.java and I want to run only AcceptanceTest2.java by maven, how can I do this? I tried with mvn clean verify -Dtest=path_to_the_AcceptanceTest2 but it does not work. It run both of them.

Collapse
 
cuongld2 profile image
cuongld2

Hello @duongnguyen,
I'm glad that this could help you.
Maybe you can share me the sample project you're having the issue?
From my understanding, I think it might come from configurations in the POM file.