Tasks and Interactions¶
Tasks vs. Interactions¶
| Task | Interaction | |
|---|---|---|
| Level | High-level, business-meaningful | Low-level, atomic |
| Composition | Can contain other Tasks and Interactions | Leaf node; directly operates on the system |
| Example | "Log in" | "Click on the login button" |
| Base class | Task |
Interaction |
Both Tasks and Interactions implement the Performable protocol, which requires a single method:
An Actor performs them with attempts_to():
Class-Based Tasks¶
Subclass Task and implement perform_as():
from screenwright import Task
class Login(Task):
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:
actor.attempts_to(
Navigate.to("/login"),
Enter.the_value(self.username).into(USERNAME_FIELD),
Enter.the_value(self.password).into(PASSWORD_FIELD),
Click.on(LOGIN_BUTTON),
)
Notice how the Task composes lower-level Interactions (Navigate, Enter, Click). This is the key advantage of the Screenplay pattern: Tasks express intent at the business level, while Interactions handle the mechanics.
Naming Convention¶
The Task base class automatically generates a human-readable name from the class name by inserting spaces before uppercase letters. Login becomes "Login", AddItemToCart becomes "Add Item To Cart". This name appears in the test report narration.
The @task Decorator¶
For simpler Tasks, you can use the @task decorator instead of a class:
from screenwright import task
@task
def login(actor, username: str, password: str) -> None:
actor.attempts_to(
Navigate.to("/login"),
Enter.the_value(username).into(USERNAME_FIELD),
Enter.the_value(password).into(PASSWORD_FIELD),
Click.on(LOGIN_BUTTON),
)
Usage:
The decorator converts the function name to a title-case label for the report. login becomes "Login", add_item_to_cart becomes "Add Item To Cart".
Class-Based Interactions¶
Subclass Interaction and implement perform_as():
from screenwright import Interaction
class Click(Interaction):
def __init__(self, target) -> None:
self.target = target
@staticmethod
def on(target) -> "Click":
return Click(target)
def perform_as(self, actor) -> None:
driver = actor.ability_to(BrowseTheWeb).driver
element = driver.find_element(*self.target.locator)
element.click()
Interactions differ from Tasks in that they:
- Directly access an Ability (like
BrowseTheWeb) - Perform a single atomic operation on the system under test
- Are not composed of other performables
The target Attribute¶
If an Interaction has a target attribute, Screenwright includes the target description in the InteractionStarted event. This appears in the report narration, for example: "Click on LOGIN_BUTTON".
Composing Tasks¶
Tasks gain their power from composition. A high-level Task can orchestrate a sequence of lower-level Tasks and Interactions:
class PlaceOrder(Task):
def __init__(self, product_name: str, quantity: int) -> None:
self.product_name = product_name
self.quantity = quantity
def perform_as(self, actor) -> None:
actor.attempts_to(
SearchFor(self.product_name),
AddToCart(quantity=self.quantity),
Checkout(),
ConfirmPayment(),
)
Each sub-Task and Interaction emits its own events, creating a nested narration in the report. The event hierarchy is maintained through parent_id fields on the events, so the report can show that SearchFor and AddToCart happened as part of PlaceOrder.
Performing Multiple Actions¶
attempts_to() accepts any number of performables:
actor.attempts_to(
Navigate.to("/products"),
SearchFor("laptop"),
AddToCart(quantity=1),
Checkout(),
)
They are executed in order. If any performable raises an exception, execution stops and the error is captured as a TaskFailed or InteractionFailed event.
Error Handling¶
When a Task or Interaction fails:
- The duration is recorded
- A
TaskFailedorInteractionFailedevent is emitted with the error type and message - The original exception is re-raised
You do not need to add try/except blocks in your Tasks or Interactions. Screenwright handles error capture automatically.