Cypress - Custom Commands
Cypress - Custom Commands
Section titled “Cypress - Custom Commands”Custom commands in Cypress allow you to encapsulate sequences of Cypress commands into reusable functions. This is extremely useful for abstracting common actions or complex interactions, making your tests cleaner, more readable, and easier to maintain.
Custom commands are typically defined in the cypress/support/commands.js file (or cypress/support/e2e.js if you’ve configured it that way in newer Cypress versions). This file is automatically imported before your test files run.
Syntax for Creating Custom Commands
Section titled “Syntax for Creating Custom Commands”You use Cypress.Commands.add() to define a new custom command and Cypress.Commands.overwrite() to modify an existing Cypress command (use with caution).
// Adding a new parent command (does not operate on a subject)Cypress.Commands.add('commandName', (arg1, arg2, ...) => { // Cypress commands here});
// Adding a new child command (operates on a subject yielded by a previous command)Cypress.Commands.add('commandName', { prevSubject: true }, (subject, arg1, ...) => { // subject is the value yielded from the previous command // Cypress commands here, often using cy.wrap(subject)});
// Adding a command that can be either parent or childCypress.Commands.add('commandName', { prevSubject: 'optional' }, (subject, arg1, ...) => { if (subject) { // Act as child command } else { // Act as parent command }});
// Overwriting an existing commandCypress.Commands.overwrite('existingCommandName', (originalFn, ...args) => { // originalFn is the original command function // Custom logic here, potentially calling originalFn});Key options for Cypress.Commands.add():
prevSubject(boolean | string | string[]): Determines if the command is a parent, child, or dual command.-
false(default): Parent command (e.g.,cy.login()).
-
true: Child command, requires a subject from a previous command (e.g.,cy.get('button').customClick()).
-
'element': Child command, requires subject to be a DOM element.
-
'document': Child command, requires subject to bedocument.
-
'window': Child command, requires subject to bewindow.
-
'optional': Can be a parent or child command.
Example: Creating a Login Custom Command (Parent Command)
Section titled “Example: Creating a Login Custom Command (Parent Command)”Let’s create a custom command for logging into an application. This is a common repetitive task.
In cypress/support/commands.js:
Cypress.Commands.add('login', (username, password) => { cy.visit('/login'); // Or your specific login page path cy.get('input[name="username"]').type(username); cy.get('input[name="password"]').type(password); cy.get('button[type="submit"]').click(); cy.url().should('include', '/dashboard'); // Verify successful login});Using the Custom Command in a Test
Section titled “Using the Custom Command in a Test”In your test file (e.g., cypress/e2e/login_spec.cy.js):
describe('Application Login', () => { it('Should log in successfully with valid credentials', () => { cy.login('testuser', 'password123'); // Further assertions or actions after login cy.contains('Welcome, testuser').should('be.visible'); });
it('Should attempt login with another user', () => { cy.login('anotheruser', 'securepass'); cy.contains('Welcome, anotheruser').should('be.visible'); });});Best Practices for Custom Commands
Section titled “Best Practices for Custom Commands”- Keep them focused: Custom commands should ideally perform one logical action or a small, cohesive set of actions.
- Avoid overly long commands: Very long custom commands can be hard to debug and make tests less flexible. Break down complex flows into smaller, reusable commands if possible.
- Parameterize for reusability: Use arguments to make your commands flexible for different scenarios (like username/password in the login example).
- Return subjects when appropriate: If your custom command yields a new subject (e.g., an element it found or created), ensure it’s returned so it can be chained.
- Add type definitions (TypeScript): If using TypeScript, declare your custom commands in a
.d.tsfile for better IntelliSense and type safety. Example:declare namespace Cypress { interface Chainable { login(username: string, password: string): Chainable<Element>; } }
Custom commands are a cornerstone of writing scalable and maintainable test suites in Cypress. They promote the DRY (Don’t Repeat Yourself) principle and significantly improve test clarity.