Your First Test¶
This guide walks through a complete working example: a BDD feature file, step definitions using the Screenplay pattern, a custom Ability, and the fluent API.
1. Create a Feature File¶
Create features/login.feature:
Feature: User login
As a registered user
I want to log in to the application
So that I can access my dashboard
Scenario: Successful login with valid credentials
Given Ali is a registered user
When Ali logs in with username "admin" and password "secret123"
Then Ali should see the dashboard
2. Define an Ability¶
Abilities represent what an Actor can do. Here is a simple example that wraps a mock authentication client:
# abilities.py
from screenwright import Ability
class AuthenticateWithAPI(Ability):
"""The ability to authenticate against the application API."""
def __init__(self, client):
self.client = client
@staticmethod
def using(client):
return AuthenticateWithAPI(client)
3. Create Tasks¶
Tasks are high-level, business-meaningful goals. You can write them as classes or use the @task decorator.
Class-based Task¶
# tasks.py
from screenwright import Task
class Login(Task):
"""Log in with the given credentials."""
def __init__(self, username: str, password: str) -> None:
self.username = username
self.password = password
@staticmethod
def with_credentials(username: str, password: str) -> "Login":
return Login(username, password)
def perform_as(self, actor) -> None:
client = actor.ability_to(AuthenticateWithAPI).client
response = client.login(self.username, self.password)
actor.remembers(auth_token=response["token"])
Decorator-based Task¶
from screenwright import task
@task
def login(actor, username: str, password: str) -> None:
"""Log in with the given credentials."""
client = actor.ability_to(AuthenticateWithAPI).client
response = client.login(username, password)
actor.remembers(auth_token=response["token"])
Both approaches produce the same result. The decorator style is more concise; the class style is better when you need factory methods like Login.with_credentials(...).
4. Create a Question¶
Questions query the current state of the system:
# questions.py
from screenwright import Question
class DashboardTitle(Question[str]):
"""What is the title shown on the dashboard?"""
def answered_by(self, actor) -> str:
client = actor.ability_to(AuthenticateWithAPI).client
token = actor.recalls("auth_token")
return client.get_dashboard(token)["title"]
Or with the decorator:
from screenwright import question
@question
def dashboard_title(actor) -> str:
"""What is the title shown on the dashboard?"""
client = actor.ability_to(AuthenticateWithAPI).client
token = actor.recalls("auth_token")
return client.get_dashboard(token)["title"]
5. Write Step Definitions¶
Wire everything together in your step definitions using pytest-bdd:
# test_login.py
import pytest
from pytest_bdd import scenario, given, when, then, parsers
from screenwright import Actor
from abilities import AuthenticateWithAPI
from tasks import Login
from questions import DashboardTitle
@scenario("features/login.feature", "Successful login with valid credentials")
def test_successful_login():
pass
@given("Ali is a registered user")
def ali(stage):
mock_client = MockAPIClient() # your test double
return (
stage.actor_named("Ali", description="a registered user")
.who_can(AuthenticateWithAPI.using(mock_client))
)
@when(
parsers.parse('Ali logs in with username "{username}" and password "{password}"'),
)
def ali_logs_in(ali, username, password):
ali.attempts_to(Login.with_credentials(username, password))
@then("Ali should see the dashboard")
def ali_sees_dashboard(ali):
ali.should_see_that(DashboardTitle(), "Welcome, Ali")
6. Run It¶
Screenwright's pytest plugin automatically:
- Creates a Stage and Scene for each scenario
- Captures every event (actor entrance, tasks, interactions, questions)
- Generates a cinematic HTML report in
screenwright-report/
Open screenwright-report/index.html in your browser to see the result.
What Just Happened?¶
Here is what Screenwright did behind the scenes:
- FeatureStarted -- recorded that the "User login" feature began
- SceneStarted -- recorded the "Successful login" scenario
- ActorEnteredStage -- Ali was placed on the Stage
- AbilityGranted -- Ali received the AuthenticateWithAPI ability
- TaskStarted / TaskCompleted -- the Login task was performed
- FactRemembered -- Ali remembered the auth_token
- QuestionAsked / QuestionAnswered -- DashboardTitle was checked
- SceneEnded -- the scenario completed with a "passed" outcome
- FeatureEnded -- the feature file finished
All of these events are stored in screenwright-report/event-stream.json and rendered into the HTML report.