Skip to content

Stage and Scene

The Stage and Scene bring the theatre metaphor to life. They manage Actor lifecycle and ensure each test scenario runs in isolation.

Stage

The Stage is the environment in which Actors perform during a test session. It is responsible for:

  • Creating Actors and wiring them with the event publisher
  • Managing the Spotlight -- tracking which Actor is currently active
  • Coordinating Scene boundaries -- clearing Actors between scenarios

Creating Actors Through the Stage

Use actor_named() to get or create an Actor:

ali = stage.actor_named("Ali", description="a scrum master")

If an Actor named "Ali" already exists on the Stage, the existing Actor is returned and the Spotlight shifts to them. Otherwise, a new Actor is created, placed on the Stage, and illuminated by the Spotlight.

Actors created through the Stage are automatically wired with the event publisher, so all their actions are captured for the report.

The Spotlight

The Spotlight tracks which Actor is currently active. When a scenario involves multiple Actors, the Spotlight shifts as each Actor takes their turn:

ali = stage.actor_named("Ali")
maryam = stage.actor_named("Maryam")

# Spotlight is on Maryam (the last Actor created or referenced)
current = stage.in_the_spotlight()  # returns Maryam

# Explicitly shift the Spotlight
stage.shine_spotlight_on(ali)
current = stage.in_the_spotlight()  # returns Ali

If no Actor is in the Spotlight (for example, before any Actor has been created), calling in_the_spotlight() raises NoActorInSpotlightError.

Each Spotlight change emits a SpotlightChanged event, which appears in the report timeline.

Scene

A Scene represents a single test scenario. It carries metadata about the scenario:

  • name -- the scenario name
  • feature_name -- the feature this scenario belongs to
  • tags -- BDD tags associated with the scenario

Scene Lifecycle

When a new Scene begins, the Stage clears any Actors from the previous Scene:

scene = stage.new_scene(
    name="Successful login",
    feature_name="User login",
    tags=["smoke"],
)

This ensures that each scenario starts with a clean slate. Actors do not leak between scenarios.

Clearing the Stage

At the end of each Scene, stage.clear() is called:

  1. An ActorExitedStage event is emitted for each Actor
  2. All Actors are removed
  3. The Spotlight is cleared
  4. The current Scene is set to None

How pytest-bdd Manages Stage and Scene

When using Screenwright with pytest-bdd, you do not need to manage the Stage or Scene lifecycle manually. The Screenwright plugin handles it:

  1. Session start -- a single Stage and event publisher are created for the entire test session
  2. Before each scenario -- stage.new_scene() is called with the scenario name, feature name, and tags; a SceneStarted event is emitted
  3. During the scenario -- Actors are created on the Stage through fixtures; all events are captured
  4. After each scenario -- a SceneEnded event is emitted with the outcome (passed/failed/skipped); stage.clear() removes all Actors
  5. Session end -- FeatureEnded events are emitted for all tracked features; the event stream is serialized and the HTML report is generated

Using the Stage Fixture

The plugin provides a stage fixture you can use in your step definitions:

@given("Ali is a registered user")
def ali(stage):
    return stage.actor_named("Ali", description="a registered user")

The stage fixture is session-scoped, meaning all scenarios in a session share the same Stage instance. However, Actors are cleared between scenarios, so each scenario gets a fresh set of Actors.

Feature Tracking

Since pytest-bdd does not have feature-level hooks, Screenwright tracks feature boundaries by observing which feature each scenario belongs to. A FeatureStarted event is emitted the first time a scenario from a new feature is encountered. At session end, FeatureEnded events are emitted for all tracked features with aggregated pass/fail/skip counts.