How to Implement Cypress Page Object Model (POM)

  • Learning Hub
  • How to Implement Cypress Page Object Model (POM)

OVERVIEW

Page Object Model is a Selenium design pattern that can be used with any kind of test automation framework, including keyword-driven, data-driven and hybrid frameworks. One of the problems I faced before using the Page Object Model (POM) design pattern was when one of the elements would change, and I had to update the selectors from all the places where the element was used, especially in large code bases.

So, to change one little selector, I’d have to go all over the code, find out where it’s been used, and change them everywhere, which took a lot of time for such a simple task.

That was before I was using the Page Object Model design pattern. In this blog post on Cypress Page Object Model, I will show you the POM design pattern, why it is important, and how to use Cypress Page Object Model using the Cypress best practices.

...

What is Cypress?

Cypress is a test automation framework that is used for testing web applications. It is based on JavaScript and provides a unique set of features like screenshots and records for your test runs that make it well-suited for testing modern web applications. Cypress has been designed from the ground up to be easy to use, reliable, and scalable. Cypress visual regression testing can be used to validate the visual component of a web application.

As such, it has quickly become the framework of choice for many test automation experts. In addition to its core features, Cypress also provides a wide range of plugins and extensions that further enhance its functionality. As a result, Cypress is an incredibly powerful automation testing framework that can be used to test any web application confidently.

Shown below is the download comparison of Cypress vs. Selenium, an indicator that Cypress is gaining a lot of traction:

Cypress vs. Selenium

Source

Akin to Page Object Model in Selenium, POM with Cypress also offers a numerous set of benefits since the overall principles of the design pattern remains the same. Cypress Page Object enables you to reuse code and avoid code duplication, makes your tests more maintainable, and helps to keep your code clean and organized.

In this tutorial on Cypress Page Object Model, we'll look at how to start using the Cypress Page Object Model design pattern and build a robust test automation suite.

What is a Page Object Model (POM)?

The Page Object Model (POM) is a design pattern used in software development where classes represent pages. POM can make code more maintainable and reduce duplication.

All page elements are stored in that class for the related page. This makes it easy to access and update page elements as needed, especially when there are changes in the front end (or UI) of the website.

Page Object Model also makes it easy to reuse code, which can save time and money when testing web applications.

Advantages of using Cypress Page Object Model

There are several advantages of using the Cypress Page Objects design pattern; some major ones are elbow:

  • The Cypress Page Objects Model offers a high level of abstraction. This means that tests can be written without having low-level details of the implementation. This makes it easier to write maintainable and robust tests.
  • The Cypress Page Objects Model improves readability. It can make tests more readable and easier to understand by segregating the page logic from the test logic, making it easier for new team members to understand the test suite.
  • It helps improve code efficiency. Because Cypress Page Object Model offers a higher level of abstraction, they can save time when tests are being written by developers.
  • It is an elegant way to keep your test cases maintainable if some of your element selectors change in the future. You will only have to fix the selectors in that specific page object file without updating the selectors in every test file in which the element is used.

Overall, the Page Object Model is a valuable design pattern that can be used to simplify the Cypress UI testing process. When used in conjunction with Cypress, Page Objects can offer significant benefits in terms of readability, maintainability, and performance.

Getting started with Cypress Page Object Model

To run Cypress on your local machine:

  • You need to have Node.js installed; if you don’t have it already, make sure you download it from the official Node.js website.
  • Create an empty folder for your Cypress tests with a name of your choice. I will name it “cypress-pom.”
  • Open the directory and initialize a Node.js project by running the following command
  • $ npm init -y
  • This will create a package.json file for you that stores the details for your current project.

In order to install Cypress:

  • Run the following command in your terminal.
  • $ npm install cypress --save-dev
  • We use the --save-dev flag because we use Cypress for development purposes only. Or if you use yarn:
  • $ yarn add -D cypress
    This command will download and install the latest version of Cypress in your project. As you can see below, the latest version right now is cypress@10.4.0cypress@10.4.0
  • Your directory structure should look like this, we only have the node_modules folder, package.json, and yarn.lock files.
  • yarn.lock

Update the package.json scripts

  • Go to your package.json file and add in two different scripts, for cypress run and the other for cypress open
  • ...
    "scripts": {
        "cypress:run": "cypress run",
        "cypress:open": "cypress open"
    },
    ...
    
  • Now that you have set your scripts correctly, run the following command to open Cypress.
  • $ npm run cypress:open
    This will run your Cypress client.Welcome to Cypress
  • Now press E2E testing to set up your configuration files and the Cypress environment.
  • E 2 E testing In Cypress
  • This will create some configuration files that are specific to Cypress.
  • configuration files that are specific to Cypress

Cypress config file

