Skip to content

The Screenplay Pattern

What Is It?

The Screenplay pattern is an approach to writing automated acceptance tests that models your tests around Actors who perform Tasks and ask Questions about the system under test. It replaces the widely used Page Object Model with a more flexible, composable, and human-readable architecture.

In the Screenplay pattern, tests read like natural descriptions of user behavior:

ali.attempts_to(Login.with_credentials("admin", "secret123"))
ali.should_see_that(DashboardTitle(), "Welcome, Ali")

History

The Screenplay pattern evolved from the Journey pattern, introduced by Antony Marcano, Andy Palmer, Jan Molak, and John Ferguson Smart around 2015. It was first implemented in the Serenity BDD framework for Java and later ported to JavaScript (Serenity/JS).

Screenwright brings these ideas to the Python ecosystem, adapted to Python's conventions and integrated with pytest-bdd.

Why Screenplay Over Page Object Model?

The Page Object Model (POM) groups methods by page or component. This leads to several problems at scale:

Problem Page Object Model Screenplay Pattern
God objects Page objects accumulate dozens of methods Tasks and Questions are small, single-purpose classes
Poor reuse Logic is trapped inside a specific page object Tasks compose other Tasks and Interactions freely
Unclear intent loginPage.enterUsername("admin") describes mechanics actor.attempts_to(Login.with_credentials(...)) describes goals
Rigid coupling Tests depend on page structure Tests depend on business capabilities (Abilities)
Hard to narrate No built-in test narration Every action produces a domain event for reporting

The Six Key Concepts

The Screenplay pattern is built around six concepts:

                    performs
    Actor --------------------------> Task
      |                                |
      | has                            | composed of
      v                                v
    Ability                       Interaction
      |                                |
      | enables                        | acts on
      v                                v
     Fact                     System Under Test
      ^
      |  answers
    Question

1. Actor

An Actor represents a user or external system interacting with your application. Each Actor has a name and optionally a description of their role.

ali = Actor.named("Ali", description="a scrum master")

2. Ability

An Ability is a capability that an Actor possesses -- for example, the ability to browse the web, call an API, or query a database. Abilities are granted to Actors and retrieved by type.

ali.who_can(BrowseTheWeb.using(driver))
driver_ability = ali.ability_to(BrowseTheWeb)

3. Task

A Task is a high-level, business-meaningful goal that an Actor wants to achieve. Tasks can be composed of other Tasks and Interactions.

ali.attempts_to(Login.with_credentials("admin", "secret123"))

4. Interaction

An Interaction is an atomic, low-level action. Interactions are the leaf nodes of the action tree -- they directly manipulate the system under test through an Ability.

ali.attempts_to(Click.on(LOGIN_BUTTON))

5. Question

A Question queries the current observable state of the system. Actors ask Questions and verify the answers against expected values or predicates.

ali.should_see_that(DashboardTitle(), "Welcome, Ali")

6. Fact

A Fact is a piece of information that an Actor remembers. Facts are stored as key-value pairs and recalled later during a scenario.

ali.remembers(username="admin")
username = ali.recalls("username")

How Screenwright Implements It

Screenwright provides base classes and protocols for each concept:

Concept Base Class / Protocol Module
Actor Actor screenwright.core.actor
Ability Ability screenwright.core.ability
Task Task / @task screenwright.core.task
Interaction Interaction screenwright.core.interaction
Question Question / @question screenwright.core.question
Performable Performable (Protocol) screenwright.core.performable
Answerable Answerable (Protocol) screenwright.core.answerable
Stage Stage screenwright.core.stage
Scene Scene screenwright.core.scene
Spotlight Spotlight screenwright.core.spotlight

Every action an Actor takes emits a domain event (for example, TaskStarted, TaskCompleted, QuestionAnswered). These events feed into Screenwright's reporting system to produce the cinematic HTML report.