What is Page Objects | Bondar Academy
Course: Cypress UI Testing with JavaScript
Module: Page Object Design Pattern
Instructor: Artem Bondar
Lesson Summary
In this lesson, we explore the Page Object Model (POM) , a design pattern used in test automation to enhance the organization, maintainability, and reusability of code. Key Concepts of Page Object Model High-Level Definition: POM organizes repetitive code into methods, reducing code duplication and improving maintainability. Implementation Variability: There is no industry-standard implementation of POM; various engineers have their own approaches, such as using different storage methods for locators (e.g., constants, JSON, CSV). Core Idea: Each web application page has its own class with methods for operations related to that page. Benefits of Using POM Reduces the number of lines of code in tests. Enhances code readability and maintainability. Facilitates easier updates across tests when changes occur. Design Principles DRY (Don't Repeat Yourself): Avoid code duplication by creating reusable methods. KISS (Keep It Simple, Stupid): Maintain simplicity in design to ensure the framework is user-friendly and easy to understand. Best Practices Descriptive Naming: Use clear and meaningful names for methods and variables to enhance understanding. Avoid Tiny Methods: Group related steps into larger methods to prevent clutter and confusion. In the next lesson, we will begin building our first page object. Stay tuned!
Video Transcript
Hey guys, welcome back and in this module, we will talk about Page Object Model and dive deep into it. In this particular lesson, we'll talk about what is Page Object overall. So I prepared a few slides for you and let me show you those. So Page Object Model as a high-level definition for this concept, it is a design pattern used in test automation to organize source code, improve maintainability, and reusability of the code. So you see, it is a kind of very high-level concept, and the core idea is this one, that with the page objects, you take the repetitive parts of your code, put them into the functions or methods, and then instead of calling the steps directly, you call the method that implemented those steps. So that way, you reduce the number of lines of code in your project, improve reusability because you don't need to copy-paste the code anymore, and maintainability as well. When you need to update your test, you just update the implementation of the method instead of implementation in every single test. But the truth is that there is no industry implemented standard for the Page Object Model. There are hundreds and thousands of engineers who has own flavor of the page objects. Some using not Page Object Model, some calling this Page Object Functions, or even the concepts like App Actions. Some engineers can keep their locators inside of the methods. Some of them keep them in the constructor, some of them put them as a constants, some of them like to put the locators as a JSON files, and some add locators into CSV files. There are tons and tons of flavors about the page objects. But the general high-level concept for the page object would sound like this. Core concept is this, that every page of the web application has own class with methods, functions, responsible for operations on this page. That's a high-level concept. Then from this high-level concept, you can go sideways deciding how exactly to build the framework architecture. There are no rights or wrongs about the page objects. It's just a matter of preference and what makes sense in the context of the existing project. In this module, I will show you my approach, the page object model that I used on all of my projects that worked very well for me. I automated hundreds and hundreds of tests with this approach. Also, this approach is very scalable. You can take the concept shown in this lesson to your project, and then modify it for your needs based on your application functionality. Let me show you one of the example where do we need a page objects. For example, we have a login page, e-mail, password, and login button. Let's say you have two tests where you need to log into your application. You have some code before, some step before, then you type e-mail, type password, login, and then some code after that. For every test, you technically need to copy-paste these three lines of Cypress code because you need to log into your application. Not optimal way at all. Because if something will be changed on this login page, for example, placeholder or maybe login button will change the name from login to sign-in, and then you will need to go and change this login to sign-in in all of your tests. Not optimal at all. Also, test is actually harder to read when it is like this, because you have a lot of code with many steps. Instead, you can create an object of the login page and create a method that will be responsible for login operation, and it would look like this. You would create a method and calling it performLogin, so method is well descriptive and telling what it is doing. You're putting all those steps inside of this method, and then instead of calling them steps to log into your application in the test, you call them method that reference to all those steps, and it looks like this, onLoginPage, performLogin, and the same for the test too. You see the three lines of code inside of the test reduce just a single line of code. It is very descriptive. You can read this code clearly on the login page, performLogin. If something will have to be changed later, for example, login button will be changed to sign-in button, you can go to just a performLogin method, change it in a single place, and it will be applied automatically to all of your tests. That's the core concept. Moving on. There are two important principles when you design the page objects that you have to follow. Principle number one, call dry, which is acronym for don't repeat yourself. That means that if you copy-pasting the code, if you copy-pasting some of your code more than three times, it means that you probably need to stop there and think how you can create a reusable method or function that can be used in your test instead of copy-pasting this code. The second principle is a kind of opposite from the principle number one, which is KISS, keep it simple, stupid. Maybe it sounds strange, but it's actually very easy to overcomplicate the framework design. It is much harder to keep your code simple, clear, and understandable. New engineers who learn first design patterns and how code can be organized are super excited about those concepts and start overbuilding methods, classes, helper functions, different, I don't know, whatever util classes you may need, and that create framework just look cool but hard to use. So don't fall into this trap. So trust me, keeping the code simple and easy to use, it's actually not bad. Simple code is easier to maintain and easier to onboard new engineers. For example, if you hand over this framework to a new engineer who came to the company, if this framework is clearly to understand, most likely that this person keep using this framework, keep developing this framework, updating it, and so on. But the worst thing that can happen with your framework, if you spend a year developing test automation framework, in your eyes, it looks super cool, so modern, and so on, and then you hand it over to a new person, and new person just cannot use it just because it's too complex. And what this person does is just removes your framework and start from scratch. So if this happened, it means that your test design failed. So guys, keep your framework as simple as only possible, okay? And the two useful practices. The practice number one is descriptive naming. So naming in the computer programming, believe it or not, is the hardest thing to do. So avoid shortcutting acronyms and all that stuff in method naming, class naming, variables, functions, and so on. So instead of click login method, create click login button. Well descriptive method name that exactly says what is it doing. If you're not sure about method name, create the method name, tap the shoulder for your colleague and show me, hey, look at this method name. Does this method make sense? Can you recommend any other more meaningful name for this scenario? Give the person to read your test scenario and ask, hey, is it clear from the test scenario and the names of the methods what this test scenario is about? So keep attention on the clear naming. And the second thing is the avoid tiny methods. So methods like click login button that inside has just a single line that is just button, login, click. And that's all what this method is doing. I don't mean that don't create methods like that. I'm just saying that try to avoid it. So if you can put more steps or more meaningful implementation into your method, try to group several meaningful steps of your test scenario into the methods so your code will be not that bloated and your class will not have 50 tiny methods and you quickly get lost what those methods are doing. So try to group them meaningfully to make sense. If you need to create a method like this, okay, do it. But if you can avoid it and group your test steps into more bigger methods that would do some certain functionality on your page, better do this way. And that's it about the core concepts of page object models. And in the next lesson, we will start building our first page object. So I'll see you in the next lesson.