Skip to content
AP

Ajdin Proho

1 article

June 8, 2026

Interacting with Web Elements using Serenity Screenplay

QA/Test Automation

Interacting with Web Elements using Serenity Screenplay

What is Serenity Screenplay?   Screenplay is a test automation design pattern used to write readable, maintainable tests; it is part of Serenity BDD. Screenplay uses a model based on the Actors. Every Screenplay test has at least one actor (you can also have multiple actors). You can model scenarios involving multiple users, each with specific Abilities and Interactions. Besides Actors, other important components of Screenplay are Tasks, Interactions, Questions, and Abilities. Tasks and Actions are reusable across different test scenarios, helping minimize code duplication.   To use Screenplay, you will have to add these dependencies into pom.xml file:   <dependency>    <groupId>net.serenity-bdd</groupId>    <artifactId>serenity-screenplay</artifactId>    <version>4.2.34</version>         </dependency> <dependency>    <groupId>net.serenity-bdd</groupId>    <artifactId>serenity-screenplay-webdriver</artifactId>    <version>4.2.34</version> </dependency> Actors An actor represents a user who interacts with the application. Actors have abilities, such as the ability to interact with a web browser. They also perform tasks, interactions, and answer questions to check whether the feature behaves as we expect.   This is how we define an actor and give the actor the ability to interact with a web browser using Selenium WebDriver: final Actor actor = new Actor("User").can(BrowseTheWeb.with(getDriver()));   When writing code with Selenium, it can get a little messy; with a lot of code, it can become hard to read or maintain. For example, it can take a lot of time to figure out the best way to interact with a specific button on a page. With Screenplay, we use actors to perform interaction: Selenium example: getDriver().get("https://testingpage.com/login"); final WebElement username = getDriver().findElement(By.id("username")); username.sendKeys("John-Doe"); final WebElement password = getDriver().findElement(By.id("password")); password.sendKeys("pass123"); final WebElement loginButton = getDriver().findElement(By.id("login")); loginButton.click();   In this example, we can see: Selenium focuses on how you find an element and click on it or type into the field. Code repeats. Screenplay example:   actor.attemptsTo(  Open.url("https://testingpage.com/login"),        SendKeys.of("John-Doe").into(By.id("username")),        SendKeys.of("pass123").into(By.id("password")),        Click.on(Button.withText("Login")) ); OR You can create a separate CommonFields class where you will store common fields: public static final Target USERNAME = Target.the("Username field").located(By.id("username")); public static final Target PASSWORD = Target.the("Password field").located(By.id("password")); public static final Target LOGIN_BUTTON = Target.the("Login button").located(By.id("login"));   And then use it in a test:   actor.attemptsTo(        Open.url("https://examplepage.com/login"),        SendKeys.of("John-Doe").into(CommonFields.USERNAME),        SendKeys.of("pass123").into(CommonFields.PASSWORD),        Click.on(CommonFields.LOGIN_BUTTON) ); In this example, an actor performs a sequence of actions, which describes what the user does, not how it is done. It is readable, reusable, and maintainable. If an element changes, you only need to update it in one place. Tasks A task is a high-level action that an actor performs. It consists of smaller interactions like clicking, typing, etc. We can additionally create a task for login: public class LoginTask implements Task {    private final String username;    private final String password;   public LoginTask(final String username, final String password) {        this.username = username;        this.password = password;    }  public static LoginTask usingData(final String username, final String password) {        return new LoginTask(username, password);    }   @Override   public <T extends Actor> void performAs(T actor) {        actor.attemptsTo(                SendKeys.of(username).into(CommonFields.USERNAME),                SendKeys.of(password).into(CommonFields.PASSWORD),                Click.on(CommonFields.LOGIN_BUTTON)        );    } } And then use it in test:   actor.attemptsTo(        Open.url("https://examplepage.com/login"),        LoginTask.usingData("John-Doe", "pass123") );     In previous examples, we saw how to click on some element or type into the field. Next, we will see more basic interactions: Move mouse Move the mouse on a specific element (for example, you can use it to trigger a tooltip): actor.attemptsTo(MoveMouse.to(CommonFields.LOGIN_BUTTON)); Double click actor.attemptsTo(DoubleClick.on(target)); Right click actor.attemptsTo(RightClick.on(target)); Enter value This will enter a value into a field, first it will wait until the field is enabled, and then clear the field of any current values, before entering the specified value: actor.attemptsTo(Enter.theValue("John-Doe").into(CommonFields.USERNAME)); Upload file Files can be placed in a hard-coded location or stored on the classpath, which is a better solution:   actor.attemptsTo(Upload.theFile(Path.of("test/data/api/files/" + fileName +".extension")).to(uploadField)); Questions When an actor wants to get a specific piece of information from the system, it can be done using a Question. Questions are queries about the application's state. Actors ask questions using the method askFor().   Some of the common Question classes are: Text.of()   final String text = actor.asksFor(Text.of(TARGET_ELEMENT));   This will extract the text of a target element and return the value that you can use for assertion.   When working with table, we can extract data from cells:   final List<String> tableHeaders = actor.asksFor(Text.ofEach(HEADERS)); final List<List<String>> tableRows = actor.asksFor(Text.ofEach(ROWS)); isVisible() boolean isVisible = actor.asksFor(Visibility.of(TARGET_ELEMENT));   This checks whether a UI element is displayed. isDisabled() boolean isDisabled = actor.asksFor(Disabled.of(TARGET_ELEMENT));   This will check whether an element is disabled. Presence.of() boolean isPresent = actor.asksFor(Presence.of(TARGET_ELEMENT)); This checks whether the element is present in the DOM. Conclusion With Serenity Screenplay, you can write clean and maintainable automation tests using Actors, Abilities, Tasks, and Questions. Instead of just writing a bunch of code with Screenplay, your automation code will be easy to read and understand for both QA and developers. It is also important to know that Screenplay doesn’t replace Selenium; they work together. Selenium is the engine that communicates with the browser, and Screenplay is the pattern that makes your tests feel like a story.

Ready to Achieve More?

We’ll help you reach your goals quickly with an easy and straightforward process to kick off our collaboration. Here’s what happens next.

STEP 1

Discovery Call

Let’s chat to understand your company, project needs, and answer any questions along the way.

STEP 2

Free Consultation

Work closely with our experts to explore the right solutions for your business.

STEP 3

Collaboration Proposal

We'll recommend the best strategy for your goals, ensuring you get the most from our expertise.

STEP 4

30-Day Cancellation
Policy Contract

Spoiler: It’s Never Been Used

Enjoy peace of mind while we deliver excellence from day one—our track record speaks for itself.

Services you're interested in (Optional)