Understanding the Screenplay Pattern in Test Automation
Test automation often starts simple a few UI actions, maybe a Page Object or two. But as the system grows, maintaining and scaling those tests becomes a real challenge.
Enter the Screenplay Pattern: a powerful, actor-based model for writing clean, reusable, and maintainable tests.
What is the Screenplay Pattern?
The Screenplay Pattern is a test automation design pattern that models test scripts like a movie script involving Actors, Tasks, Abilities, Interactions, and Questions.
It encourages us to:
- Think in terms of what the actor does, not how
- Build modular, readable, and reusable test logic
- Focus on behavior rather than implementation
Key Building Blocks
Actor
Represents the user or persona interacting with the system.
Actor yusuf = Actor.named("Yusuf").whoCan(BrowseTheWeb.with(driver));
Task
A meaningful action or series of steps the actor performs.
public class Login implements Task {
public static Login withCredentials(String username, String password) {
return instrumented(Login.class, username, password);
}
public <T extends Actor> void performAs(T actor) {
actor.attemptsTo(
Enter.theValue(username).into(USERNAME_FIELD),
Enter.theValue(password).into(PASSWORD_FIELD),
Click.on(LOGIN_BUTTON)
);
}
}
Usage:
yusuf.attemptsTo(Login.withCredentials("admin", "1234"));
Question
Used to extract information from the system, like validations or assertions.
public class WelcomeMessage implements Question<String> {
public String answeredBy(Actor actor) {
return Text.of(WELCOME_MESSAGE_LOCATOR).viewedBy(actor).asString();
}
}
Usage:
String message = yusuf.asksFor(new WelcomeMessage());
Ability
Defines what the actor can do. For example, browse the web or call APIs.
BrowseTheWeb.with(driver); // Enables web interactions
Target: Screenplay’s Way of Handling Locators
If you stuck with POM and cant quit completely(like me) you can still integrate it to your POM too. Instead of using Page Object Model and WebElements, the Screenplay Pattern uses Target objects to define locators.
In traditional POM:
@AndroidFindBy(accessibility = "Login Screen")
public WebElement loginScreen;
In Screenplay:
public final class LandingPage {
private LandingPage() {} // Prevent instantiation
public static final Target LOGIN_SCREEN = Target.the("Login screen")
.locatedByAccessibilityId("Login Screen");
public static final Target ECHO_BOX_SCREEN = Target.the("Echo Box screen")
.locatedByAccessibilityId("Echo Box");
public static final Target LIST_DEMO_SCREEN = Target.the("List Demo screen")
.locatedByAccessibilityId("List Demo");
public static final Target LIST_DATE_SCREEN = Target.the("Date Picker screen")
.locatedByAccessibilityId("Picker Demo");
public static final Target WEBVIEW_SCREEN = Target.the("WebView screen")
.locatedByAccessibilityId("Webview Demo");
}
And in your tasks:
actor.attemptsTo(
Click.on(LandingPage.LOGIN_SCREEN)
);
Benefits:
- No need for PageFactory or WebElement instantiation
- Targets are
static
, so they can be reused anywhere
- Fully integrates with Screenplay’s task-based structure
If you're using Appium with Serenity, you can also use:
Target LOGIN_SCREEN = Target.the("Login screen")
.located(MobileBy.AccessibilityId("Login Screen"));
Benefits of Screenplay Pattern
- Improved readability (tests look like real scenarios)
- High reusability (Tasks & Questions are shared across tests)
- Better scalability for growing test suites
- Strong adherence to SOLID principles
If you notice classes not using extends keyword for inheritance.(Congrats you are detail-oriented person) Because Screenplay prefers Composition over Inheritance.
Inheritance in Page Object Model vs. Implementation in Screenplay Pattern
One of the key architectural differences between the Page Object Model (POM) and the Screenplay Pattern lies in their use of object-oriented principles—specifically, inheritance versus implementation.
Page Object Model: Inheritance-Based Structure
In POM, it is common to use inheritance via the extends
keyword. Typically, a base class (e.g., BasePage
) is created to house shared functionalities such as clicking elements, sending input, or waiting for elements. All page classes then extend this base class to inherit these methods. This approach promotes code reuse but can lead to tightly coupled and less flexible designs.
public class BasePage {
public void click(WebElement element) {
element.click();
}
}
public class LoginPage extends BasePage {
WebElement loginButton;
}
Screenplay Pattern: Interface Implementation
Screenplay, on the other hand, follows a more composition-driven design by using interfaces like Task
, Question
, or Interaction
, which are implemented rather than extended. This provides greater flexibility and promotes the principle of "composition over inheritance."
Each Actor
performs actions by executing these Tasks or Questions, making the codebase more modular and maintainable.
public class Login implements Task {
private final String username;
private final String password;
public static Login withCredentials(String username, String password) {
return Tasks.instrumented(Login.class, username, password);
}
@Override
public <T extends Actor> void performAs(T actor) {
actor.attemptsTo(
Enter.theValue(username).into(LoginPage.USERNAME_FIELD),
Enter.theValue(password).into(LoginPage.PASSWORD_FIELD),
Click.on(LoginPage.LOGIN_BUTTON)
);
}
}
While POM is easier to grasp and implement for smaller test suites, the Screenplay Pattern offers a more scalable and maintainable architecture for complex testing needs.
Comparison: POM vs Screenplay
Feature | Page Object Model | Screenplay Pattern |
Structure | Page-based | Actor-based |
Code Reuse | Inheritance | Composition |
Reusability | Moderate | High |
Readability | Good | Excellent |
Maintainability | Challenging in large projects | Easier due to modularity |
Test Style | Imperative | Declarative |
Design Focus | Pages & Elements | Tasks & Behaviors |
Final Thoughts
The Screenplay Pattern takes a bit of setup at the beginning, because its a approach rather than ready-to-use methods.(Serenity Library comes with that methods!) but the benefits in clarity, reusability, and scalability are huge especially in large automation projects. If you're building or maintaining a serious test framework, it's worth giving Screenplay a try!
Thanks for reading.