Writing Selenium Web Automation tests in Fluent way!

Mohammad Faisal Khatri
16 min readAug 10, 2022

--

cover image

Introduction

Recently, I was going through some of the design patterns in java by reading the book Head First Design Patterns. It is an awesome book with lots of knowledge about multiple design patterns in java. I was searching for some examples to practice the design patterns that I had recently read about and came across a pattern over the internet called as Fluent Interface. I found it quite impressive and thought of creating an example code to write web automation tests using the fluent pattern with Selenium WebDriver.

Fluent pattern helps us write an easy-readable code which could be understood without putting efforts into technically understanding the code.

Here is an example of the code from one of the tests just to show you how easy it is to read and understand:

Register User Test

I guess you might have got a fair idea of what this test does. It will navigate to the Home Page of the Website then open the Registration Page and verify its header. Next it will register the user and verify whether registration is successful and then continue to My Account Page. The steps for continuing to My Account Page and checking its header had to be included as that marks the completion of the Registration process. Point to note here is that no test data has been passed in the tests nor in the method signature making it look clean and crisp!

Test data is been passed internally while registering the user within the registerUser() method. Details and explanation will follow in the blog, keep reading!

You see how simple and cool it is to write in a Fluent Way!

Let’s get into the deeper discussion and overview about how you too can write the tests in such a fluent fashion easily.

Before I begin writing about how I wrote the tests and discuss the code, Let me tell you about the tools and the website under test.

Tools Used

Following tools have been used in writing and running the tests:

  1. Programming Language: Java
  2. Web Automation Tool: Selenium WebDriver(latest version)
  3. WebDriverManager is used for managing the drivers.
  4. Test Runner: TestNG
  5. Build Tool: Maven

6. Proxies that can be used for running tests

Application Under Test

LambdaTest E-Commerce Playground Website is used for writing the end to end tests.

LambdaTest ECommerce Playground Website — Home Page

This website is used as it has a full end to end demo business flow from registering a user to adding and checking out the product and confirming the order. And there are multiple screens having various fields which could be automated using Selenium WebDriver.

It also gives newbies in Testing and Automation a fair idea of how to perform end to end testing.

Automation Test Strategy

Following is test automation strategy derived to test the end to end flow of the website:

  1. The User will navigate to the website.
  2. From the Home Page of the screen, user will navigate to the Registration Page and register himself. Verification will be done by asserting the registration successful message.
  3. User will click on the Shop by Category option on the top left and select a category for selecting the product to purchase.
  4. From the Product Page, the user will hover on any product which he likes and select the Add to cart option. Once a product is added to cart, assertions will be performed to check the success message displayed.
  5. On the Checkout page, user will provide the billing address details and also assertion will be made for product name and its respective price.
  6. Once a product is checked out, the user lands on the Order Confirmation page, where product name, price and shipping address will be asserted and after that Order would be marked as confirmed.
  7. Finally, an Order confirmation message would be verified in the tests which marks the end of the test journey.

Github Repository

Github Repository — selenium4poc

All of the code which is showcased above is located in this github repository.

Please checkout the following packages in the github repository for test,page objects and test data for the code described in this blog:

Test: Checkout src\test\tests\lambdatestecommerce\EndToEndWebsiteTests.java

Page Objects: Checkout src\test\pages\lambdatestecommerce package.

Test Data: Checkout src\test\data\ package.

Do mark a ⭐ and make the project popular so it reaches to the people who want to learn and upgrade and get better understanding about Web Automation with Selenium WebDriver with Java.

Getting Started

As discussed earlier, I have created this project using Maven. TestNG is used as test runner. Once the project is created we need to add the following dependencies for Selenium WebDriver, TestNG, WebDriverManager , Javafaker and Lombok in pom.xml file.

pom.xml

Versions are maintained separately inside the properties block. It helps in easy readability and maintenance of the version, as all versions are available inside one block.

properties block in pom.xml file

Residential proxies can also be used for running the automation tests as it provides enhanced user privacy and keeps the user data safe. It is important to use good reliable IPs before running tests in order to overcome IP blocks.

NodeMaven provides proxies with industry-first IP filtering. They have 95% clean proxies and help in providing super sticky sessions.

