Using Page Objects in Cypress
Tags: cypress, javascript, testing, tutorial
Published: 2022-02-04 01:00:55

# Introduction 
Page Objects is a pattern in test automation that allow the automation engineer to encapsulate the data and methods used to support automation of a page.  Typically each page of the application will have an automation class that contains data, methods, and locators needed for automation of that page.  

In this post I will take a look at a sample Cypress script that does not use Page Objects, and walk you through the steps of converting to the Page Object pattern.

# Advantages
So why do we want to use Page Objects?  Some advantages of this pattern include:
- separating the implementation complexity of automation from the more business-focused details of the test script steps
- providing a single location for automation details, so if something like a page locator changes in the application, we only need to change it in one place in the automation code

But enough talking, let's get started.   Hopefully we can see these advantage in action!

# Setup
To make this easy to follow along, I'm going to be starting with the sample test scripts that are included when you install Cypress. Let's do that:

1. make sure you have node installed
2. create a new folder for our example and from the command line run: `npm init -y`
3. install cypress with: `npm install cypress --save-dev`
4. start the test runner with: `npx cypress open`

After starting the test runner, you'll see a `cypress` folder structure like this:

![Cypress folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g1ujcnhjw3yx1xgoah6g.png)

In the `1-getting-started` folder you'll see `todo.spec.js`.  This is a sample test that comes with Cypress and demonstrates some basic functionality using https://example.cypress.io/todo as the application under test.

To complete the setup, let's just make sure this test runs properly.  Run the test from the command line with `npx cypress run --spec cypress/integration/1-getting-started/todo.spec.js`.  If things go as planned, you should see messages that 6 tests ran and something like this towards the end:  


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbo7bwvcdqggtvwf1npk.png)

There we go, setup complete!  

# Planning our page class - round 1
Let's take a closer look at the `todo.spec.js` file.  The `beforeEach()` hook is not all that interesting, but let's start with that since it's pretty easy to understand.

```javascript
beforeEach(() => {
    cy.visit('https://example.cypress.io/todo')
  })
  ```

Instead of having the `cy` command and the destination URL in the spec, let's create a page object method to deal with all that.

# Creating the page object class
The class we're going to create is just a JavaScript class.  Create a new folder in the integration folder and name it something like `page-objects`.  Create a new file names `todo-page.js` in the `page-objects` folder.

Add the following to the new class file:
```javascript
export class TodoPage {

    navigateToHome() {
        cy
            .visit('https://example.cypress.io/todo')
    }
}
```
# Update the spec to use the page object

We have a new method named `navigateToHome()` that we're going to call from our spec file.  To make that happen, we just need to make a few updates to the `todo.spec.js` file.
1.  add the following import:
```javascript
import { TodoPage } from "../page-objects/todo-page"
```
2. instantiate the ToDoPage object prior to the beforeEach hook:
```javascript
const todoPage = new TodoPage()
```
2. update the beforeEach hook to call the page object method:
```javascript
  beforeEach(() => {
    todoPage.navigateToHome();
  })
  ```
Those are the changes.  Run the test again and make sure it's still green:  
`npx cypress run --spec cypress/integration/1-getting-started/todo.spec.js`

And that's about it!  We've created a page object class, and used it from our test spec.  

# Planning our page class - round 2
There are other examples in the spec that might benefit more from Page Objects.  Take a look at the first line of the first test: 
```javascript
cy.get('.todo-list li').should('have.length', 2)
```
This step is verifying that our app has two to-do items.  The Cypress interaction detail is right there in the spec, with a lot of locator and cypress detail that could be moved to the page object.  

Also what about other tests that follow this pattern?  The locator for the to-do list items will be scattered throughout our tests.  What if that locator changes in the future?  Yup, lots of updates and all the work and risk that comes with that.

I want to move all that detail into one place, the page object.  Our spec will become more clear, with a statement such as:
```javascript
todoPage.validateTodoCount(2)
```
See how clear that is?  It's so clear I am not even going to explain it. After our first example, it's probably pretty clear how to do this in the page object class.  Let's take a look.

# Updating the page object class
Since we already had the implementation details in the spec, we can just copy/paste/tweak that for our new Page Object method:
```javascript
    validateTodoCount(expectedLength) {
        cy
            .get('.todo-list li')
            .should('have.length', expectedLength)
    }
```
So with those changes to the spec and page object class, run the test again and make sure you are still seeing green tests.  

Cool, right?  And the great thing?  Any test that needs to validate the to-do count in the future can just use this method without worrying about locators or Cypress.  

# Wrap-up
So with those basic examples I hope you can see the value of encapsulating your automation code into Page Objects.  Feel free to experiment on your own and convert ALL the tests in that that spec to use Page Objects.  It's a great exercise.

I should also point out that since our Page Object class does not have any instance data, we could have just used functions instead of the class. To learn about this option and much more, I highly recommend you look at Cypress courses **Introduction to Cypress** by Gil Tayer and **Advanced Cypress** by Filip Hric, available for **free** from [Test Automation University](https://testautomationu.applitools.com/).  Much of my initial Cypress interest and learning came from these 2 courses.

And finally, I would be remiss if I did not mention the article by the Gleb Bahmutov [Stop using Page Objects and Start using App Actions](https://www.cypress.io/blog/2019/01/03/stop-using-page-objects-and-start-using-app-actions/#just-functions) where he explores some alternatives to Page Objects.

Feel free to subscribe to my [blog site](https://dennis-whalen.com) for more test automation content.  Thanks!

<a href="https://dev.to/leading-edje">
  ![Smart EDJE Image](https://dev-to-uploads.s3.amazonaws.com/i/5uo60qforg9yqdpgzncq.png)
</a>