Skip to main content
SeleniumDecoded
Back to Challenges

Extract a Page Object

intermediate Java 20 min

Three tests repeat the same login steps with inline locators. Extract a LoginPage that hides locators and waits.

The Scenario

The login page is about to get a redesign: the email field becomes a username field and the submit button gets a test id. Three tests contain the same four locators, and there are twelve more tests in other files that log in the same way.

Your Task

Extract a LoginPage class so a locator change is a one-line fix, and rewrite the three tests to use it. Assume a DashboardPage with an isWelcomeVisible() method exists.

What Good Looks Like

  • Locators are private and appear once.
  • Public methods are named for what a user does, not for which element they touch.
  • Navigation methods return the next page object; waits live inside the page object.
  • The tests shrink to a few readable lines each.

Your task

Three tests repeat the same login steps with inline locators. Extract a LoginPage that hides locators and waits.

Problem Code
@Test void loginShowsDashboard() {
    driver.get("https://app.example.com/login");
    driver.findElement(By.id("email")).sendKeys("qa@example.com");
    driver.findElement(By.id("password")).sendKeys("secret");
    driver.findElement(By.cssSelector("button[type=submit]")).click();
    new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.urlContains("/dashboard"));
    assertTrue(driver.findElement(By.cssSelector("h1.welcome")).isDisplayed());
}

@Test void wrongPasswordShowsError() {
    driver.get("https://app.example.com/login");
    driver.findElement(By.id("email")).sendKeys("qa@example.com");
    driver.findElement(By.id("password")).sendKeys("wrong");
    driver.findElement(By.cssSelector("button[type=submit]")).click();
    WebElement error = new WebDriverWait(driver, Duration.ofSeconds(10))
        .until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".alert-error")));
    assertEquals("Invalid credentials", error.getText());
}

@Test void emptyFormShowsValidation() {
    driver.get("https://app.example.com/login");
    driver.findElement(By.cssSelector("button[type=submit]")).click();
    assertEquals(2, driver.findElements(By.cssSelector(".field-error")).size());
}

Need Help?

Solution

Try to solve the challenge yourself before revealing the solution.

Lessons that cover this