🎬 Screenplay Pattern - Part 2: Actions
In the Screenplay pattern, once you've defined your actor, the next question is:
What can this actor do?
That's where Actions come in.
🛠️ What are Actions?
Actions are the building blocks of your test.
They define how an actor interacts with the system — but in a reusable and readable way.
Instead of spreading low-level commands all over your tests, you create named tasks that express intention, like:
   bankCustomer.makeAction('enterLoginCredentials', {
                email: validUser.email,
                password: validUser.password,
            });
It tells you exactly what’s happening — not how it’s implemented.
How the actions works:
- I use an class for each feature of our system:
 
export class LoginActions {
    enterLoginCredentials(input: { email?: string; password?: string }) {
        loginPage.waitForPageToLoad();
        if (input.email) {
            cy.get(loginPage.getEmailInputSelector())
                .filter(':visible')
                .should('be.enabled')
                .clear()
                .type(input.email, { delay: 50 });
        }
        if (input.password) {
            cy.get(loginPage.getPasswordInputSelector())
                .filter(':visible')
                .should('be.enabled')
                .clear()
                .type(input.password, { delay: 50 });
        }
    }
}
The UI selectors are stored in a separate file. By keeping selectors in their own file, they can be reused across different actions.
After this, the actors who can perform this actions, only need:
export default class BankCustomer extends BaseActor {
    constructor() {
        const loginActions = new LoginActions();
        super(loginActions);
    }
}
So when you read a test and see an action, it tells you what is being done — not how it's done. If you want to check the implementation, just search for the action name or look it up in the documentation. (Screenplay makes documenting tests easier — more on that later!)
âś… Why use Actions?
Readable: Your test reads like a user story.
Reusable: One action can be used across many scenarios.
Maintainable: If the UI changes, you update the action, not every test.
In short:
Actions help you write tests that describe behavior, not code.
They're a key piece in making automation feel like a conversation between the user and the system.
Next post: ❓Questions – how do we verify what happened?
              
    
Top comments (0)