Quality Engineering
min read
December 1, 2022
October 17, 2022

Implementing Page Object Model in Cypress

Implementing Page Object Model in Cypress
Table of contents

Page Object Model is an object design pattern that is popularly used in test automation for a better testing experience. In this technique, a Page class is created for each web page of the application. This Page class contains web elements and methods for action to be performed on these web elements. These web elements and methods are accessed by test cases, which are written in a separate Test class file.

Consider that you need to perform login action before booking a flight and viewing the itinerary. The login function is common for both booking flights and viewing itinerary scenarios. Instead of writing login web elements and methods in each page class, we can create one login page class, and reuse it in other page classes.

Cypress, a popular automation framework,  provides features to support Page Object Model. In this article, we will cover the setup and end-to-end flow for the Page Object Model using Cypress (version 10).

Cypress E2E Page Object Model

To demonstrate the working of the page object model in Cypress, we will use newtoursdemosite as a demo site. We will implement the 'Login' scenario in this example. Let's start!

Step 1

Create a 'pageobjects' folder under the 'cypress' folder of the project, which will store the page classes.

Step 2

Create a page class 'loginPage.js' under the 'pageobjects' folder. In 'loginPage.js', we will store the web elements and write methods to perform login functionality. 

Cypress POM - 1

Step 3

In loginPage.js, create a 'loginPage' class that we will export to the test spec file using 'export'.

Inside the class, create an object named 'elements'. 'elements' object contains a set of key and value pairs for locating web elements on the login page. 


class loginPage{

  elements = { 
       usernameInput : () => cy.get('input[name="userName"]'),      
       passwordInput : () => cy.get('input[name="password"]'),    
       loginBtn : () => cy.get('input[name="submit"]'),
       successTxt : () => cy.get('h3'),
       errorTxt : () => cy.get('span')
   }
}

export default loginPage;


Then write methods for the following actions:

  • Enter username
  • Enter password
  • Click Submit

class loginPage{

   elements = { 
       usernameInput : () => cy.get('input[name="userName"]'),      
       passwordInput : () => cy.get('input[name="password"]'),    
       loginBtn : () => cy.get('input[name="submit"]'),
       successTxt : () => cy.get('h3'),
       errorTxt : () => cy.get('span')
   }

   enterUsername(username)
   {
       this.elements.usernameInput().clear();
       this.elements.usernameInput().type(username);
   }

   enterPassword(password)
   {
       this.elements.passwordInput().clear();
       this.elements.passwordInput().type(password);
   }
  
   clickSubmit() {
       this.elements.loginBtn().click();
   }

}

export default loginPage;

 

Step 4

Create a 'tests' folder under the 'e2e' folder, which will store all test cases. Now, create a test spec file 'verifyLogin.spec.cy.js' under the 'tests' folder.

Cypress POM - 2

Note: For the cypress version below 10, create a 'tests' folder under 'integration'.

Step 5

Import loginPage.js class to access its methods. Then create an instance of the loginPage.js class and call the respective methods.


import loginPage from '../../pageobjects/loginPage'

describe('POM Test', () => {

 beforeEach(function() {
   // executes prior each test within it block
   cy.visit('https://demo.guru99.com/test/newtours/login.php');
})

 it('Verify Login successful', () => {
   const loginObj = new loginPage();
   loginObj.enterUsername('selenium@qa')
   loginObj.enterPassword('qa@12345')
   loginObj.clickSubmit();
   loginObj.elements.successTxt().should('have.text','Login Successfully');
 })

 it('Verify Login unsuccessful for invalid username/password', () => {
   const loginObj = new loginPage();
   loginObj.enterUsername('selenium')
   loginObj.enterPassword('qa@123')
   loginObj.clickSubmit();
   loginObj.elements.errorTxt().should('contain','Enter your userName and password correct');
 })
})

Step 6

Run the test in Cypress

Cypress POM - 3

Using Getter and Setter

You need to create a "get" and "set" command to define Object accessors. The advantage of using getter and setter is that we can use them as properties instead of functions.

 

Without Getter

With Getter

loginObj.enterUsername('selenium@qa')

loginObj.username.type('selenium@qa')

loginPage.js class file


class loginPage{

   get username()
   {
       return cy.get('input[name="userName"]');
   }

   get password()
   {
       return cy.get('input[name="password"]');
   }

   get submit()
   {
       return cy.get('input[name="submit"]');
   }

  get successText()
   {
       return cy.get('h3');
   }

   get errorText()
   {
       return cy.get('span');
   }

}

export default loginPage;


verifyPage.spec.cy.js class file


import loginPage from '../../pageobjects/loginPage'

describe('POM Test', () => {

 beforeEach(function() {
   // executes prior each test within it block
   cy.visit('https://demo.guru99.com/test/newtours/login.php');
})

 it('Verify Login successful', () => {
   const loginObj = new loginPage();
   loginObj.username.type('selenium@qa')
   loginObj.password.type('qa@12345')
   loginObj.submit.click();
   loginObj.successText.should('have.text','Login Successfully');
 })
})


Test result

Cypress POM - 4

Note: Find the sample code snippets for these features in the GitHub repository here.

Conclusion

Go ahead and implement Page Object Model using Cypress in your project. And improve test readability, and code maintainability, and reduce code duplication.

Happy Testing!

Written by
Editor
No art workers.