Step By Step Page Object Model in Cypress with Examples

Page Object Model, commonly known as POM, is a popular pattern in any automation framework. Page Object Model can be applied in Cypress too. Page Object Model has many advantages in creating a framework for test automation, such as reducing code duplication and increasing maintainability and readability. Cypress provides us the flexibility to incorporate Page Object Model in the test script. In this article, we will look at creating a Page Object Model in Cypress step by step with examples.

Table of Contents:

cypress page object model
Cypress Page Object Model

What is Page Object Model?

Page Object Model is a design pattern where the page objects are separated from the automation test scripts. Automation testing gives us many leverages that benefit us in testing; however, there are some outcomes such as code duplication and an increase in the risk of maintainability as the project grows. Let us understand the significance of POM with an example.

Consider we have multiple pages in our application like Login Page, Registration Page, and Book Flights page.

  • The Login page contains all the web elements of the login functionalities
  • The Registration contains all the methods and web elements of the registration process
  • The Book flights contain the web elements of the flight booking page

There are three test cases, namely TC1, TC2, and TC3.

  • TC1 contains the login test cases.
  • TC2 contains login and registration test cases
  • TC3 contains login, registration, and flight booking test cases
Flight booking
Example without POM

Now, the login page interacts with TC1.

Registration page needs to interact with TC1 and TC2, and

The flight booking page needs to interact with TC1, TC2, and TC3

As you can see, there are common functionalities between all three test cases. Instead of writing the methods and locators of login in all the test case files, we can have them separately and access them across the files. This way, the code is not repeated, and it is easily readable.

One of the best practices in coding is a concept called DRY. It means Do Not Repeat Yourself. As the full form clearly says, we should not repeat the lines of code again and again. To overcome this, Page Object Model plays an important role in best coding practices.

Page Object Model Framework Architecture

The page object model framework architecture is a proven architecture that can customize with simple methods. Today, almost all companies follow agile methodologies, which involve continuous integration, development, and testing. The automation testers maintain the test framework to work alongside the development process with the Page Object Model. It is a significant design pattern in maintaining the automation test framework as the code grows with new features.

The page object is a design pattern that is an object-oriented class that interacts with the pages of the application we are testing. Page Object comprises of Page Class and Test casesPage class consists of methods and locators to interact with the web elements. We create separate classes for every page in the application. We will be creating individual methods for each functionality and access them in our spec file.

Page Class
Page Object Model

Advantages of using Page Object Model in Cypress

  1. The methods are reusable across the whole project and easy to maintain when the project grows. The lines of code become less readable and optimized.
  2. Page Object Pattern suggests that we separate the operations and flow that we are performing in the UI from verification steps. When we follow the POM pattern, we tend to write clean and easily understandable code.
  3. With the Page Object Model, objects and test cases are independent of each other. We can call the objects anywhere across the project. This way, if we are using different tools like TestNG/JUnit for functional testing or Cucumber for acceptance testing, then it is easily accessible.

Step By Step Page Object Model Cypress with Example

This section will understand how to create a Page Object Model in Cypress with real-time examples that we can implement in projects. We will understand from the basic setup and step-by-step process for creating a Page Object Model.

Let’s discuss the scenario on which we will write the functions in this example.

  1. Navigate to https://admin-demo.nopcommerce.com/ website
  2. Enter valid username and password
  3. Click on the Login Button
  4. Validate the URL whether it is appended with /admin after login

We will be creating two files – one PageObject file and one spec file for this example. Let us begin!

Step 1: Open our project in VS code. Create a folder called PageObject under the integration folder. Under this folder, you can create page object files for any modules.

anysnap 26 aug 2021 at 7 08 10 pm
New folder named PageObject

Step 2: Create a file named LoginPage.js under the PageObject folder. In LoginPage.js, we will be writing the methods that involve the login functionalities.

anysnap 26 aug 2021 at 8 33 13 pm
LoginPage.js creation under PageObject folder

Step 3: Let’s start writing our first test method in the LoginPage.js file. We have to first create a class that we will be exporting in our spec file. We will call our class as LoginPage

