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:
- getters (
get
); - 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');
}
}
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:
- 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.
- Getters create unexpected behavior
- Since Cypress commands don’t return actual values, writing like
LoginPage.usernameField.type('testuser')
will fail because usernameField
does not return an immediate element.
- 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');
}
}
Now, you can use it correctly in your tests:
const loginPage = new LoginPage();
loginPage.usernameField().type('testuser');
loginPage.passwordField().type('password');
loginPage.loginButton().click();
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");
}
}
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")
Comparison: getters vs functions in Cypress
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');
}
}
Your test:
loginPage.usernameField().type('testuser');
While this technically works, using functions directly is a cleaner solution.
Conclusion
- Avoid getters in Cypress POMs because Cypress commands don’t return immediate elements.
- Use functions to ensure Cypress properly executes commands and handles automatic waiting.
- 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)