Over the years I’ve had the chance to play with many tools and frameworks. When I started out writing automated tests I was keen to bring as much of my Object Oriented Programming knowledge to the task as I could. Back then, I was still learning really… and I made mistakes.
One such mistake was to fall into the trap of over-reliance on the Page Object Model. Now, I want to make it clear, there is nothing inherently wrong with the P.O.M; like any tool or framework or pattern, it comes down to how you use it, how well you understand its limitations, and avoiding the tendency to overuse the tool.
Looking back to those early years on my journey, it seems as though every QA reached for the Page Object Model when creating their test-suites. And if I’m honest, they didn’t apply SOLID principles:
- Single Responsibility Principle – a class should only have a single responsibility, that is, only changes to one part of the software’s specification should be able to affect the specification of the class
- Open-Closed Principle – open for extension, but closed for modification
- Liskov substitution Principle – objects in a program should be replaceable with instances of their sub-types without altering the correctness of that program
- Interface segregation – many client-specific interfaces are better than one general-purpose interface
- Dependency Inversion Principle – depend upon abstractions, not concretions
It wasn’t until I came across the Screenplay Pattern (formerly known as the Journey Pattern) that I realised the mistakes I was making, and how common they are in the QA community. I started to learn that Page Objects typically break the SOLID principles above.
They quickly become unwieldy as testers start to sub-consciously adhere to the prevailing convention and add elements or actions in places they really shouldn’t be placed. The thinking around test design begins to be dictated by the structure of the page objects themselves rather than the true user journeys or business requirements.
Another common mistake is to look at each page and write a page object that covers every element available on that page, plus every conceivable action. That leads to breaking the YAGNI “You Ain’t Gonna Need It” – rule.
The Screenplay Pattern is an attempt at providing a mechanism for the development of acceptance tests based on SOLID principles.
Each user is treated as an actor on a stage. The stage is global. Each actor can ask questions about the state of the SUT; they have abilities (think adaptors) that allow them to perform tasks against the SUT – (each task is made up of one or more actions / interactions that are made available by the abilities the actor has). See below:
Here is where Serenity-JS comes in to the picture. Serenity-JS is an acceptance testing framework designed to enable testers & developers to create user-centric test scenarios, utilising a domain-specific-language tailored to each domain and each business, making it scale-able.
It’s not just for testing your front-end either; yes it provides the tools to test the UI, but it also provides the tools to test HTTP/REST API’s, manage Node.js HTTP servers and provides easy integration with Cucumber.js, Jasmine or Protractor.
Another very useful facet of Serenity-JS is the ‘living’ documentation – insightful reporting showing requirements coverage as well as test execution. The idea of this high-quality reporting is to show not only what your system does but also why it is doing it. This can help boost confidence that the business requirements are being delivered – building the right thing, in the right way. This is helped by the DSL that truly conveys the business lingo and supports collaboration between stakeholders and the tech teams, allowing the entire delivery team to own the automated tests and increasing the chances that they will be of a high-quality and given the proper level of importance.
It advocates object composition instead of traditional inheritance. Crucially it also derives at least part of its design from Domain Driven Design ideas. It allows the construction of meaningful layers of abstraction encouraging good practices and test-suite design that is scale-able, clean, easy-to-read and maintain.
In a large corporate I worked with, the use of Serenity-JS meant that all the Developers and QA’s worked collaboratively together and with the business stakeholders. Together we fleshed out and created example test scenarios, using the Screenplay pattern and Serenity-JS abstraction to embody the business value we arrived at and wanted to deliver.
- Web and cross-browser testing
- HTTP(s) and REST API testing
- Workflow testing
- Multi-actor testing
- In-depth reporting and automatic screenshots
- An easy way to introduce and follow SOLID design principles
- An effortless integration with popular test and collaboration tools, such as Cucumber.js and Jasmine.
- An easy way of sharing the test code across projects and teams”
- Provides Abilities and an asynchronous communication mechanism to enable you to use those various (often incompatible) tools together in perfect harmony and a single test suite, or even a single test.
- Gives you a powerful and elegant model to create business-focused DSLs – the Screenplay Pattern, which also takes care of intricacies of the asynchronous nature of the underlying tools leaving your tests free of noise.
- Uses its deep insight into the activities performed by your test actors, as well as information sourced from the low-level integration tools and test runners to provide you with comprehensive test execution reports and living documentation.”
It follows the Single Responsibility Principle by using interactions that use the domain specific language and are focused on doing one thing. E.g. “Click on a button”, “Enter monthly contribution into a form field”. If you want to implement an interaction that performs more than one thing, you can compose them into a task.
It follows the Open-Closed Principle because, unlike in the traditional inheritance context, you don’t need to change the Actor class to add new abilities – you simply create a new ability and a task to use it.
It follows the Liskov Substitution Principle, for example, allowing you to have a UI implementation of a task, and a REST implementation of the same task.
It follows the Interface Segregation Principle by using very narrow interfaces, allowing you to combine them in order to add complexity.
Finally, it follows the Dependency Inversion Principle. Serenity-JS works like in-memory microservices with actors interacting with the SUT on a stage. You are able to bring as many or as few stage crew members in as you need. This can increase the value of your reporting, without adding to the complexity of your tests.
Here’s an interesting point as well: actors can be users, or external systems.
A Simple Example
For more comprehensive examples, have a look at the repo via the link below and the Serenity-JS handbook via the link near the bottom of this post. But, for a simple example, here’s a todo list test:
The easiest way to get started is to take a look at the templates available here https://github.com/serenity-js
The two main contributors to this repo are Jan Molak and John Ferguson Smart.
There are some interesting updates coming up. Two such updates are Bridging the Communications Gap, and Full Stack Acceptance Testing. Keep your eyes on the Serenity-JS Handbook at the link below for more on these.
© Copyright 2022 Cognito Square Ltd
Like what you see? Please support us with a donation.
Support Cognito Square Ltd with a one-off donation in order to help us continue to publish helpful QA Automation and Agile Project Delivery articles.