class LoginPage {
}

Based on our pseudocode, our first step is to navigate to the URL. We will call our method as navigate(). Inside our navigate method, we shall add the cy.visit() function from Cypress.

 navigate() {
        cy.visit('https://admin-demo.nopcommerce.com/')
    }

anysnap 26 aug 2021 at 8 51 29 pm
navigate method

Step 4: Now, we will have to enter the username in our email field. We will name our method as enterEmail(). First, we should get the locator of the email field and access them via cy.get() command. Then we will clear the field using the clear() command and add the username using the type() command. In our method, we pass a parameter username to pass the value in the spec file. This way, we are keeping it generic to access this method if a different email id is required.

enterEmail(username) {
        cy.get('[id=Email]').clear()
        cy.get('[id=Email]').type(username);
        return this
    }

Instead of writing the cy.get() command twice in the above code, we can simply loop them with the dot operator.

  enterEmail(username) {
        cy.get('[id=Email]')
            .clear()
            .type(username);
        return this
    }

anysnap 26 aug 2021 at 9 01 21 pm 1
enterEmail method

You might have noticed return this in line 9. this indicates that the enterEmail method belongs to the particular LoginPage class. Basically, this represents the class.

Step 5: We have to create a method for passwords similar to our enterEmail method. We will call our password method as enterPassword(). Initially, we will get the locator for the password, clear the field and type the input value. We will pass a parameter to our method called pswd and access in the type() command.

enterPassword(pswd) {
    cy.get('[id=Password]')
        .clear()
        .type(pswd)
    return this
}
Screenshot 2021 08 26 at 9.54.47 PM
enterPassword method

Step 6: Our last method would be to click on the login button. We shall name our method as submit(). We will get the locator and click the button using the click() method from Cypress.

 submit() {
        cy.get('[type=submit]').click()
    }

Screenshot 2021 08 26 at 9.57.55 PM
submit method

Step 7: Now, we have to export this class to use it across our spec file. For this, we just add one line outside our class, and we can easily access it in our spec file.

export default LoginPage

Screenshot 2021 08 26 at 10.01.24 PM
export command

Hurray! We have created a Page Object file for our project. It was pretty simple and easy!

Accessing the Page Objects in the Spec file

Now let us move on to our test case file. We have to create a spec file in our integration folder. We shall call our spec file POMDemo.spec.js.

anysnap 27 aug 2021 at 12 01 59 pm
POMDemo.spec.js file creation

Step 1: To access our methods in the LoginPage.js file, we must import them into our spec file. We import by using the import statement. We should navigate to the LoginPage.js file by using ../

In our case, the path is ../integration/PageObject/LoginPage. So, the import statement will look something like the below.

import LoginPage from "../integration/PageObject/LoginPage"

Step 2: Since we use Mocha, we will write our test case inside describe() and it() block. describe() represents a test suite, and it() represents a test case. Both the blocks are a function and accept a string parameter that includes the description of the test.

describe("Cypress POM Test Suite", function () {
})

anysnap 27 aug 2021 at 12 17 00 pm
Describe block

Inside the describe block, we will write our it() by adding the description as login with valid credentials.

it("Login with valid credentials", function () {
       
    })

anysnap 27 aug 2021 at 12 20 54 pm
it block

Step 3: To access our methods from our Page object file, we should create an instance for our Login class. To create an instance for the login class, we must declare a variable and assign it to our class file using the new keyword. With the declared variable, we can easily access the methods from the Page object file.

                                               const login = new LoginPage();
anysnap 27 aug 2021 at 1 05 50 pm
Instance of a class

Note: With the variable login, we can access the methods from the Page object class. When we start typing login. , the vscode will list the suggestions of all the methods available in the LoginPage.js file. This helps us to verify that we have exported and imported our class properly!

Step 4: Let us call our navigate() method to visit the URL. This is the first action in our test case.

/// <reference types="cypress" />
import LoginPage from "./PageObject/LoginPage"
describe("Cypress POM Test Suite", function () {
    it("Login with valid credentials", function () {
        const login = new LoginPage();
        login.navigate();
    });
});

