Page Object Model is a design pattern that focuses on making a Test Automation Framework extensible, maintainable, and easy to understand. In this article, we will see how we can create a simple Page Object structure for cypress.

To implement POM for Cypress we would be doing two things:
1. A place for managing locators – ‘pages’ folder
2. A place to write reusable functions – ‘utils’ folder

Let’s further deep dive by automating a scenario:
1. Successful Login to https://opensource-demo.orangehrmlive.com/
2. Successful Logout

Step 1: Create two folders pages and utils inside integration folder. So, for each page of the application, there will be two files; one containing all the locators of that page and the other containing all the reusable codes/functions. For our test case, we would be working with two pages – the login page and dashboard page.

So, the pages folder will have two files ‘loginPage.js’ and ‘dashboardPage.js’ which contain all the locators of the respective pages. Similarly, the utils folder will also have two files ‘login.js’ and ‘dashboard.js’ containing all the reusable codes/functions for the respective pages.

page object structure
 

Step 2: Since we will be using custom commands in a file other than commands.js, we have to import files where we will be writing our custom commands in support/index.js

importing util files in support index js
 

Step 3: Write the page-specific locators in the respective files under ‘pages’ folder. For our test script, we will write the locators under loginPage.js and dashboardPage.js.

loginPage.js:

login page locators file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class loginPage {

    usernameInput() {
        return cy.get('#txtUsername')
    }

    passwordInput() {
        return cy.get('#txtPassword')
    }

    loginBtn() {
        return cy.get('#btnLogin')
    }
}
export default loginPage

 
dashboardPage.js

dashboard page locators file

1
2
3
4
5
6
7
8
9
10
11
12
class dashboardPage {

    welcomeTxt() {
        return cy.get('#welcome')
    }

    logoutTxt() {
        return cy.contains('Logout')
    }
}

export default dashboardPage

 

Step 4: Next step is to write our reusable functions in one place. This will again be page-specific. So Under ‘utils’ folder we will create two files login.js and dashboard.js.

login.js:

login page reusable functions file

1
2
3
4
5
6
7
8
9
10
11
12
import loginPage from '../pages/loginPage.js'
import dashboardPage from '../pages/dashboardPage.js'
const login = new loginPage();
const dashboard = new dashboardPage();

Cypress.Commands.add('login', (data) => {
    cy.visit('/')
    login.usernameInput().type(data.username)
    login.passwordInput().type(data.password)
    login.loginBtn().click()
    dashboard.welcomeTxt().contains(data.welcomeText)
})
1
2
import loginPage from '../pages/loginPage.js'
const login = new loginPage();

This will enable us to access all the locators from loginPage.js in the login.js file.

1
2
import dashboardPage from '../pages/dashboardPage.js'
const dashboard = new dashboardPage();

This will enable us to access all the locators from dashboardPage.js in the login.js file.

1
2
3
4
5
6
7
Cypress.Commands.add('login', (data) => {
    cy.visit('/')
    login.usernameInput().type(data.username)
    login.passwordInput().type(data.password)
    login.loginBtn().click()
    dashboard.welcomeTxt().contains(data.welcomeText)
})

We are creating a custom command login which takes the parameter ‘data’ which we will be passing from our test.spec file. ‘data’ is a reference of our fixture file ‘testdata.json’ which contains our test data. This is how our fixture file looks like:

test data fixture file

Next, we are visiting the website https://opensource-demo.orangehrmlive.com/ using the cy.visit(‘/’) command. If you have mentioned baseUrl in your cypress.json file then you can use the command like this.

Now login.usernameInput().type(data.username) will input username into the username input field and login.passwordInput().type(data.password) will input password into the password input field.

login.loginBtn().click() will click on the login button.

dashboard.welcomeTxt().contains(data.welcomeText) confirms successful login by checking the Welcome text on dashboard page.
 

dashboard.js:

dashboard page reusable functions file

1
2
3
4
5
6
7
8
9
10
import loginPage from '../pages/loginPage.js'
import dashboardPage from '../pages/dashboardPage.js'
const login = new loginPage();
const dashboard = new dashboardPage();

Cypress.Commands.add('logout', () => {
    dashboard.welcomeTxt().click()
    dashboard.logoutTxt().click()
    login.usernameInput().should('be.visible')
})
1
2
import loginPage from '../pages/loginPage.js'
const login = new loginPage();

This will enable us to access all the locators from loginPage.js in the dashboard.js file.

1
2
import dashboardPage from '../pages/dashboardPage.js'
const dashboard = new dashboardPage();

This will enable us to access all the locators from dashboardPage.js in the dashboard.js file.

1
2
3
4
5
Cypress.Commands.add('logout', () => {
    dashboard.welcomeTxt().click()
    dashboard.logoutTxt().click()
    login.usernameInput().should('be.visible')
})

We are creating a custom command logout which has all the required steps to perform the logout function. Unlike before this function is not taking any parameters.

dashboard.welcomeTxt().click() will click on the Welcome Text on the page to open the drop down which has the Logout button.

dashboard.logoutTxt().click() will click on the Logout text.

login.usernameInput().should(‘be.visible’) will make sure that after logout, user is redirected to login screen and to validate that we are making sure that the username field is visible.
 

Step 5: Now, we will write our test script. Since all of the stuff has been written already in pages and utils, our spec file will look very minimalistic (easy to read).

cypress page object test script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
describe('Validate Login and Logout on OrangeHRM website', function () {

    beforeEach(function () {
        cy.fixture('testdata').then(function (testdata) {
            this.testdata = testdata
        })
    })

    it('Validate successful Login', function () {
        cy.login(this.testdata)
    })

    it('Validate successful Logout', function () {
        cy.logout()
    })
   
})

Here in the beforeEach, we are referencing our fixture file testdata.json from fixtures folder as ‘testdata’, then passing it as a parameter in cy.login(this.testdata).

cy.login(this.testdata) executes the login custom command written under integration/utils/login.js

cy.logout() executes the logout custom command written under integration/utils/dashboard.js
 

Step 6: After Execution:

Cypress page object test execution

Do check out 🙂

Github: https://github.com/alapanme/Cypress-Automation
All Cypress Articles: https://testersdock.com/cypress-tutorial/