Introduction

The Page Object pattern is considered the standard when talking about patterns for test automation. But do you know there is another way to model your tests in such a way that gives you a lot of flexibility, maintenance and scalability benefits? This is what we will discuss today. The Screenplay Pattern comes to the rescue!

The Scripted way

Back in the days, test automation was not considered a proper software development practice. It was almost considered black magic, and usually delegated to QA teams where there were a lot of good intentioned people, but with little to none actual software development experience. I can tell this from my own experience, having developed a test framework with Ruby & Watir for MercadoLibre, one of the biggest e-commerce sites in Latin America… Without even knowing object oriented programming principles.

But I know this didn’t happened to me only, it was (and sadly sometimes still is), a common approach in software projects.

For illustration purposes, let’s try to automate a simple acceptance test using the scripted approach, from the following user story for the Vue.js TodoMVC example App

For this example we will use Mocha as the Test Runner, WebdriverIO as our web automation driver library, and code with Typescript.

If you want to take a closer look, follow along and run this examples, please check my fork of a boilerplate Serenity.js project

Issues with this approach:

  • Low level navigation and synchronisation code
  • Duplicated code
  • Complicated logic included in the test

As you see this approach violates principles of good software development, like repeating ourselves, but most importantly, we are developing fragile and anti resilient scripts.

“If you have WebDriver APIs in your test methods, You’re Doing It Wrong”

Simon Stewart.

Page Object Pattern

Martin Fowler started talking about Window driver back in 2004, but it wasn’t until 2014 until he renamed it to Page Object under the scope of web test automation.

In a nutshell, a Page Object is a wrapper of a user interface (html, mobile views or screens, etc) or a fragment of it. It provides a specific API that allows the tests to manipulate web elements without worrying about any HTML details.

The golden rule of Page Objects is that they should encapsulate the mechanisms to find and manipulate elements and data in a user interface.

Let’s check our last example, now refactored in a Page Object style way. For simplicity, the Page Object is created in the same file as the test (in real life the class would be a separate file):

This is way better, but we still have some problems in our code:

  • Operations that are not part of the page object’s responsibilities are still present in the test
  • Page objects usually need to be instantiated in the tests
  • Repeated calls to recordItemsCalled

And in general, there are other issues with Page Objects like:

  • If your test interacts with multiple pages or views, page objects can return other page objects (which in a sense is modelling navigation and not behaviour, and adds maintenance problems). But sometimes page objects will also return data types (eg strings, dates), which is confusing.
  • It’s not clear if page objects should include validation steps or not:
  • Testers that support adding validations in the page object class do so because it avoids code duplication, provides easier to use APIS, and enables better error handling messages.
  • The proponents of NOT including validations say that doing so is mixing the responsibility of accessing page data with validation logic.
  • The pattern itself usually leads to bloated paged objects, that clearly violate the SOLID and DRY principles, in particular the Single Responsibility and the Open Closed principles.

But, the biggest issue, is that we are modelling our tests based on Pages or Views and not in our end users needs. What if we take a step back and think about them?

A new way of thinking tests

If we start thinking our tests from a user centric point of view, we should ask this questions:

Roles -> Who is this for?
Goals -> Why are they here and what results are they looking for?
Tasks -> What they need to do to concrete their goals?
Actions -> How are they going to complete each task through specific interactions?

Having this in mind, we can change the way we perceive our domain and hence how we model our tests. This type of thinking is not compatible with pages modelling. We start thinking about Actors that have abilities to fulfil certain roles.

This approach, combined with the principles of object oriented programming violated by the Page Object Patter we discussed before, is what makes us look for a new alternative: The Screenplay pattern.

Finally, the Screenplay Pattern!

Original image from The Serenity JS Handbook

Tests are modelled with the point of view of one or more Actors. Actors have Abilities, such as “browse the web” using a browser. This Actors perform Tasks based on Interactions, in order to achieve Goals, such as “add an item to a Todo List”. Actors can also ask Questions about the state of the application, for instance, checking a result on a screen.