Step 5: We should enter the username in the email field. We access the enterEmail() with the login object. enterEmail() method accepts a parameter username. So we should pass the value for the username as a string in our spec file

/// <reference types="cypress" />
import LoginPage from "./PageObject/LoginPage"
describe("Cypress POM Test Suite", function () {
    it("Login with valid credentials", function () {
        const login = new LoginPage();
        login.navigate();
        login.enterEmail('[email protected]');
    })
})

Step 6: Similar to step 5, we should call our enterPassword() method by passing the password as a parameter in the string.

/// <reference types="cypress" />
import LoginPage from "./PageObject/LoginPage"
describe("Cypress POM Test Suite", function () {
    it("Login with valid credentials", function () {
        const login = new LoginPage();
        login.navigate();
        login.enterEmail('[email protected]');
        login.enterPassword('admin');
    })
})

Step 7: Next, we have to click on the login button. We will call the method submit() from our page object file.

/// <reference types="cypress" />
import LoginPage from "./PageObject/LoginPage"
describe("Cypress POM Test Suite", function () {
    it("Login with valid credentials", function () {
        const login = new LoginPage();
        login.navigate();
        login.enterEmail('[email protected]');
        login.enterPassword('admin');
        login.submit();
    })
})

Step 8: After logging in, we have to assert the URL. We will verify whether the URL is equal to the URL after login. For assertion, we will use the Chai assertion library, which is inbuilt with Cypress.

/// <reference types="cypress" />
import LoginPage from "./PageObject/LoginPage"
describe("Cypress POM Test Suite", function () {
    it("Login with valid credentials", function () {
        const login = new LoginPage();
        login.navigate();
        login.enterEmail('[email protected]');
        login.enterPassword('admin');
        login.submit();
        cy.url().should('be.equal', 'https://admin-demo.nopcommerce.com/admin/')
    })
})

anysnap 27 aug 2021 at 4 39 36 pm
Login test case

The above image represents the login test case. We were able to write a test case with a Page Object Model with very few simple steps. Now let us run the test case and see the result.

We shall open the Cypress test runner and click on the spec file and run our test case. Check this article on how to open Cypress test runner.

anysnap 27 aug 2021 at 1 41 55 pm 2
Test Result in Cypress

Hurray! We have successfully written a test case that uses Page Object Model in Cypress. We can incorporate this pattern in real-time projects. There are many ways that we can write the methods in a page object file. I have shown you an example that is standard and works for any project. You can also write only the return function in the page object file and then click and type directly in our spec file.

We will see another pattern that we can use in the project. This method will also work perfectly fine.

In this type, we will be returning only the locator function in our method and perform actions in the test file. We will write code for the same scenario we saw above.

Page Object – LoginPage.js

class LoginPage {
    navigate() {
        cy.visit('https://admin-demo.nopcommerce.com/')
    }
    enterEmail() {
        return cy.get('[id=Email]')
    }
    enterPassword() {
        return cy.get('[id=Password]')
    }
    submit() {
        return cy.get('[type=submit]')
    }
}
export default LoginPage

As we saw above, we are writing only the locator inside our function and returning them. The return represents that the particular method belongs to the class LoginPage.js. We are not adding any actions in our methods.

anysnap 27 aug 2021 at 4 48 05 pm
Page Object File example

Spec File – POMDemo.spec.js

We will look into the example of accessing the methods in the spec file.

/// <reference types="cypress" />
import LoginPage from "./PageObject/LoginPage"
describe("Cypress POM Test Suite", function () {
    it("Login with valid credentials", function () {
        const login = new LoginPage();
        login.navigate();
        login.enterEmail().clear()
        login.enterEmail().type('[email protected]');
        login.enterPassword().clear()
        login.enterPassword().type('admin');
        login.submit().click();
        cy.url().should('be.equal', 'https://admin-demo.nopcommerce.com/admin/')
    });
});

Screenshot 2021 08 28 at 7.35.20 PM
Spec file Example

