Forem

Cover image for Getters vs. functions in Cypress: The best practice you need to know
Daniil
Daniil

Posted on

Getters vs. functions in Cypress: The best practice you need to know

Recently I've observed that some of us, QA Automation engineers, are still using getters in their test automation frameworks with Cypress.
When working with the Page Object Model in Cypress (Yes, you could use POMs if your web application is big, has a lot of micro services, micro frontends, and plenty of configurations and settings), you might come across two ways to define element selectors:

  1. getters (get);
  2. functions (method()).

Cypress works differently from Selenium & Playwright

Cypress executes commands asynchronously, meaning .get() does not return an element immediately like in Selenium or Playwright. Instead, Cypress commands are added to an internal queue and resolved automatically when Cypress executes them.
It means that getters won’t work as expected when trying to interact with elements.

Example of a getter (incorrect approach in Cypress)

class LoginPage {
  get usernameField() {
    //Cypress does NOT return an element immediately:
    return cy.get('#username'); 
  }
}
Enter fullscreen mode Exit fullscreen mode

This fails because Cypress does not return an immediate element reference. Instead, it returns a Cypress chainable object, which requires further chaining for interactions like .type(), .click(), or .should(). Instead, they return a Cypress chain that must be resolved in Cypress' command queue.

Why getters fail in Cypress

Using getters in Cypress is problematic because:

  1. Cypress commands are not immediately resolved
  • Cypress chains commands and executes them sequentially. Getters try to return an element immediately, which breaks Cypress' execution model.
  1. Getters create unexpected behavior
  • Since Cypress commands don’t return actual values, writing like
LoginPage.usernameField.type('testuser') 
Enter fullscreen mode Exit fullscreen mode

will fail because usernameField does not return an immediate element.

  1. Lack of explicit execution
  • Cypress follows a declarative approach, where you describe what should happen, and Cypress handles the execution. Getters hide Cypress commands inside properties, making it harder to debug.

The correct approach: use functions instead

Instead of getters, define element selectors as functions. This ensures Cypress correctly waits for elements before interacting with them.

Correct Page Object Model with function approach

Option 1 - Returning a Cypress command for chaining

class LoginPage {
  usernameField() {
    return cy.get('#username');
  }

  passwordField() {
    return cy.get('#password');
  }

  loginButton() {
    return cy.get('#login');
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, you can use it correctly in your tests:

const loginPage = new LoginPage();
loginPage.usernameField().type('testuser');
loginPage.passwordField().type('password');
loginPage.loginButton().click();
Enter fullscreen mode Exit fullscreen mode

This approach ensures Cypress waits for elements to be available before performing actions.

Let me add something here and explain 1 more thing...

Option 2 - Cleaner and better - Performing an action inside the function

class LoginPage {
  usernameField() {
    //Works without return:
    cy.get('#username').type("123");
  }
}
Enter fullscreen mode Exit fullscreen mode

So, would you use return or not?

Use return when:

  • you need to perform multiple actions in a test (.type(), .clear(), .should(), etc.).
  • you want to chain commands later.

Don't use return when:

The function directly executes an action inside it (like .type("123")).

Just compare the next two rows and look which is better and cleaner for your test scripts.

// Option 1:
loginPage.usernameField().clear().type("testuser")

// Option 2:
loginPage.enterUsername("testuser")
Enter fullscreen mode Exit fullscreen mode

Comparison: getters vs functions in Cypress

Table

When can getters work in Cypress?

If you are migrating from Selenium or (for some reason) from Playwright you might still want to use getters. Then you must return a function inside the getter. However, this adds unnecessary complexity.

Your POM:

class LoginPage {
  get usernameField() {
    //This will work but unnecessary complexity:
    return () => cy.get('#username'); 
  }
}
Enter fullscreen mode Exit fullscreen mode

Your test:

loginPage.usernameField().type('testuser');
Enter fullscreen mode Exit fullscreen mode

While this technically works, using functions directly is a cleaner solution.

Conclusion

  1. Avoid getters in Cypress POMs because Cypress commands don’t return immediate elements.
  2. Use functions to ensure Cypress properly executes commands and handles automatic waiting.
  3. By switching from getters to functions, you’ll write cleaner, more maintainable Cypress tests that follow its execution model.

Have you ever faced issues with getters in Cypress or you think it still better than using functions? Drop your thoughts in the comments below!

Check out more about chaining on official Cypress portal

Top comments (0)