From the course: Advanced Selenium: Page Objects and GUI Automation

What are page objects?

From the course: Advanced Selenium: Page Objects and GUI Automation

Start my 1-month free trial

What are page objects?

- [Narrator] Page Objects are the most common form of abstraction for Web and GUI Automating. Basically an object that represents a page. Now that seems simple, but we have to make a lot of decisions around how much information to hide, what is actually a page and what level of abstraction the page models. And I'm going to talk through some of those decisions in the following examples. So this test, using PageFactory object is fairly short because I've already abstracted some functionality into a page object. In this case, the finding of elements. And presumably the synchronization of those elements. So this test creates a page object on line 25 and then creates a todo list. So actually finds the field we used to create the todo list and returns that. So we're using the web elements directly in this test. So how did I implement this? Let me click through. In this particular page object uses the PageFactory support class. I cover this in more detail in the Advanced Selenium Support classes video course. But in summary, the PageFactory in its elements method, scans the annotations that you can see here, that are find by annotations to create proxy web elements. Those are web elements that refresh themselves to avoid steal element exceptions, and which find themselves in the dome using the specification in the annotation. This saves me writing find element or find elements in my actual test code. But it does encourage me to use implicit waiting strategies, and I've been encouraged here to make the web elements public for ease of creating the class rather than adding extra methods into the PageFactory class. Now, if I go back to the test, we can see there's another test in here called UsingAPageObject. This is the same basic test that has different abstraction levels. So rather than make the web elements public, which is a common approach with a PageFactory usage, I'm encouraged to keep the web element fields private and expose the page functionality through methods rather than fields. I didn't have to make the web elements public in the PageFactory based class, but it was so easy todo, the very often when we're working with PageFactory, that's how we start. So I have a method here that creates a todo list and I had to make a decision about what to call that method. May not seem like a hard decision, but if I want to create todo list, then I simply create a method called createTodoList. But what, if I just wanted to type in todo list name into the field, I'd need to create a separate method to do that. And I've abstracted the way the mechanism for creating a todo list. I press in the Enter key after typing in some text. All of that is hidden within the createTodoList method. In the application itself, if I type in, new todo list here, we can see that I can create a todo list just by Losing Focus and clicking off the field. I didn't type Enter there, but in my createTodoList method, You can see that I have hard-coded the use of the Enter key, which means if I only use this abstraction of my tests, I don't have any coverage of the change of focus functionality. When we create abstractions, we tend to model in the most general implementation. This doesn't mean that all our tests need to use that abstraction. If I want to automate the creation of a todo, which uses the click on a page to change focus method, then I can still do that. I just don't use the abstraction for that. If I was really worried, then I could randomly decide in here whether to click or use Enter in the abstraction, but I probably wouldn't do that. Now some people at this point might go a little bit overboard and create a method on the todo's list called createTodoListByLossOfFocus, to cover the semantics of Losing Focus. But if I implement this, then my page object will start to get cluttered with methods that are rarely going to be used. Well, we create page objects and abstractions for the most general use case. Because we are going to use them most frequently. We don't have to add methods for every single occasion. Perhaps I could go a little bit more generic, and name this typeIntoCreateTodo. And then I leave up to the test itself to send a key to enter or change the focus. But then I lose the ability to easily reuse this across tests that don't care how actually a todo list. Just a todo list is created. So I'm going to delete this and the messages don't be tempted to create all the possible ways of using the system in the page objects. One thing that I find useful about simple plain old Java objects with abstraction methods, is that it's very easy to add synchronization. I want to make sure that this createTodoList synchronizes fully, then I might want to wait for the input field to be visible and enabled. And it's natural in a plain old Java object, to add that type of code. So if I wanted to synchronize, and just in here, I'd create a new WebDriverWait for that driver and see until the, Let's bring the same to make good provision work Until the expected conditions, of element to be clickable. And then the input field. If I format that we can see it, because clickable means enabled and visible. Now, I could still do this in a PageFactory class, but the temptation is to rely on implicit wait rather than more explicit waits. I do cover this in more detail in my Synchronization course. Now I prefer, to use plain old Java objects for my classes and not the PageFactory. Sometimes if I'm in a hurry, I will start by creating page objects using the PageFactory, by eventually refactor these into plain old Java objects fairly quickly, because I need to make sure that we have a level of abstraction through the methods and that we have synchronization in place. Now that naming of the methods is important. I generally tried to target most generic conditions that are going to be most used, rather than cater for every possibility.

Contents