Try NodeMaven now (Use F86 at checkout to get extra 2GB of proxy)

Details about the dependencies:

  1. Selenium WebDriver: Core Selenium dependency for web automation.
  2. TestNG: This dependency helps to run the tests.
  3. WebDriverManager: This dependency carries out the driver management so you don’t have to manually download the drivers for running the tests in browsers.
  4. JavaFaker: This dependency helps in generating test data on run time.
  5. Lombok: This dependency helps in automatically generating getters, setter and builders so you can get rid of writing lengthy java classes and boilerplate code.

End to End Tests

Before we begin and start with the steps used for writing the tests in a Fluent way, there are some basic things that need attention so it helps you in better understanding. A combination of following things are used in this project and I hope you have a basic understanding as a prerequisite:

  1. Page Object Model is used for maintaining Page Objects and fluent pattern is used for writing tests.
  2. Builder Pattern is used for test data generation.

Let’s begin with the tests now. We discussed the the test automation strategy in the earlier section of this blog.

Let’s start implementing it step by step.

Test 1: User Registration

To start the tests we need to navigate to the website, open the registration page and register the user and perform some assertions to check what we did was correct.

Here is the first test of this project:

Register User Test

There are multiple questions that would be appearing in your mind, like what does the Website look like, what does the Registration Page look like and what fields/locators are we working on?

Here is how the Home Page of the LambdaTest ECommerce Playground looks like:

LambdaTest ECommerce Playground Website — Home Page

Here is the screenshot of the Registration Page which opens after navigating to My Account >> Registration link from the above page.

LambdaTest ECommerce Playground Website — Registration Page

We need to first find the locators for the Home Page and then move on to the Registration page.

HomePage Class

registerLink() and selectCategory() methods are returning the Web Elements which are actually locators for these respective fields.

openMyAccountMenu() will click on My Account link and shopByCategory() method will click on Shop by Category link. Both of these methods are part of the fluent pattern and will return the instance of the Home Page class. The beauty of return this; is, it will allow performing method chaining.

openUserRegistrationPage() will return a new instance of the Registration Page class once the user clicks on the register link. This will allow chaining the methods in the Registration Page with this page’s methods.

Note: A static constructor has been created in every class, so we don’t have to instantiate the respective page object classes and use static methods by importing it directly in the test class.

Next, we need to focus on the Registration Page and take care of the process to register the user. For registration, we need to find the locators of the Register user form and provide the necessary test data so it could be filled in automatically when the test runs every time and we can get rid of manually changing the test data every time to generate a new registered user.

RegistrationPage Class

First thing first we need to do is to check if we have landed on the correct page by checking the page header if it displays Register Account. verifyPageHeader() method performs this check by locating the element of the page header and then checking it with the expected text we have provided for assertion.

There are multiple fields which need to be filled in for registering the user in the system. firstNameField(), lastNameField() , emailField() , telephoneField() , passwordField() are mandatory fields required to be filled in to register user. So, respective methods returning the respective locators have been created in th RegistrationPage class.

verifyPageHeader() will locate the element for page header and will compare it with the expected header — “Register Account”. This method is a part of the fluent pattern and will return an instance of the Registration Page class.

Before we execute the registerUser() method we need to have the data available readily so it could be input in the respective fields. For doing this, the RegisterUserData class is used. This class has respected variables which are mandatory for registering a user.

RegisterUserData Class

Notice the @Getter and @Builder annotations which are put on top of the class name. These are annotations provided by Lombok.

@Getter annotation will provide all the getter methods on run time.

@Builder annotation helps us for using the Builder Pattern without writing the boiler plate code.

You see, how simple it is to use the builder pattern by just providing an annotation to the top of the class using Lombok. However, we are yet not done for data generation, we need to build the data and we would be using JavaFaker library to generate data on runtime to use it in our tests.

TestDataBuilder Class will take care of building the data for us.

TestDataBuilder class — getRegisterUserData() method

getRegisterUserData() method will return a set of data required for the mandatory fields for registering a user.

When registerUser() method is executed it will invoke getRegisterUserData()method and generate the required data on run time and help in registering the user and once the user is registered successfully it will return a new instance of the Registration Success Page as this is the next page that would be displayed on the screen once registration is successful.

