The page object model is invariably spoken about whenever we read or hear about test automation.
Yes, as the automation test coverage increases, the test code is on the ascendency, and thus from the outset test engineers need to design a strategy or a framework for code reusability, maintainability, etc. The page object model is mostly used as a design pattern for code reusability. Now, the intriguing thing is, that we see a sizeable number of test engineers thinking that the page object model is a de facto design pattern to be followed irrespective of the test automation framework one is working with. The reason for writing this piece was after seeing test engineers trying to use the page object model as it is when creating Cypress test scripts. Let’s try to figure out if there is a different or a better way of doing it!
What is Page Object Model?
Page Object Model is a design pattern where in we can re-use the test code across multiple tests. This pattern is generally used in Selenium for building test suites. In this pattern, any web page under test will have a corresponding test class. The web elements are mapped with the class variables and the web page interactions such as typing in a text box, or clicking a button are achieved through the test class functions.
Can Page Object Model be generalized?
We do see quite a few test engineers starting with the Page Object Model as the design pattern when implementing test automation in tools other than Selenium such as Cypress. Engineers who come from good Selenium experience more often than not follow this practice. Is it required to follow this pattern? Can this design pattern be considered a default way of implementing code reusability? I think in Cypress we can achieve code reusability in a better way.
How can we achieve better code reusability in Cypress?
In the page object model pattern, you would need to create and maintain class/classes for each of your pages or components which can be a cumbersome and restrictive way of doing it. (reference PoM implementation in cypress) - https://medium.com/reactbrasil/deep-diving-pageobject-pattern-and-using-it-with-cypress-e60b9d7d0d91
What alternatives do we have with Cypress?
We can create reusable functions at the component level (which is part of a webpage) or even more granular at an element level (say a dropdown or a date element). This provides us more freedom and leverage in creating a code reusability pattern. Example: Say we have two web pages with some common components. For example, in the below picture the address component is common across the two pages
Generally, a test engineer trying to follow Page Object Model implementation in Cypress would either:
Create classes/ files for each web page with corresponding web element variables and interactions
Create classes/ files for each of the common components
Cypress Custom Commands
Cypress custom commands are like a reusable function where we can group a bunch of test steps. These custom commands can be reused in multiple places such as test cases or other custom commands. Custom Commands can be created for the following cases
1. Element level: We can create element level custom commands in order to access and perform an action on that element.
This can be similar to how a developer would design an element in modern Single Page Applications (SPA)
The standard practice in any SPA is to create an application level standard web elements be it a text, dropdown, or a date component by creating wrappers over the native elements
So, if there are any element-level design changes in the product, eg if there is a design change for a date element then the developer has to make the changes only in one place
In the test automation script, we can take the above inspiration to create a reusable function at an element level.
Since an element like a dropdown or a date would be used in numerous instances the element level command is an obvious advantage for code maintainability, abstraction, ease of use etc
1. Let's see the below example of a dropdown element in any Single Page Application
Goal: To automate selecting a single value from a dropdown
DOM snippet for illustration:
Cypress code to select a value from the dropdown and validate the selected value
We would need to repeat the above lines of code for each instance in your different tests. This can easily be converted into a reusable parameterized cypress command as below
This Cypress command can be reused in:
Any of your tests
Part of other custom commands which act as a component level command. eg Address component can have a dropdown to select a country or a state
If your tests, requires performing login action for each test then we can write a custom command for the same.
3. Component level commands: If your application or product has a common component that is being reused on different pages. eg Address component
How Custom Commands can replace Page Object Model
Page level: Instead of creating a page level multiple classes for a login page in Page Object Model we can create one custom command for login as shown above in the Actionable command example
Component level: Similarly instead of multiple classes for a component we can create simple commands for component level similar to the setAddress example shown above
Element level: As explained previously.
Custom Commands Composition: We can perform a composition of element level commands to form a part of a component level custom command as well, eg setAddress command explained above
For code readability, one can always group the custom commands in different files based on their functionality or use case
I think using plain simple reusable Custom Commands as a reusable code in Cypress test automation is the way to go instead of creating multiple classes/files as part of the page object model As an engineer when we are working with different automation tools we should try to understand how the tools are different and try to devise solutions such that the tool can be used most effectively rather than starting with preconceived beliefs or patterns.