Mastering `cypress.commands.add` in TypeScript

Cypress is a popular end - to - end testing framework for web applications. One of its powerful features is the ability to create custom commands using cypress.commands.add. When combined with TypeScript, it becomes even more robust as TypeScript adds static typing, which helps catch errors early and provides better code intelligence. In this blog post, we will explore the fundamental concepts of cypress.commands.add in TypeScript, its usage methods, common practices, and best practices.

Table of Contents

  1. Fundamental Concepts
  2. Usage Methods
  3. Common Practices
  4. Best Practices
  5. Conclusion
  6. References

Fundamental Concepts

What is cypress.commands.add?

cypress.commands.add is a method in Cypress that allows you to create custom commands. These commands can encapsulate a series of actions that you perform frequently in your tests. For example, logging in to an application might involve multiple steps like visiting the login page, entering credentials, and clicking the login button. You can create a custom command to perform all these steps in one go.

Why use TypeScript with cypress.commands.add?

TypeScript adds type safety to your Cypress tests. When you define a custom command in TypeScript, you can specify the types of the parameters and the return type. This helps in catching type - related errors at compile - time rather than at runtime. It also makes your code more self - documenting and easier to understand and maintain.

Usage Methods

Basic Syntax

The basic syntax of cypress.commands.add in TypeScript is as follows:

// commands.ts
Cypress.Commands.add('customCommandName', (parameter1: string, parameter2: number) => {
    // Command implementation
    cy.get('selector').type(parameter1);
    cy.get('another - selector').click();
    return cy.wrap(parameter2);
});

Using the Custom Command in a Test

// example.spec.ts
describe('Test suite', () => {
    it('should use the custom command', () => {
        cy.customCommandName('test value', 123).then((result) => {
            expect(result).to.equal(123);
        });
    });
});

Common Practices

Creating a Login Command

// commands.ts
Cypress.Commands.add('login', (username: string, password: string) => {
    cy.visit('/login');
    cy.get('#username').type(username);
    cy.get('#password').type(password);
    cy.get('#login - button').click();
});
// login.spec.ts
describe('Login tests', () => {
    it('should log in successfully', () => {
        cy.login('testuser', 'testpassword');
        cy.url().should('include', '/dashboard');
    });
});

Chaining Commands

// commands.ts
Cypress.Commands.add('fillFormAndSubmit', (formData: { name: string; email: string }) => {
    cy.get('#name').type(formData.name);
    cy.get('#email').type(formData.email);
    return cy.get('#submit - button').click();
});
// form.spec.ts
describe('Form tests', () => {
    it('should fill and submit the form', () => {
        cy.visit('/form');
        cy.fillFormAndSubmit({ name: 'John Doe', email: '[email protected]' });
        cy.get('.success - message').should('be.visible');
    });
});

Best Practices

Keep Commands Small and Focused

Each custom command should have a single responsibility. For example, instead of creating a large command that does everything from logging in, navigating to a page, and performing multiple actions, break it down into smaller commands like login, navigateToPage, and performAction.

Add Type Definitions

To make your custom commands work well with TypeScript, you need to add type definitions. You can create a index.d.ts file in your Cypress project and add the following:

// index.d.ts
declare namespace Cypress {
    interface Chainable {
        customCommandName(parameter1: string, parameter2: number): Chainable<number>;
        login(username: string, password: string): Chainable<void>;
        fillFormAndSubmit(formData: { name: string; email: string }): Chainable<JQuery<HTMLElement>>;
    }
}

Error Handling

Handle errors gracefully in your custom commands. For example, if a required element is not found, you can use cy.get with a timeout and handle the error appropriately.

Cypress.Commands.add('findElement', (selector: string) => {
    return cy.get(selector, { timeout: 5000 }).then(($element) => {
        if ($element.length === 0) {
            throw new Error(`Element with selector ${selector} not found`);
        }
        return $element;
    });
});

Conclusion

cypress.commands.add in TypeScript is a powerful tool for creating custom commands in your Cypress tests. By understanding the fundamental concepts, usage methods, common practices, and best practices, you can write more maintainable, readable, and reliable tests. TypeScript adds an extra layer of safety and clarity to your custom commands, making it easier to catch errors and work with your test code.

References