Custom commands fixed repeated actions, like login. There is a second kind of repetition, and it hurts just as much.
Look at these three lines. They appear in eight different test files:
cy.get('[data-testid="contact-name-input"]').type('Dana');
cy.get('[data-testid="contact-email-input"]').type('dana@foxlabs.io');
cy.get('[data-testid="save-contact"]').click();
A developer renames contact-name-input to contact-full-name. Now you search the whole project for that string and fix eight files. Miss one, and a test fails tomorrow for a reason that has nothing to do with the feature.
The answer is to keep the selectors in one place. Create a file that describes the screen:
export const contactForm = {
name: () => cy.get('[data-testid="contact-name-input"]'),
email: () => cy.get('[data-testid="contact-email-input"]'),
save: () => cy.get('[data-testid="save-contact"]'),
fill(contact) {
this.name().type(contact.name);
this.email().type(contact.email);
this.save().click();
},
};
Each key is a small function that returns the element. fill is a shortcut that uses them together. When the developer renames that test id, you change one line in one file.
Your test then reads almost like English:
contactForm.fill({ name: 'Dana Fox', email: 'dana@foxlabs.io' });
cy.contains('[data-testid="contact-row"]', 'Dana Fox').should('exist');
This pattern has a name: the Page Object Model. You will be asked about it in interviews. The short answer they want is: it keeps selectors and page actions in one place, so a UI change is one edit instead of many.
Now the mistake almost everyone makes at first. Do not put your checks inside the page object:
// Do not do this
verifyContactSaved() {
cy.get('[data-testid="toast"]').should('contain', 'Contact created');
}
It looks tidy, but now nobody can read a test and see what it proves. They have to open another file. Keep it simple: the page object holds selectors and actions. The test holds the checks.
Remember this: if you cannot tell what a test proves without opening a second file, you have gone too far.
Reference: Best Practices.