Actions¶
Actions are the things that an Actor
can do,
using their Abilities.
Using Actions¶
Actions can be used pretty much anywhere.
They will typically be used to create Tasks
or move around in your Features.
Here is an example of using the Click
action:
from screenpy.actions import Click
from ..user_interface.homepage import LOGIN_LINK
Perry.attempts_to(Click.on_the(LOGIN_LINK))
Actors will always only attempt
to perform an action.
They may not actually have the correct Abilities,
after all.
If an actor is unable to perform an action or task,
they will raise an UnableToPerformError
.
Writing New Actions¶
Occasionally,
you might find that the base actions
don’t quite cover
a unique use case you have
for your test suite.
Since Screenplay Pattern is built to be extensible,
it is easy and encouraged
to create your own custom actions
to achieve what you need!
The only requirement for creating more actions
is that they have a perform_as
method defined
which takes in the actor who will perform the action.
A base class for Actions is provided
to ensure the required methods
are defined:
screenpy.actions.base_action.BaseAction
Let’s take a look
at what an extremely contrived custom action,
ChecksTheSpelling
,
might look like:
# actions/checks_the_spelling.py
from screenpy.actions import BaseAction
class ChecksTheSpelling(BaseAction):
@staticmethod
def of_words_in_the(locator):
return ChecksSpelling(locator)
def perform_as(self, the_actor):
the_actor.uses_ability_to(CheckSpelling).to_check()
def __init__(self, locator):
self.locator = locator
ScreenPy attempts to follow a convention
of putting all the static methods first,
then the perform_as
function,
and leaving the dunder methods at the bottom.
This way the most important methods are first
for someone perusing your code.
Tasks¶
Sometimes, your actors might repeat the same series of actions several times. A grouping of common actions can be abstracted into a Task in your Tasks.
A common task for Screenplay Pattern suites is logging in to your application under test. This login task might look something like this:
# tasks/login.py
import os
from screenpy import Actor
from screenpy.actions import BaseAction, Click, Enter
from ..user_interface.homepage import (
SIGN_ON_LINK,
THE_USERNAME_FIELD,
THE_PASSWORD_FIELD,
LOGIN_BUTTON,
)
class LoginSuccessfully(BaseAction):
"""
Log in to the application successfully.
"""
@staticmethod
def using_credentials(username: str, password: str) -> "LoginSuccessfully":
"""
Supply the credentials for the account.
Args:
username: the username to use.
password: the password to use.
"""
return LoginSuccessfully(username, password)
def perform_as(self, the_actor: Actor) -> None:
"""
Asks the actor to log in to the application.
Args:
the_actor: the actor who will perform this task.
Raises:
UnableToPerformError: the actor does not have the ability to
BrowseTheWeb.
"""
the_actor.attempts_to(
Click.on(SIGN_ON_LINK),
Wait.for_the(THE_USERNAME_FIELD).to_appear(),
Enter.the_text(self.username).into(THE_USERNAME_FIELD),
Enter.the_text(self.password).into(THE_PASSWORD_FIELD),
Click.on_the(LOGIN_BUTTON)
)
def __init__(self, username: str, password: str):
self.username = username
self.password = password
And there you have it!
Now all you have to do
is ask your actor
to attempt to LoginSuccessfully
,
and you’ve got the same set of actions everywhere.
Note that tasks,
just like actions,
are required to have a perform_as
method defined.
You can use the BaseAction
class
for tasks as well.
Provided Actions¶
Open¶
-
class
screenpy.actions.open.
Open
(location: Union[str, object])¶ A very important action; opens the browser! An Open action is expected to be instantiated via its static
browser_on()
method. A typical invocation might look like:Open.browser_on(the_homepage_url)
Open.browser_on(HomepageObject)
If you pass in an object, make sure the object has a url property that can be referenced by this action.
It can then be passed along to the
Actor
to perform the action.-
static
browser_on
(location: Union[str, object]) → screenpy.actions.open.Open¶ Creates a new Open action which holds its destined location.
Parameters: location – The URL to open when this action is performed, or an object containing a url property that holds the URL to open when this action is performed. Returns: Open
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the supplied actor to perform this Open action, using their ability to browse the web.
Parameters: the_actor – The Actor
who will perform the action.Raises: |UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
static
their_browser_on
(location: Union[str, object]) → screenpy.actions.open.Open¶ Syntactic sugar for
browser_on()
.
-
static
Click¶
-
class
screenpy.actions.click.
Click
(target: screenpy.target.Target)¶ Clicks on an element! A Click action is expected to be instantiated via its static
on()
oron_the()
methods. A typical invocation might look like:Click.on_the(PROFILE_LINK)It can then be passed along to the
Actor
to perform the action.-
static
on
(target: screenpy.target.Target) → screenpy.actions.click.Click¶ Syntactic sugar for
on_the()
.
-
static
on_the
(target: screenpy.target.Target) → screenpy.actions.click.Click¶ Creates a new Click action with its crosshairs aimed at the provided target.
Parameters: target – The Target
describing the element to click.Returns: Click
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to find the element described by the stored target, and then clicks it. May wait for another target to appear, if
then_wait_for()
had been called.Parameters: the_actor – the
Actor
who will perform the action.Raises: |DeliveryError|
– an exception was raised by Selenium.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
then_wait_for
(target: screenpy.target.Target) → screenpy.actions.click.Click¶ Syntactic sugar for
then_wait_for_the()
.
-
then_wait_for_the
(target: screenpy.target.Target) → screenpy.actions.click.Click¶ Supplies a target to wait for after performing the click.
This method has been deprecated as of version 1.0.0. Please use the included
Wait
action instead. This method will be removed in version 2.0.0.Parameters: target – The Target
describing the element to wait for after performing the click.Returns: Click
-
static
Clear¶
-
class
screenpy.actions.clear.
Clear
(target: screenpy.target.Target)¶ Clears the text from an input field. A Clear action is expected to be instantiated by its static
the_text_from()
method. A typical invocation might look like:Clear.the_text_from(COMMENT_FIELD)It can then be passed along to the
Actor
to perform the action.-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to performs the Clear action, clearing the text from the targeted input field using their ability to browse the web.
Parameters: the_actor – The Actor
who will perform this action.Raises: |UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
static
the_text_from
(target: screenpy.target.Target) → screenpy.actions.clear.Clear¶ Syntactic sugar for
the_text_from_the()
.
-
Enter¶
-
class
screenpy.actions.enter.
Enter
(text: str, mask: bool = False)¶ Enters text into an input field. An Enter action is expected to be instantiated by its static
the_text()
method. A typical invocation might look like:Enter.the_text(“Hello world!”).into(COMMENT_FIELD)It can then be passed along to the
Actor
to perform the action.-
into
(target: screenpy.target.Target) → screenpy.actions.enter.Enter¶ Supplies the target to enter the text into. This is most likely an input field.
Parameters: target – The Target
describing the input field.Returns: Enter
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to perform the Enter action, entering the text into the targeted input field using their ability to browse the web.
If this Enter object’s
then_hit()
method was called, it will also hit the supplied keys. Finally, if thethen_wait_for()
method was called, it will wait for the supplied target to appear.Parameters: the_actor – the
Actor
who will perform this action.Raises: |DeliveryError|
– an exception was raised by Selenium.|UnableToActError|
– no target was supplied.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
static
the_keys
(text: str) → screenpy.actions.enter.Enter¶ Syntactic sugar for
the_text()
.
-
static
the_password
(text: str) → screenpy.actions.enter.Enter¶ Syntactic sugar for
the_secret()
.
-
static
the_secret
(text: str) → screenpy.actions.enter.Enter¶ Creates a new Enter action with the provided text, but will mask the text for logging. The text will appear as “[CENSORED]” in the report. It is expected that the next call will be to the instantiated Enter object’s
into()
method.Parameters: text – the text to enter into the target, but it’s a secret. Returns: Enter
-
static
the_text
(text: str) → screenpy.actions.enter.Enter¶ Creates a new Enter action with the provided text. It is expected that the next call will be to the instantiated Enter object’s
into()
method.Parameters: text – the text to enter into the target. Returns: Enter
-
then_hit
(*keys) → screenpy.actions.enter.Enter¶ Supplies additional keys to hit after entering the text, for example if the keyboard ENTER key should be pressed.
Parameters: keys – the keys to hit afterwards. These are probably the constants from Selenium’s Keys, but they can be strings if you know the codes. Returns: Enter
-
then_press
(*keys) → screenpy.actions.enter.Enter¶ Syntactic sugar for
then_hit()
.
-
then_wait_for
(target: screenpy.target.Target) → screenpy.actions.enter.Enter¶ Supplies the target to wait for after entering text (and hitting any additional keys, if this object’s
then_hit()
method was called).This method has been deprecated as of version 1.0.0. Please use the included
Wait
action instead. This method will be removed in version 2.0.0.Parameters: target – the Target
to wait for after entering text.Returns: Enter
-
Enter2FAToken¶
-
class
screenpy.actions.enter_2fa_token.
Enter2FAToken
(target: screenpy.target.Target)¶ Enters the current two-factor authentication token into an input field. An Enter2FAToken action is expected to be instantiated by its static
into_the()
method. A typical invocation might look like:Enter2FAToken.into_the(2FA_INPUT_FIELD)It can then be passed along to the
Actor
to perform the action.-
static
into
(target: screenpy.target.Target) → screenpy.actions.enter_2fa_token.Enter2FAToken¶ Syntactic sugar for
into_the()
-
static
into_the
(target: screenpy.target.Target) → screenpy.actions.enter_2fa_token.Enter2FAToken¶ Provide the input field into which to enter the 2FA token.
Parameters: target – the Target
describing the input field.Returns: Enter2FAToken
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to perform the Enter2FAToken action, which will get the current token using the actor’s AuthenticateWith2FA ability.
Parameters: the_actor – the Actor
who will perform this action.Raises: |UnableToPerformError|
– if the actor does not have the abilities toAuthenticateWith2FA
andBrowseTheWeb
.
-
static
Select¶
-
class
screenpy.actions.select.
Select
¶ Selects an option from a dropdown menu. This is an entry point that will create the correct specific Select action that will need to be used, depending on how the option needs to be selected. Some examples of invocations:
Select.the_option_named(“January”).from_the(MONTH_DROPDOWN)
Select.the_option_at_index(0).from_the(MONTH_DROPDOWN)
Select.the_option_with_value(“jan”).from_the(MONTH_DROPDOWN)
It can then be passed along to the
Actor
to perform the action.-
static
the_option_at_index
(index: Union[int, str]) → screenpy.actions.select.SelectByIndex¶ Instantiate a SelectByIndex class which will select the option at the specified index. This index is 0-based.
Parameters: index – the index (0-based) of the option to select. Returns: SelectByIndex
-
static
the_option_named
(text: str) → screenpy.actions.select.SelectByText¶ Instantiate a SelectByText class which will select the option with the given text.
Parameters: text – the text of the option to select. Returns: SelectByText
-
static
the_option_with_value
(value: str) → screenpy.actions.select.SelectByValue¶ Instantiate a SelectByText class which will select the option with the given text.
Parameters: value – the value of the option to select. Returns: SelectByText
-
static
-
class
screenpy.actions.select.
SelectByText
(text: str, target: Optional[screenpy.target.Target] = None)¶ A specialized Select action that chooses the option by text. This class is meant to be accessed via the Select action’s static
the_option_named()
method. A typical invocation might look like:Select.the_option_named(“January”).from_the(MONTH_DROPDOWN)It can then be passed along to the
Actor
to perform the action.-
from_
(target: screenpy.target.Target) → screenpy.actions.select.SelectByText¶ Syntactic sugar for
from_the()
.
-
from_the
(target: screenpy.target.Target) → screenpy.actions.select.SelectByText¶ Provides the target to select the option from.
Parameters: target – the Target
describing the dropdown or multi-select element to select the option from.Returns: SelectByText
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to attempt to find the dropdown element described by the stored target, then performs the select action.
Parameters: the_actor – The
Actor
who will perform the action.Raises: |DeliveryError|
– an exception was raised by Selenium.|UnableToActError|
– no target was supplied.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
-
class
screenpy.actions.select.
SelectByIndex
(index: Union[int, str], target: Optional[screenpy.target.Target] = None)¶ A specialized
Select
action that chooses the option by its index. This class is meant to be accessed via the Select action’s staticthe_option_at_index()
method. A typical invocation might look like:Select.the_option_at_index(0).from_the(MONTH_DROPDOWN)It can then be passed along to the
Actor
to perform the action.-
from_
(target: screenpy.target.Target) → screenpy.actions.select.SelectByIndex¶ Syntactic sugar for
from_the()
.
-
from_the
(target: screenpy.target.Target) → screenpy.actions.select.SelectByIndex¶ Provides the target to select the option from.
Parameters: target – The Target
describing the dropdown or multi-select element to select the option from.Returns: SelectByIndex
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to attempt to find the dropdown element described by the stored target, then performs the select action.
Parameters: the_actor – The
Actor
who will perform the action.Raises: |DeliveryError|
– an exception was raised by Selenium.|UnableToActError|
– no target was supplied.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
-
class
screenpy.actions.select.
SelectByValue
(value: Union[int, str], target: Optional[screenpy.target.Target] = None)¶ A specialized Select action that chooses the option by its value. This class is meant to be accessed via the Select action’s static
the_option_with_value()
method. A typical invocation might look like:Select.the_option_with_value(“jan”).from_the(MONTH_DROPDOWN)It can then be passed along to the
Actor
to perform the action.-
from_
(target: screenpy.target.Target) → screenpy.actions.select.SelectByValue¶ Syntactic sugar for
from_the()
.
-
from_the
(target: screenpy.target.Target) → screenpy.actions.select.SelectByValue¶ Provides the target to select the option from.
Parameters: target – The Target
describing the dropdown or multi-select element to select the option from.Returns: SelectByValue
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to attempt to find the dropdown element described by the stored target, then performs the select action.
Parameters: the_actor – The
Actor
who will perform the action.Raises: |DeliveryError|
– an exception was raised by Selenium.|UnableToActError|
– no target was supplied.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
AcceptAlert¶
-
class
screenpy.actions.accept_alert.
AcceptAlert
¶ Accepts an alert. An AcceptAlert action is expected to be instantiated as it is, no static methods for this one. The only invocation looks like:
AcceptAlert()It can then be passed along to the
Actor
to perform the action.-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to perform the AcceptAlert action.
Parameters: the_actor – The
Actor
who will perform this action.Raises: |BrowsingError|
– no alert was present.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
DismissAlert¶
-
class
screenpy.actions.dismiss_alert.
DismissAlert
¶ Dismisses an alert. An DismissAlert action is expected to be instantiated as it is, no static methods for this one. The only invocation looks like:
DismissAlert()It can then be passed along to the
Actor
to perform the action.-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to perform the DismissAlert action.
Parameters: the_actor – The
Actor
who will perform this action.Raises: |BrowsingError|
– no alert was present.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
RespondToThePrompt¶
-
class
screenpy.actions.respond_to_the_prompt.
RespondToThePrompt
(text: str)¶ Responds to a javascript prompt by entering the specified text and accepting the prompt. RespondToThePrompt is expected to be instantiated using its
with_()
static method. A typical instantiation might look like:RespondToThePrompt.with_(“I am big. It’s the pictures that got small.”)It can then be passed along to the
Actor
to perform the action.-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to perform the RespondToPrompt action.
Parameters: the_actor – The
Actor
who will perform this action.Raises: |BrowsingError|
– no alert was present.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
static
with_
(text: str) → screenpy.actions.respond_to_the_prompt.RespondToThePrompt¶ Specifies the text to enter into the prompt.
Parameters: text – the text to enter. Returns: RespondToTheText
-
SwitchTo¶
-
class
screenpy.actions.switch_to.
SwitchTo
(target: Optional[screenpy.target.Target])¶ Switches to something, most likely an iframe, or back to default. A SwitchTo action is expected to be instantiated by its static
the()
ordefault()
methods, or on its own. A typical invocation might look like:SwitchTo.the(ORDERS_FRAME)
SwitchTo.default()
It can then be passed along to the
Actor
to perform the action.-
static
default
() → screenpy.actions.switch_to.SwitchTo¶ Switches back to the default frame, the browser window.
Returns: SwitchTo
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to perform the SwitchTo action.
Parameters: the_actor – The Actor
who will perform this action.Raises: |UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
static
Wait¶
-
class
screenpy.actions.wait.
Wait
(seconds: int = 20, target: Optional[screenpy.target.Target] = None)¶ Waits for an element to fulfill a certain condition. A Wait action is expected to be instantiated by its
for_()
method, followed by one of its strategies. By default, theto_appear()
strategy is used. Wait can also be instantiated with an integer, like Wait(30), which will set the timeout to be used. Some examples of invocations:Wait.for_the(LOGIN_FORM)
Wait.for_the(WELCOME_BANNER).to_contain_text(“Welcome!”)
Wait.for(CONFETTI).to_disappear()
Wait(10).seconds_for_the(PARADE_FLOATS).to_appear()
It can then be passed along to the
Actor
to perform the action.-
static
for_
(target: screenpy.target.Target) → screenpy.actions.wait.Wait¶ Creates a new Wait action holding the provided target.
Parameters: target – The Target
to wait for.Returns: Wait
-
static
for_the
(target: screenpy.target.Target) → screenpy.actions.wait.Wait¶ Syntactic sugar for
for_()
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to perform the Wait action, using the contained strategy and any extra arguments provided.
Parameters: the_actor – The
Actor
who will perform this action.Raises: |UnableToActError|
– no target was supplied.|UnableToPerformError|
– the actor does not have the ability toBrowseTheWeb
.
-
seconds_for
(target: screenpy.target.Target) → screenpy.actions.wait.Wait¶ Sets the target after invoking
Wait
with the number of seconds you want wait to allow the target to fulfill the expected condition. For example:Wait(60).seconds_for(CONFETTI).to_disappear()This will ask the actor to wait up to 60 seconds for CONFETTI to disappear before throwing an exception.
Parameters: target – The Target
to wait for.Returns: Wait
-
seconds_for_the
(target: screenpy.target.Target) → screenpy.actions.wait.Wait¶ Syntactic sugar for
seconds_for()
-
to_appear
() → screenpy.actions.wait.Wait¶ Uses Selenium’s “visibility of element located” strategy. This is the default strategy, so calling this is not strictly necessary.
Returns: Wait
-
to_be_clickable
() → screenpy.actions.wait.Wait¶ Uses Selenium’s “to be clickable” strategy.
Returns: Wait
-
to_contain_text
(text: str) → screenpy.actions.wait.Wait¶ Uses Selenium’s “text to be present in element” strategy.
Parameters: text – the text to expect to be present. Returns: Wait
-
static
Pause¶
-
class
screenpy.actions.pause.
Pause
(number: float)¶ Pauses the actor’s actions for a set amount of time. This class should only be used when absolutely necessary. You must call one of the “…_because” methods to pass in the reason for your pause; an
UnableToActError
will be raised if no reason was given when the actor attempts to perform this action.A Pause action is expected to be instantiated by its static
for_()
method, followed by one of the methods that supply a reason (seconds_because, second_because, or milliseconds_because). A typical invocation might look like:Pause.for_(500).milliseconds_because(“the welcome banner needs to hide.”)It can then be passed along to the
Actor
to perform the action.-
static
for_
(number: int) → screenpy.actions.pause.Pause¶ How many seconds or milliseconds to wait for.
Parameters: number – the number of seconds or milliseconds to sleep for. Returns: Pause
-
milliseconds_because
(reason: str) → screenpy.actions.pause.Pause¶ Tells the Pause instance to use milliseconds and provides a reason for the pause. Hard waits are the worst of all wait strategies, so providing a reason will help explain why it was necessary to use this strategy.
Parameters: reason – the reason for needing to pause. Returns: Pause
-
perform_as
(the_actor: screenpy.actor.Actor) → None¶ Asks the actor to take their union-mandated break.
Parameters: the_actor – the Actor
who will perform this action.Raises: |UnableToActError|
– no reason was supplied.
-
second_because
(reason: str) → screenpy.actions.pause.Pause¶ Syntactic sugar for Pause.seconds_because
-
seconds_because
(reason: str) → screenpy.actions.pause.Pause¶ Tells the Pause instance to use seconds and provides a reason for the pause. Hard waits are the worst of all wait strategies, so providing a reason will help explain why it was necessary to use this strategy.
Parameters: reason – the reason for needing to pause. Returns: Pause
-
static
Debug¶
-
class
screenpy.actions.debug.
Debug
¶ In long chains of actions, it can be difficult to drop a debugger in the right place. This action can be placed anywhere in the chain to give you a debugger in the middle of the action chain. This action uses Python 3.7+’s breakpoint() call if it can, otherwise it will default to pdb.set_trace().
A Debug action is expected to be instantiated in the standard way. A typical instantiation will always look like:
Debug()It can then be passed along to the
Actor
to perform the action.