Someone recently asked me what I think of page objects, and I realized it's time for an update.
I recently had a chat with Titus Fortner about implementing a good page object pattern (and many other things!) in this Test Automation Experience episode:
And, let’s dig into page objects a bit more.
Within your applications and sites there are elements that your tests interact with, sometimes on a repeating basis. Rather than having to repeatedly code these interactions into your test, you can use page objects to abstract them into a single functional unit. For example, your tests may require logging into a site or application. Rather than coding all these interactions into your test, you can create a LoginPage object that contains these interactions, which you then refer to in your test. This means taking a sort of object-oriented approach to test construction that enables you to simplify your test code and reduce duplication of effort. For more information, check out these resources.
The Selenium documentation on page object models
The page class should only contain methods for interacting with the HTML page or component.
A page object doesn't have to be an entire HTML page and can be a small component.
"Page" object is a poorly chosen name as it makes us think that a class is an entire HTML page, which is not the case. Many page objects are small components of a page.
This ProductsPage
1{2public class ProductsPage : BaseWebPage3{4private readonly string _pageUrlPart;56public ProductsPage(IWebDriver driver) : base(driver)7{8_pageUrlPart = “inventory.html”;9}1011public bool IsLoaded => Wait.UntilIsDisplayedById(“inventory_filter_container”);1213private IWebElement LogoutLink => Driver.FindElement(By.Id(“logout_sidebar_link”));1415private IWebElement HamburgerElement => Driver.FindElement(By.ClassName(“bm-burger-button”));1617public int ProductCount =>18Driver.FindElements(By.ClassName(“inventory_item”)).Count;1920public CartComponent Cart => new(Driver);21
is composed of a CartComponent
1public class CartComponent2{3private readonly IWebDriver _driver;45public CartComponent(IWebDriver driver)6{7_driver = driver;8}910private string CartItemCounterText11{12get13{14try15{16return _driver.FindElement(By.XPath(“//*[@class=‘fa-layers-counter shopping_cart_badge’]”)).Text;17}18catch (NoSuchElementException)19{20return “0”;21}22}23}
Here's an entire C# repo that uses page objects for web and mobile.
You can also read my article on Tech Beacon for a more in-depth description about high-quality page object patterns.
Yes, if you’re doing a lot of opaque box end-to-end (e2e) testing. It's not a perfect model. However, it's very simple to pick up for almost anyone.
However, it has its limitations. I especially don't like how it makes moving from functional e2e to any lower system testing impossible without rewriting the tests.
If you can do white box testing of your apps as well, then you don’t need to use page objects for test automation. With the ability to do end-to-end, component testing, unit testing, and API testing, I'm not 100% sure if you need page objects even for our UI tests. It might be overkill, especially if you don't want to do too much UI testing.
Filip Hric has a similar opinion, as he expresses in his YouTube video
It depends a lot on the app and the control of our environment. However, in this example of a live web application that I coded and hosted, I had only a few e2e UI tests. My tests were component tests, visual tests, front-end performance, and snapshot tests. Do I need extra code and abstractions in the form of page objects for so few e2e UI tests? I lean towards no.
Imagine if I started all of my testing by writing e2e UI tests with page objects. This is actually very common. If I wanted to replace those e2e UI tests with more efficient tests (e.g., component, snapshot, visual), I would need to delete the code that I spent time writing. Replace that code with new code. Creating page objects in this case wastes engineering time.
Page objects are a great start for anyone looking to start better UI automation. They're simple. I like simplicity.
But page objects might be overkill once you start doing testing of the entire system using unit tests, component tests, API tests, UI, and so on. Meaning that you might have so few UI tests that page objects become unnecessary as the value they serve is minimized.
This post was originally published on November 17, 2022 and has been updated in April 2023.