DEV Community

Cover image for TestFly Part 2: Accessibility-first locators, BasePage and WaitEngine
Hakan GÜL
Hakan GÜL

Posted on Edited on Originally published at hakangul.lovable.app

TestFly Part 2: Accessibility-first locators, BasePage and WaitEngine

Semantic locators based on accessibility

Most Selenium tests find elements with brittle CSS selectors or long XPaths, and those break whenever the DOM hierarchy changes:

// Brittle — breaks on CSS redesigns:
find(By.cssSelector("div.modal > form button.btn-primary")).click();
Enter fullscreen mode Exit fullscreen mode

TestFly adds Playwright-style semantic locators. They target the accessibility tree, so a test finds elements the way a person sees them on the page:

getByRole(Role.BUTTON).withName("Submit").click();
getByLabel("Email address").type("[email protected]");
getByPlaceholder("Search products…").type("laptop");
getByText("Forgot password?").click();
getByTestId("checkout-cta").click();
Enter fullscreen mode Exit fullscreen mode

Each one returns a chainable Locator that waits on its own, so there is no Thread.sleep() in the test.

Page objects with BasePage

BasePage has helper methods that wait before they act: type, click, getText, getAttribute and isDisplayed.

package io.testfly.examples.pages;

import io.testfly.test.BasePage;
import io.testfly.locator.Role;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LoginPage extends BasePage {

    private static final By USERNAME = By.id("username");
    private static final By PASSWORD = By.id("password");

    public LoginPage(WebDriver driver) {
        super(driver);
    }

    public void login(String user, String pass) {
        type(USERNAME, user);
        type(PASSWORD, pass);
        getByRole(Role.BUTTON).withName("Sign In").click();
    }
}
Enter fullscreen mode Exit fullscreen mode

Custom waits with WaitEngine

When you need your own wait conditions, WaitEngine keeps explicit waits in one place and takes the timeout from timeouts.explicit in testfly.yml:

import io.testfly.wait.WaitEngine;

// Centralized explicit wait conditions:
WaitEngine.waitForVisible(By.id("dashboard-banner"));
WaitEngine.waitForClickable(By.id("pay-button"));
WaitEngine.waitForInvisible(By.cssSelector(".loading-spinner"));
Enter fullscreen mode Exit fullscreen mode

Top comments (0)