The cypress.config.js file is used to edit the Cypress settings. For example, setting the base URL for every request or visit done by Cypress.

E2E.js

The E2E.js file is processed and loaded automatically before each one of your test files. This is a good place to put global configuration and behavior that modifies Cypress.

Commands

The commands.js file lets you write your custom commands so you can use or reuse them later in your tests. This file also lets you overwrite the existing commands.

An example of adding a new custom command:

Cypress.Commands.add('login', (email, password) => { ... })

Fixtures

When it comes to Cypress Page Object Model, Fixtures are a great way to mock data for responses to routes. This is especially useful when you need to test something that is not yet implemented or when you want to avoid making real requests. Cypress Fixtures are easy to set up and use, and they can save you a lot of time and effort when writing tests.

  • Press Continue so you will be redirected to choose your preferred browser for Cypress testing
  • Press Continue
  • Select your preferred browser for your end to end testing, I personally use Chrome.
  • Select your preferred browser for your end to end testing

Congrats, now our Cypress dashboard is ready and we can write tests and run them.

Cypress dashboard

If we have a look at our folder structure, we can see that Cypress has also automatically created a folder with the name “cypress” which also has some files for the fixtures and custom commands.

folder with the name “cypress”

Since we are using a Cypress Page Object design pattern, I will create a folder with the name “pages” to store all of the page objects we need in our test.

Let’s create our first object in cypress/pages/Home.js, which will store all of the home page methods.

Implementing Page Object Model using Cypress

For this example, we will be using the LambdaTest E-Commerce Playground to run all of the tests on it.

We will test the home page to ensure our application works as expected. We will be using the Cypress Page Object Model design pattern to create methods we can reuse throughout the test suite

So, the first step will be setting this link to our baseUrl property in our cypress.config.js file

const { defineConfig } = require("cypress")
 
 module.exports = defineConfig({
   e2e: {
     setupNodeEvents(on, config) {
       // implement node event listeners here
     },
     baseUrl: "https://ecommerce-playground.lambdatest.io",
   },
 })
 

Creating an object for the home page

For simplicity, we will write some methods that will help us to get access to certain elements.

Let’s say you want to write some methods that will give you access to each element in the navbar

Lambdatest ecommerce each element in the navbar

Let’s write our first class for the home page.

FileName - pages/Home.js

class Home {
  visit() {
    cy.visit("/")
  }
 
  searchInput(text) {
    return cy.get('input[name="search"]').first().type(text)
  }
 
  getSearchButton() {
    return cy.get("#search > div.search-button > button").first()
  }
 
  getHomeButton() {
    return cy.get(
      "#widget-navbar-217834 > ul > li:nth-child(1) > a > div > span"
    )
  }
 
  getSpecialButton() {
    return cy.get(
      "#widget-navbar-217834 > ul > li:nth-child(2) > a > div > span"
    )
  }
 
  getBlogButton() {
    return cy.get(
      "#widget-navbar-217834 > ul > li:nth-child(3) > a > div > span"
    )
  }
 
  getMegaMenuButton() {
    return cy.get(
      "#widget-navbar-217834 > ul > li.nav-item.dropdown.dropdown-hoverable.mega-menu.position-static > a > div > span"
    )
  }
 
  getAddOnsButton() {
    return cy.get(
      "#widget-navbar-217834 > ul > li:nth-child(5) > a > div > span"
    )
  }
 
  getMyAccountLink() {
    return cy.get(
      "#widget-navbar-217834 > ul > li:nth-child(6) > a > div > span"
    )
  }
}

You can get access to these selectors quickly by using the Chrome DevTools, right-click on an element and then open the “copy” dropdown, and then select “copy selector”.

get access to these selectors quickly by using the Chrome DevTools

As you can see, some of the selectors might be a bit long, and if we didn’t use the Cypress Page Objects design pattern, we’d have to write all of these in our spec files, which would make the code look messy and we’d have a lot of code duplication. You can learn more about selectors through this locator tutorial.

Creating the blog page object

Let’s create another object for our blog page. I will create a file in the pages folder with the name of the page, which is Blog.js.

blogjs
// cypress/pages/Blog.js
class Blog {
  constructor() {
    this.url = "/index.php?route=extension/maza/blog/home"
    this.title = "Blog"
  }
}

In this object, we will store some methods specific to this page.

E commerce LambdaTest website

Let’s write some methods that will give us access to specific elements.

FileName - pages/Blog.js

class Blog {
  constructor() {
    this.url = "/index.php?route=extension/maza/blog/home"
    this.title = "Blog"
  }
 
  visit() {
    cy.visit(this.url)
  }
 
  getFirstCategoryButton() {
    return cy.get("#entry_210963 > div > a:nth-child(1)")
  }
 
