Scale Your Automated Test Code Beyond a Single Project
By: Shirley Ong
Tags: Automation, Software Testing, Tdd, Software Engineering, Programming

Why Not Page Object?

A seasoned tester would find that Page Object falls short of a scalable and maintainable test suite. Many tried to overcome the weaknesses by employing variations of Page Object. In my opinion, the best variation so far is breaking the UI into components instead of pages and introducing a layer of abstraction between the UI and the tests. John Smart’s article on how to write Page Objects that “suck less” further suggests how to improve the approach by storing only the locators in the Page Objects, keeping the Page Objects free of business logic, and categorising the abstraction layer into actions and questions. Next, apply the SOLID principles and use objects rather than methods to represent the actions and questions, and we naturally arrive at the Screenplay Pattern.

Head to the Resources section down below to read articles that explain why you would want to employ these techniques. After reading the articles, you should be convinced of the benefits of the techniques mentioned.

Perhaps you are already using Page Object and thinking of just using some of the techniques above without fully resorting to using the Screenplay Pattern. I’ll show you why you would still want to consider rewriting your whole test framework or switch over to a test framework that supports the Screenplay Pattern.

We have established in the previous section that a fluent DSL is highly attractive to meet our goal of a scalable test framework. Let’s take Cheapflights or any travel website as an example. Say a user wants to fly from London to Bali on the 1st of October 2020 and return on the 31st of October 2020. In the Page Object world, the action “search flights" would be represented by the ensuing method. This is the method that contains the implementation of the interactions with the website that you would call from your step library. We are not going to go into why you shouldn’t do the implementation in the step library itself.

searchFlights("London", "Bali", "1 October 2020", "31 October 2020");

In an attempt to make this read better, you might use the Builder Pattern so that calling the method now looks like this:

Flight flight = Flight.builder()

.from("London")

.to("Bali")

.departOn("1 October 2020")

.returnOn("31 October 2020")

.build(); searchFlights(flight);

Now that looks better, but the Screenplay Pattern can make it even more elegant. This is possible because the action “search flights" is an object:

SearchFlights.from("London")

.to("Bali")

.departOn("1 October 2020")

.returnOn("31 October 2020");

Let’s take another example on the website. After making the basic search, users are presented with the search results and options to filter the results. Some of the options are in the form of a slider. You might create a Page Object for the slider component that takes in the data attribute of the slider container as a parameter to differentiate the sliders on the results page. Using the Builder Pattern for the stopover duration slider, the code looks like this:

Slider stopoverDurationSlider = Slider.builder()

.id(stopoverDurationSliderId)

.min(30)

.max(120)

.build();

slide(stopoverDurationSlider);

Compare that with the following if you were to use the Screenplay Pattern. Again, notice how the latter looks more fluent and natural:

Slide.toMin(30)

.andToMax(120)

.the(stopoverDurationSlider)

There you have it. The solid reasons not to use Page Object.