There is nothing much to detail out in Registration Success Page class, verifySuccessfulRegistration() method will actually check for the locator of the success message, get its text and will compare with the expected message “Your Account Has Ben Created!” provided in the method and this will be done using the assertEquals() provided by TestNG. Finally this method will return the instance of MyAccount Page class.

RegistrationSuccessPage Class

The continueToMyAccount() method will click on the continue button displayed on the Registration Success Page and return a new instance of MyAccount Page Class.

MyAccountPage Class — verifyPageHeader() method

On the My Account Page we are just verifying that the page header My Account is correctly displayed. With this, our test for registering the user ends.

Now, it makes sense to read the following code and understand what it is actually doing!

Test 2: Add Product to Cart

Next, we move on to check the second business scenario by adding a product to Cart. Here is the test for it:

Add Product to Cart Test

Since we are writing end to end tests, it makes sense to add the dependsOnMethods attribute to this test as it is dependent on the registered user. Though adding a product to cart is allowed as a guest user as well, however at the time of checking out, the system will ask the user to register to continue, so it is good if we start the test journey as a registered user.

LambdaTest ECommerce Playground Website — Product Page

In this test, from the Home Page we would be navigating to Product Page by clicking on Shop by Category link and selecting Components category, then we would be adding Palm Treo Camera Lens to cart and verify the success message(this assures that the product was added successfully to the cart) and finally we move on to Checkout Product page to checkout the product.

HomePage Class — shopbyCategory() method

shopByCategory() method takes in the link name as parameter, clicks on that respective link provided which in our case is Components and returns a new instance of Product Page.

ProductPage class — addPalmTreoCameraLensToCart() method

We need to select a product to add it to the cart, for this, we would be selecting the Palm Treo Camera Lens and will add it to the cart. This part is a bit tricky as the option to add the product to cart is displayed after hovering over the product. Hence to do this, Selenium’s Actions class has been used as it provides the flexibility to chain UI actions and help us in doing the same manual action which the user would be doing, in an automated way.

The screenshot of addPalmTreoCameraLensToCart() method above is self explanatory as it does the exact action which we discussed in the above paragraph. Note that this method will return the instance of Product page and help us chain this method with other methods of Product Page class.

Product page class — verifySuccessMessage() method

To verify that the product is added successfully to the cart and confirm that the actions which we did above are doing what they are expected to do, we would be verifying the success message in the next step.

Note here, MessageFormat class is used to format the expected message and make it look more readable and concise. Finally we would be moving ahead to checkout the product next.

Product Page class — checkoutProduct() method

The checkoutProduct() method from Product Page class returns a new instance of Checkout Page class after clicking on the Checkout Button displayed on the Success Message on Product Page. This marks the completion of our test 2.

Let’s now focus on the next test to checkout the product.

Test 3: Checkout Product

LambdaTest ECommerce Playground Website —Product Checkout Page

In this test we will check the Checkout Product page and verify its functionality of checking out the product successfully.

Checkout Product Test

This test depends on the testAddProductToCart() test, if the previous test is successful then only this test will be executed otherwise it will be skipped.

We would be storing the unit price of the camera lens in a global variable named unitPricePfCamerLens in the first step of this test as it will help us to use this value in asserting the unit price on the order confirmation page.

CheckoutPage Class — getUntPriceOfCameraLens() method

Next, on the Checkout Page, we would be setting the billing address and checking out the product.

Again, for setting the billing address Builder Pattern has been used and test data is generated using the JavaFaker library which actually eases the pain of handling test data on run time.

Billing Data Class

For Billing Data, the mandatory fields required to fill in the form are:

  1. First Name
  2. Last Name
  3. Address Line one
  4. City
  5. PostCode
  6. State
  7. Country

We have taken these fields into consideration and created a Billing Data class and added the annotations @Getter and @Builder which will help for using this class with Builder Pattern. The skeleton of the data is created. Let’s move on now to generate the test data which will be taken care of in Test Data Builder class.

Test Data Builder class — getBillingData() method

getBillingData() method will return a set of data required for the mandatory fields for setting the Billing address required to be entered before checking out the product.

CheckoutPage class — setBillingAddress() method

