DEV Community

TestDino
TestDino

Posted on

Mistake 6/14: Stop Putting Assertions in Page Objects

A developer wants to keep their tests "dry," so they put the expect statement inside the Page Object method. It makes sense at first. login() handles everything: fill the form, click the button, confirm you’re on the dashboard. One method. Clean. ✅

Until you need to test a failed login. ✖️

Now your login() method asserts success but your negative test is looking for a failure. To fix it, you add loginExpectingFailure(). Then loginAndCheckError(). Six login methods later, your POM is a graveyard of duplicated logic.

This is the exact trap teams fall into when a suite grows.

Page Objects should be simple. They store locators and perform actions. That is it. Assertions belong in the test file, where the intent of the test is immediately visible.

The Clean Pattern

Instead of baking the assertion into the class, keep the class "pure":

class LoginPage {
  async login(user, pass) {
    await this.emailInput.fill(user);
    await this.passInput.fill(pass);
    await this.submitBtn.click();
  }
}
Enter fullscreen mode Exit fullscreen mode

Then, handle the different outcomes in your actual test files:

// Happy path
test('success', async ({ page, loginPage }) => {
  await loginPage.login('user@test.com', 'pass123');
  await expect(page).toHaveURL('/dashboard');
});

// Negative path
test('failure', async ({ page, loginPage }) => {
  await loginPage.login('user@test.com', 'wrong');
  await expect(loginPage.error).toBeVisible();
});
Enter fullscreen mode Exit fullscreen mode
  • One method: A single login() method with zero assertions.
  • Visible Intent: Anyone reading the test knows exactly what is being verified.
  • No Bloat: No duplicated methods. No boolean flags. No loginVersion4().

Do you enforce a "no assertions in POM" rule on your team, or is it a free-for-all? Drop it in the comments.

playwright #testing #automation #sdet

Top comments (0)