DEV Community

Cover image for Page Object Pattern + Reusable Functions in Cypress
ajdin.must for Bornfight

Posted on

Page Object Pattern + Reusable Functions in Cypress

If you have ever wished to have more structured, reusable, and readable automated tests, you should have started with the Page Object Pattern.


Page Object Pattern

Page Object Pattern is basically removing all the page information from your actual test and grouping them together considering their location on your web page. For example, you can take all the selectors that you have on the homepage of your web and put them in one class, give them more meaningful names and then call them in any of your tests ...

Imagine your homepage went through a design and development modification that impacted your selectors to change, you would need to go through all of your tests and change the same selector in all the places. However, with the page object pattern, you change the selector only in one place - in the class that you have created for the homepage selectors. There, you saved yourself a lot of time and made sure that there won't be some forgotten, unchanged, and obsolete selectors in one of your tests.

Adding More of Reusability

Nevertheless, you can make your tests even more structured, reusable, understandable, and easier to maintain, by adding custom commands and reusable functions to them. The same way I made a class for homepage selectors I also made a class for all the functions from the homepage, that are used all over the different tests. For example, if I had 5 different tests/test cases where a user fills out the same form, I wouldn't be needed to copy/paste Cypress code to every each of the tests but I'd reuse the already written functions.

Example how my Cypress test would look like with the page object pattern and reusable functions:

describe("Fill out user satisfaction form", function () {

    it("Check if the user can fill out the form", function () {
        cy.visitFormsPage();
        cy.userAcceptsTerms();
        cy.userFillsOutsTheForm();
        cy.formFilledOutCorrectlyAssert();
    });
});
Enter fullscreen mode Exit fullscreen mode


All together now

Combining page object pattern and reusable functions gave me a whole new perspective of the tests. Not only are they easier to use and maintain, but they also look very neat and easier to understand for my other colleagues, even non-technical members of the team. In the beginning, you need to spend a bit more time on the setup but later on, you will see that the effort is paid off.

Feel free to share with me some of your "reusability" secrets.

Discussion (4)

Collapse
nenad_cvet profile image
Nenad Cvetković

How did you solve verification / assertion?

Collapse
nikomadar profile image
Niko • Edited on

You can still do assertions if you write your elements in the POM class to return the cy objects.

Example:
usernameField(){
return cy.get(#username)
}

And then in your test file you can just chain cy commands of it.

loginPage.usernameField().should('be.visible')

Collapse
ajdinmust profile image
ajdin.must Author

Hi Nenad! Thanks for the question. If needed, I assert directly in the function, so it is completely standalone.

Collapse
nikomadar profile image
Niko • Edited on

I prefer to do the assertions in the test file. Becuase then the POM element can be used for various assertions without having to duplicate them.
Also the test should be where all the checks take place. If the check is in an external function then we lose test clarity.