Page Object Model in Cucumber
By Kailash Pathak, Community Contributor - September 23, 2022
Page Object Model is a design pattern commonly used in enterprise test automation that makes an object repository for web UI elements. It helps us to cut back duplication and improves test maintenance.Test Automation helps in achieving this with better accuracy and in a shorter period of time, keeping product release cycles shorter.
How does Page Object Model (POM) work?
We can break POM into two-parts (PO+ M)
In POM we create objects of page class and by using this object we are able to interact with web elements and also the method of page class.
In POM each page within the web application contains a corresponding Page Class that includes the Web Elements and the Methods which operate on those Web Elements.
Benefit of Page Object Model
1. Code Re-usability: POM increases code reusability. Teams can write common methods which can be used for various pages. for instance, if there’s a date functionality that’s used on a different page. So, we will create a common method to handle the date functionality and use the identical for every page class.
2. Code Readability: POM Improves readability because of clean separation between test code and page-specific code as each web page has its individual class file to store its Locators, Methods, and Test Steps.
- The page class file contains methods, and related locators for the specific web page,
- The Test class file contains related test steps for a specific web page. For example, we have a home web page for which we can create 2 class files:
- Page class : homePage.js: which contains locators and methods related to the home page
- Test Class (homeTest.spec.js): It contains test steps related to the home page
3. Code Maintenance: Code maintenance is easy with POM. just in case any change comes we are able to directly change the code at the method level (the common method) and updates will reflect everywhere.
Read More: Cucumber Best Practices for testing
What is Cucumber and BDD?
Cucumber is a testing tool that supports behavior-driven development (BDD). BDD aqueduct the space between business stakeholders and also the technical team through a standard platform and communication among the team becomes more transparent.
Gherkin language is used to write the test cases in a very simple format and even be read and modified by a non-technical user.
In BDD, “Given-When-Then” is the suggestive approach for creating test cases.
Here is an example for better understanding:
Given the user has entered valid credentials When a user clicks on the sign-in button Then validates the content on the home page after login
Implementing POM with Cucumber and Cypress
Implement POM (Page Object Model) using the Cucumber and Cypress using the below high-level steps for Cypress installation
Step 1: Create a folder and Generate package.json
- Create a project, here naming it as cypress_cucumber_updated
- Use npm init command to create package.json file
Step 2: Install Cypress
To install Cypress, still, in the project folder, run > npm install cypress — save-dev
Once installed, Cypress version 9.7.0 is reflected as seen below
Must Read: How to Run Tests with Cypress and Cucumber
Installing Cucumber
Step 1: To install cucumber run this command run > npm install — save-dev cypress-cucumber-preprocessor
Once installed, Cucumber devDependency in package.json can be seen as below
Step 2: Add below code snippet in cypress > plugins > index.js
const cucumber = require("cypress-cucumber-preprocessor").default; module.exports = (on, config) => { on("file:preprocessor", cucumber()); };
Step 3: Add the below code snippet in package.json
"cypress-cucumber-preprocessor": { "nonGlobalStepDefinitions": true }
Step 4: Add the below line in cypress.json
{ "testFiles": "**/*.feature" }
Create a Folder Structure
Step 1: Create folder POM inside “Integration/examples”. Under POM create further TWO folder names Tests and Pages
Step 2: Create two subfolders for Home and log-in test under the Pages and Tests folder
Step 3: Now Create Two Feature files for Home and Login with name (HomeTest.feature, LoginTest.feature)
Create Feature files
In the first test case, we want to login with the valid and invalid user
Write the below code under the LoginTest.feature file attached below
Feature: I want to login into the site with valid and invalid data and search T-shirt Background: Given I navigate to the Website Scenario: Login as new sign up user with valid data When I entered valid crediential | email | validpassword | | qatubeupdate@yopmail.com | 12345 | When User click on sign in button Then Validate the title after login Scenario: Login as new sign up user with invalid data When I entered invalid crediential | email | invalidpassword | | qatubeupdate@yopmail.com | 123456 | When User click on sign in button Then Error message should display | errormessage | | Authentication failed |
In the second test case, we have to verify the links after successful login
Write the below code under the HomeTest.feature file attached below
Feature: I want open the Site and verify links in Home Page Background: Given I navigate to the Website Scenario: Verify content in Home Page When I views links in Home Page of the Site | HomePageLinks | | Contact us | | Sign in | | Women | | Popular | | Best Seller | | Cart |
Create Page Class
We have created our feature file above now we need to create our page classes
Create loginPage.js class to cover login with valid/ invalid user scenario
Here we created Methods for enterUrl,enterUserNamePassword,clickOnSignInButton and validateErrorMessage() and we have exported the login object.
We will use these methods in our page class
/// <reference types ="cypress"/> class LoginPage { enetURL() { cy.visit("http://automationpractice.com/"); } enterUserNamePassword(username, password) { cy.contains("Sign in").click(); cy.get("#email").clear(); cy.get("#email").type(username); cy.get("#passwd").clear(); cy.get("#passwd").type(password); return this; } clickOnSignInButton() { return cy.get("#SubmitLogin").click(); } verifyPageTitle() { return cy.title().should("eq", "My account - My Store"); } validateErrorMessage(errorMessage) { return cy.contains(errorMessage); } } const login = new LoginPage(); export default login;
- In line #4 we have created the enterUrl() method to enter the site URL
- In line #7 we have created the enterUserNamePassword() method to enter the username and password on the login screen
- In line #15 we have created clickOnSignInButton() method to click on Sign-in button,In line #18 we have created verifyPageTitle() method to verify page title after login
- In the line #21 we have created validateErrorMessage() method to verify the error message when the user enters an invalid username and password,
- In line #26 we are creating the object of login (*After this we need not create the object in the test class) and in #27 We are just exporting the object.
Create a homePage.js class to verify the contents on the Home page after login
/// <reference types ="cypress"/> class HomePage { searchItem(element) { cy.contains(element.HomePageLinks).should("be.visible"); return this; } } const homepage = new HomePage(); export default homepage;
In line #4 we have created searchItem() method to verify links on the home page
In line #9 we are creating the object of the homepage (*After this we need not create the object in the homePagetest class)
Create Test Class
Methods in page class are already created, now will use these methods in the Test class. Create loginTest.spec.js class to cover scenario login with valid/ invalid user
**NOTE: Make sure when creating a test class, “Given”, “When” and “Then” mapping should be the same as given in the respective feature file
import login from "../../Pages/LoginPage/loginPage"; // Scenario 1 : Login with Valid crediential Given("I navigate to the Website", () => { cy.visit("http://automationpractice.com/"); }); When("I entered valid crediential", (datatable) => { datatable.hashes().forEach((element) => { login.enterUserNamePassword(element.email, element.validpassword); }); }); When("User click on sign in button", () => { login.clickOnSignInButton(); }); Then("Validate the title after login", () => { login.verifyPageTitle(); }); // Scenario 2 : Login with Invalid crediential and Verify error messsage When("I entered invalid crediential", (datatable) => { datatable.hashes().forEach((element) => { login.enterUserNamePassword(element.email, element.invalidpassword); }); }); When("User click on sign in button", () => { login.clickOnSignInButton(); }); Then("Error message should display", (datatable) => { datatable.hashes().forEach((element) => { login.validateErrorMessage(element.errormessage); }); });
Create homeTest.spec.js class to verify the link on the home page
import homePage from "../../Pages/HomePage/homePage"; Given("I navigate to the Website", () => { cy.visit("http://automationpractice.com/"); }); When("I views links in Home Page of the Site", (datatable) => { datatable.hashes().forEach((element) => { homePage.searchItem(element); }); });
Run Test Class
Run the test class using the following command:
yarn run cypress open
Both the feature files HomeTest.feature and LoginTest.feature can be seen. You can run either of these features or both of them.
Running Test in Cucumber
Passed Test Result
Failed Test Result
In the below screenshot we can see the test case is failed also in log in THEN part we can see the message “Authentication failed” is displaying
Conclusion
POM design pattern makes these test automation frameworks user-friendly by keeping tests and the element locators separate. It supports code reuse and code maintenance where changes to the UI for locating the elements are confined to the automation code only, without affecting the automated test cases.
Using Cucumber in the POM design pattern makes test cases more readable and easy to understand for the non-technical user.
Follow-Up Read: Cross Browser Testing Using Cucumber