  getSecondCategoryButton() {
    return cy.get("#entry_210963 > div > a:nth-child(2)")
  }
 
  getThirdCategoryButton() {
    return cy.get("#entry_210963 > div > a:nth-child(3)")
  }
 
  getPreviousBlogsButton() {
    return cy.get(
      "#mz-article-listing-76210960 > div.mz-tab-listing-header.d-flex > div > div > a.mz-swiper-nav-prev.swiper-button-disabled"
    )
  }
 
  getNextBlogsButton() {
    return cy.get(
      "#mz-article-listing-76210960 > div.mz-tab-listing-header.d-flex > div > div > a.mz-swiper-nav-next"
    )
  }
}
 
module.exports = Blog

Now that we have created our page objects, it is time to write some tests.


Writing tests using Cypress Page Object

I will write some tests for the home page in cypress/e2e/home.cy.js, which will include all the tests for the home page.

import Home from "../pages/Home"
 
 const home = new Home()
  
 describe("testing home page", () => {
   it("should visit home page", () => {
     home.visit()
   })
  
   it("should search for a product", () => {
     home.searchInput("iphone")
     home.getSearchButton().click()
   })
 })
 

This code is implementing basic tests, the first one is just visiting the page, which is taken from the Page.js or the Page Object, as you can see, this will be useful because throughout your code, you'll need to re-use this code to visit your home page, and same goes with all the other methods.

The second test gets access to the input element and types some text; after that, it will click the search button.

Now let’s run the test by running the command cypress:open or cypress:run as we have defined the scripts from our package.json file.

Now let’s run the test by running the command

Testing the blog page

I will create a test file similar to the one on the home page with the name blog.cy.js.

Testing the blog pageThe test code:
import Blog from "../pages/Blog"
 
 const blog = new Blog()
  
 describe("testing blog page", () => {
   beforeEach(() => {
     blog.visit()
   })
  
   it("should visit the blog page", () => {
     cy.title().should("eq", "Blog - Poco theme")
   })
  
   it("should have correct category names", () => {
     blog.getFirstCategoryButton().should("contain.text", "Business")
     blog.getSecondCategoryButton().should("contain.text", "Electronics")
     blog.getThirdCategoryButton().should("contain.text", "Technology")
   })
 })
 
                                    

Running the test:bms_3

As you can see, both of the tests are running successfully, and the Cypress Page Objects Model design pattern makes it possible for us to write our code in such a way that we don't have any unnecessary clutter in our code.

This also makes it extremely easy when we have to update our code, let’s say in the future we decide to change some of the elements, and the selectors break and now the tests are failing, if the tests weren’t written using the Cypress Page Objects, we’d have to update the code for our tests in every single place in which the changed elements were present.

With the Cypress Page Object Model design pattern, we only have to update the code for the changed elements only in one place of the code, and that place is the file that has the page object inside of it.

Running automation tests on cloud Cypress grid

One of the potential shortcomings of local testing with Cypress is that it takes too many resources to the point that you can’t run a lot of parallel tests at once. Well, no machine does not have infinite CPU and RAM :) Hence, you’ll be forced to run only a handful of tests on one browser at a time, which could be very time-consuming if you have a huge codebase.

Cloud testing platforms like LambdaTest help run multiple Cypress E2E tests on multiple browsers with different versions, all in parallel in the cloud.

...

LambdaTest is a cross browser testing cloud that lets developers use Cypress for their integration testing. It provides an online Cypress grid of 40+ browser versions, on which developers can run their Cypress tests in parallel. This cuts down the testing time from days to hours and helps developers to deliver their projects on time. LambdaTest also provides several features like screenshots, video recordings, and logs, which help developers debug their tests easily.

Subscribe to the LambdaTest YouTube Channel and stay updated with the latest tutorials around Selenium testing, End-to-End (E2E) testing, CI/CD, and more

Also, setting up tests on LambdaTest is very easy, so let’s get started.

Though the latest version of Cypress on LambdaTest is 10.0.0, we would be using version 9.0.0 since Cypress 10 was released on LambdaTest only a few weeks back.

Since we have to change our version to 9.0.0 we also have to use cypress.json for our Cypress configurations. So, let’s create our configurations for Cypress.

 {
  "baseUrl": "<https://ecommerce-playground.lambdatest.io>",
  "integrationFolder": "cypress/e2e" // telling Cypress where to look for test files
}

Installing the LambdaTest Cypress CLI

The lambdatest-cypress-cli is LambdaTest's command-line interface (CLI) aimed to help you run your Cypress tests on the LambdaTest platform.

In order for us to run our Cypress tests on LambdaTest, install the LambdaTest Cypress CLI using the following command:

npm install -g lambdatest-cypress-cli