But, why that odd name?

Photo by Kyle Head on Unsplash

The design of Serenity and SerenityJS is based on a system metaphor. We can think our tests as a performance in a scenario (or Stage). Hence the name of a Screenplay! Actors play different roles within a test:

  • A “Photographer” is an actor in charge of taking screenshots, a “Reporter” is in charge of generating reports.
  • The actor that is “performing” in our test is “On the Spotlight”. We can then put different actors in the “Spotlight”, with different abilities as we see fit during the test execution.
  • As an example, we could have an actor called “Maria”, who has the ability of browsing the web with Firefox, and then another actor called “Lucas” that has the ability to browse the web with Chrome. They would be taking turns “On the Spotlight”, performing Tasks in orchestration. This is particularly important when testing multi channel scenarios, or even for creating actors that set up test data in our tests, with the ability to access API’s, etc.
  • The test tear down, where we frequently do cleanup tasks or other type of closing actions, is called “Draw the curtains” in this pattern. Isn’t this FUN?!

Frameworks

Of course, implementing all of this ourselves would be a lot of work. But luckily, there are a couple of framework options which provides Screenplay support out of the box:

  • SerenityBDD provides a way to work with this pattern out of the box. Created by John Ferguson Smart. This Java based framework enables you to write tests following the Screenplay pattern.
  • SerenityJS, created by Jan Molak, which would be interesting for people working with Javascript or Typescript.

OK, enough words for now, let’s check some actual code… Because a line of code is worth more than 100 words, right? (Well, maybe some times…)

Screenplay Code Examples

Let’s continue working with our example, now written in a Screenplay fashion. Let’s start with the test script:

The test script itself is much more readable and easy to follow, due to the awesome DSL provided by Serenity. Let’s dissect it a little:

Using Serenity, we just need to prepare an Actor with the ability to BrowseTheWeb provided, in this case, by WebdriverIO.

In this Task, an actor with a proper Ability can Navigate to a certain URL and Ensure certain conditions are met via a Question: What is the Website.title?

In this other task, we can see how to interact and pass parameters to the application under test. All this low level interaction is very well encapsulated. We use the Serenity Library to drive, in this case, the browser.

And finally, we make use of a proper page object! That is, a Lean Page Object class that only takes care of encapsulating locators for interacting with the web page, and nothing else! Let’s keep it DRY, folks!

Reporting

One of the most interesting aspects of Serenity is the very complete Reporting you get out of it. All of the instrumentation allows for a complete reporting in different formats (console, streams, html). In the screenshot below you can see the Serenity BDD reporter with screenshots, high level tasks and low level interactions being logged, amongst other goodies. You can also create your own custom reporters.

A report showing test results from Serenity, with screenshots and documentation of the steps and time it took to execute them.
A screenshot of a Serenity/JS html report

Conclusion

I hope you’ve learned something new today, or if you already knew or work with the Screenplay pattern, you still find this article useful.

Some disclaimers that need to be made before wrapping up:

  • While using this pattern is much more scalable and maintainable, it does require very good programming skills and object oriented expertise. One could argue that the same happens with Page Object or any other pattern you follow for your software development though.
  • If you are building a new team and/or need quick wins, probably a classic Page Object project could be more beneficial. It’s simpler (at the beginning), and you have more chances to hire/attract way more test automation engineers with page object experience than with Screenplay experience.

As usual, context is key for taking any decision!

Further reading

If you find Screenplay interesting enough to keep learning about it, I recommend you to go through the following list of articles:

At Adidas, we have a good list of projects currently implementing Serenity and Screenplay Pattern across our products. Are you currently looking forward to experiment, or even implemented this in a project of your own? Please share your thoughts in the comments below.

Happy testing!

The views, thoughts, and opinions expressed in the text belong solely to the author, and do not represent the opinion, strategy or goals of the author’s employer, organization, committee or any other group or individual.

--

--

Rodrigo Julian Martin
adidoescode

I am a passionate Test Engineer from Argentina, currently living in Zaragoza, Spain.