When the setBillingAddress() method is executed it will invoke getBillingData()method and generate the required data on run time.

Once the billing address is set, next we would be moving ahead to checkout the product by clicking on the agree terms and condition checkbox and clicking on the Continue button to proceed to the Order Confirmation page.

CheckoutPage class — checkoutProduct() method

Test 4: Confirm Order Test

Now its time to confirm the order we have placed using the previous test.

LambdaTest ECommerce Playground Website — Confirm Order Page

On this page we would be doing some assertions and verifying that the product we selected previously is only the one we are checking out along with the price that we saw in the initial stage of adding the product page. Also, we would be verifying the shipping address that we added while checking out the product.

Confirm Order Test

The verifyPageHeader() method has been created to assert the page header so it confirms that we are on the correct page before we proceed to run our next steps of assertions. This method returns an instance of Confirm Order Page class so we could use it by chaining with other methods of the same class.

ConfirmOrderPage class— verifyPageHeader() method

The verifyProductName() method asserts the product name to check we are ordering the correct product. This method also returns the instance of Confirm Order Page class so it would be easy to fluently use this method by chaining it with other methods of the same class(Confirm Order Page class).

ConfirmOrderPage class — verifyProductName() method

Do you remember we had saved the unit price of the test class by creating a global variable called unitPriceOfCameraLens? Now, we would be passing that variable in the verifyUnitPrice() method parameter and this value will be compared with the value we would be fetching for the unit price of the product from the Order Confirm page.

ConfirmOrderPage class — verifyUnitPrice() method

Next we need to make sure that the Billing address we have entered in the previous step is correctly displayed in the Shipping Address section of the Order confirmation page. TheverifyShippingAddress() method will assert the billing address. This method will take BillingData as a parameter as we would be passing the same instance of billing data that we used for setting the billing address. It actually helps in setting and getting the same data and eases our task of asserting the address.

ConfirmOrderPage class — verifyShippingAddress() method

After the shipping address is verified we will be moving ahead with confirming the order. confirmOrder() method will click on the Confirm Order button and help us in confirming the order.

ConfirmOrderPage class — confirmOrder() method

Test 5: Order Success Test

We have completed almost our test journey with the last step remaining where we need to check if the order that we placed has been successfully through.

Order Success Test

In this test we will be verifying the success message displayed on the Order Success Page after we confirm the order.

OrderSuccessPage class — verifySuccessMessage() method

Once the verification of the success message is done, we would be clicking on the Continue button which will help us navigate to the Home Page marking the end of our test journey.

OrderSuccessPage class — continueToHomePage() method

Running the Tests

There are 2 ways to run the tests, those are as follows:

Note: parameter name: browser should be provided in the testng.xml file where browser name like “chrome” should be provided.

  1. TestNG:
Right-Click on the `test-suite\testng-lambdatestecommerce.xml` and select Run \test-suite\testng-lambdatestecommerce.xml
Running the tests using TestNG Runner

2. Maven

To run the tests in headless mode update the value for `headless` property variable to `true`

mvn clean install -Dsuite-xml=test-suite\testng-lambdatestecommerce.xml -Dheadless=true

To run the tests without headless mode(to see the test running in browser) update the value for `headless` property variable to `false`

mvn clean install -Dsuite-xml=test-suite\testng-lambdatestecommerce.xml -Dheadless=false

Conclusion

In this blog, we discussed writing the selenium web automation tests in a fluent way. We used LambdaTest Ecommerce Playground website to run an end to end test journey where we registered a new user and passed the registration data using builder pattern, next we moved on to add a product to cart then checkout and finally confirm order and verified that the order was successfully placed.

I hope you enjoyed reading the blog and learnt something new from this, please provide your feedback in the comments below, it would be helpful for me to learn and grow as well.

If you need any help, do reach out to me for assistance, I would be happy to help.

Happy Testing!

Freelance Work / Paid Trainings/Mentoring

Contact me for Paid trainings/Mentoring related to Test Automation and Software Testing, ping me using any of the social media site listed on LinkTree or email me @mohammadfaisalkhatri@gmail.com.

--

--

Mohammad Faisal Khatri

QA with 14+ years of experience in automation as well as manual testing. Freelancer, blogger and open source contributor.