Set up the LambdaTest configurations

The lambdatest-cypress-cli provides us with a specific command to create a configuration file, which the LambdaTest platform then recognizes and will execute the tests based on the provided settings inside of the configuration file, which is lambdatest-config.json.

To create the configuration file for LambdaTest, run the following command:

lambdatest-cypress init

This will save the configurations inside the lambdatest-config.json file.

save the configurations

This file stores all of the configurations that are needed to run your Cypress tests on the LambdaTest platform, like telling LambdaTest to run your tests on a specific browser with its version, or running your tests on multiple browsers, etc.

Here is an example of the lambdatest-config.json file.

{
   "lambdatest_auth": {
      "username": "<Your LambdaTest username>",
      "access_key": "<Your LambdaTest access key>"
   },
"browsers": [
      {
         "browser": "Chrome",
         "platform": "Windows 10",
         "versions": [
            "latest-1"
         ]
      },
      {
         "browser": "Firefox",
         "platform": "Windows 10",
         "versions": [
            "latest-1"
         ]
      }
   ],
   "run_settings": {
      "cypress_config_file": "cypress.json",
      "build_name": "cypress-pom",
      "parallels": 1,
      "specs": "./**/*.cy.js",
      "ignore_files": "",
      "feature_file_suppport": false,
      "network": false,
      "headless": false,
      "reporter_config_file": "",
      "npm_dependencies": {
         "cypress": "9.0.0"
      }
   },
   "tunnel_settings": {
      "tunnel": false,
      "tunnel_name": null
   }
}

What we need to change from this configuration file first are the username and access_key values.

Use your LambdaTest username for the username field, and get your access key from the LambdaTest Dashboard, by going to your profile settings in the LambdaTest Dashboard.

I have also changed the specs property from ./*.spec.js to ./*.cy.js and the Cypress version to version 9.0.0.

In the cypress_config_file specify the configuration file of your Cypress test project, which in our case is in the root directory.

Change the build name with a name of your choice.

Running Cypress tests on LambdaTest cloud

Now that our configuration files are ready, it is time for us to upload our tests to LambdaTest and start running them on the cloud.

To run your tests on the LambdaTest cloud, run the following command:

lambdatest-cypress run

lambdatest-cypress run

If you go to your builds page in your LamdaTest Dashboard, you can see your tests running on the specific browsers specified in the LambdaTest configuration file.

LamdaTest Dashboard

Conclusion

Overall, using Cypress Page Objects makes for more maintainable and reusable code. This can be extremely beneficial in development, as you won’t have to worry about rewriting or updating your tests every time a change is made to the website.

  • Cypress automation tool helps you write concise, reliable tests
  • Cypress Page Object Model makes your tests more maintainable and easier to read.
  • With Cypress Page Object Model, you can create reusable page objects.
  • This makes it easy to update your tests when the underlying code changes.
  • Cypress Page Object Model also allows you to group related tests, which makes them easier to manage.

Frequently Asked Questions (FAQs)

Does Cypress Use Page Object Model?

Yes. Cypress uses Page Object Model to create reusable test code.

What is Dom in Cypress?

The Dom method is a function that allows you to create an element programmatically in the browser. The Dom method makes it easier for a tester to write tests in Cypress.

What are page objects in Cypress?

In-Page Object Model (POM) design pattern, page objects are separated from the automation test scripts. This design pattern makes the code reusable, which is why Cypress has implemented POM support.

What is a page object?

The Page Object Model (POM) is a design pattern in Selenium that creates an object repository for storing all web elements. This improves code reuse and makes it easier to maintain test cases. In POM, each web page of an application is treated as a class file.

Should I use POM with Cypress?

Yes, you can use POM with Cypress. In Cypress, POM can be used to create a layer of abstraction.

What is the difference between Page Object Model and Page Factory?

Page Object is a class representing a web page and holds the mechanisms of interacting with the elements on that page. The Page Factory pattern creates instances of these web page objects, initializing them with the appropriate content.

Author's Profile

...

Dawson

Dawson is a full-stack developer, freelancer, content creator, and technical writer. He has more than three years of experience in software engineering, and he is passionate about building projects that can help people. You can also follow him on Twitter.

Hubs: 04

  • Twitter

Reviewer's Profile

...

Himanshu Sheth

Himanshu Sheth is a seasoned technologist and blogger with more than 15+ years of diverse working experience. He currently works as the 'Lead Developer Evangelist' and 'Director, Technical Content Marketing' at LambdaTest. He is very active with the startup community in Bengaluru (and down South) and loves interacting with passionate founders on his personal blog (which he has been maintaining since last 15+ years).

  • Twitter
  • Linkedin

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Did you find this page helpful?

Helpful

NotHelpful