DEV Community

Cover image for How to Implement Cypress Page Object Model (POM)
Mehul Gadhiya
Mehul Gadhiya

Posted on

How to Implement Cypress Page Object Model (POM)

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.

Don’t let CSV errors slow you down. Validate and lint your CSV data with ease using our free online CSV Validator tool. Get accurate and error-free results in seconds.

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:

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.

Catch errors before they impact your JavaScript code. Our JS validator and linter enforces coding standards and helps you catch errors. Validate your code today.

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.

Keep your JavaScript code safe from syntax errors with our free online JavaScript Escape tool by quickly and easily converting special characters in your JavaScript.

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.

Need to make your JSON code more readable? Our online JSON Prettifier tool makes your JSON data more human-readable. Copy, paste, and prettify in seconds.

Getting started with Cypress Page Object ModelTo 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

  • Your directory structure should look like this, we only have the node_modules folder, package.json, and yarn.lock files.

Get faster loading times and better user experience with our efficient JSON minify tool. Quickly compress your JSON data with ease and optimize your website now.

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

  • Now press E2E testing to set up your configuration files and the Cypress environment.

  • This will create some configuration files that are specific to Cypress.

Beautify your HTML and improve readability of the code with our free online HTML Prettify tool. Beautify your code and save time on your projects.

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) => { ... })
Enter fullscreen mode Exit fullscreen mode

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

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

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.

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.

Need a fake IP address for your testing projects? Use our free online Random IP Generator to quickly generate fake IP addresses with just a few clicks.

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",
   },
 })
Enter fullscreen mode Exit fullscreen mode

Need a random MAC address for your work? Our random MAC address generator tool is fast and easy-to-use for generating random MAC addresses with just a few clicks.

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

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"
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

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”.

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.

Use our free online Random Number Generator tool to create unique non-repeating random numbers. Input your lower and upper range and get numbers with a click.

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.

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

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

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
Enter fullscreen mode Exit fullscreen mode

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

Need a block of text? Use our random paragraph generator to create random paragraphs and add some variety to your content and keep your audience interested.

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()
   })
 })
Enter fullscreen mode Exit fullscreen mode

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.

Testing the blog page

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

The 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")
   })
 })
Enter fullscreen mode Exit fullscreen mode

Running the test:

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.

Random Time Generator is an easy to use, free, online utility that lets you create a random clock time stamp. Try now, create a random time stamp for free.

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
}
Enter fullscreen mode Exit fullscreen mode

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

Need random sentences for your project? Use our online Random Sentence Generator to generate random sentences of any length. Simply choose the length and get started.

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.

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
   }
}
Enter fullscreen mode Exit fullscreen mode

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

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.

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.

Top comments (0)