Here, we call the method from the PageObject file and perform the test case actions. So first, we are calling our reference variable login and then appending it with the method enterEmail() and finally appending the action type. In our type(), we are passing the username value.

anysnap 27 aug 2021 at 1 41 55 pm 3
Test Result

As you can see, all the commands have been executed, and the test case has passed!

You can choose whichever Page Object Model suits your project and your opinion. There is no particular rule to stick to only one procedure.

How to use Fixtures as a Test Data Source in Page Object Model in Cypress?

In our Page Object Model examples, we passed the username and password value directly in either the Page Object file or directly in the test case file. This section will understand how to use fixtures in Cypress to keep the data safe and not exposed. We should try to keep all the credentials and data in one file and access them. This way, it is easy to maintain, and sensitive data like username and password are not exposed. This method is also one of the procedures that we need to follow in Page Object Pattern.

As discussed earlier, Fixture helps store data in a JSON file or excel file, or an external library like Apache POI. We will use these data by creating a variable and access them in our spec file. Let us understand with an example.

Cypress provides a folder called “fixtures.” We will create a JSON file called credentials.json under the ‘Fixtures’ folder.

Screenshot 2021 08 28 at 6.58.39 PM
JSON file creation

Let us declare our username, password, and URL values that we need to validate in a JSON format in the credentials.json file.

{
    "username" : "[email protected]",
    "password" : "admin",
    "adminUrl" : "https://admin-demo.nopcommerce.com/admin/"
}

Screenshot 2021 08 28 at 7.30.53 PM
Passing values in the credentials.json file

Accessing the values from the JSON file in the test case file

As we have defined the values in our JSON file, we will access them in our test case file using Fixtures from Cypress. We will access the JSON value with this keyword. Let’s wrap the fixture function in a before() block.

describe("Cypress POM Test Suite", function () {
 
before(function () {
        cy.fixture('credentials').then(function (testdata) {
            this.testdata = testdata
        })
})

cy.fixture(‘credentials’).then(function (testdata) { this.testdata = testdata }) – this line represents that we are passing the credentials.json file as a parameter to our cy.fixture() command. Here, we are not required to pass whether it is a JSON file. Just pass the file name alone. Later, we pass testdata as a parameter in the function and access the testdata variable using this.

/// <reference types="cypress" />
import LoginPage from "./PageObject/LoginPage"
describe("Cypress POM Test Suite", function () {
    before(function () {
        cy.fixture('credentials').then(function (testdata) {
            this.testdata = testdata
        })
    })
    it("Login with valid credentials", function () {
        const login = new LoginPage();
        login.navigate();
        login.enterEmail(this.testdata.username)
        login.enterPassword(this.testdata.password)
        login.submit();
        cy.url().should('be.equal', this.testdata.adminUrl)
    });
});

login.enterEmail(this.testdata.username) – This will fetch the username value from the credentials.json file and fill it into the email field.

login.enterPassword(this.testdata.password) – This will fetch the password value from the credentials.json file and fill it into the password field

cy.url().should(‘be.equal’, this.testdata.adminUrl) – This will get the adminUrl from the credentials.json file and validate in the assertion

Screenshot 2021 08 28 at 7.32.17 PM
Passing the data from JSON file to spec file

Now, let us run the test case for the result.

anysnap 27 aug 2021 at 1 41 55 pm 4
Test result

As we can see, the test cases have been executed and have passed. This example will help you to write a basic Data-driven test case. You can incorporate it in your project using this method. You can create new JSON files under the Fixture folder, add values related to test data, and access it across any test file.

Frequently Asked Questions

Does Cypress support Page Object Model?

Of course. Cypress gives all the flexibility to play around with pages and objects in the repository. It is easy to implement.

Which Page Object Model should I use from the above examples?

There is no particular rule to stick to only one way of Page Object Model. You can use any model that has been discussed above. You are free to customize the model according to your project.

Why should I use fixtures in the Page Object Model in Cypress?

Fixture helps store sensitive data like username, password, and URLs in a separate file like JSON or excel. This ensures the application’s security and access them easily in any files across the project. To access the JSON file, we use fixtures to use it in our spec file.