Cypress.Commands.add()

Cypress предоставляет мощный механизм для создания собственных команд через метод Cypress.Commands.add(). Это позволяет инкапсулировать повторяющиеся действия, упрощать поддержку тестов и повышать читаемость кода. В основе лежит возможность определить новую команду, которая становится доступной во всех тестах как часть цепочки cy.

Синтаксис и базовое использование

Cypress.Commands.add(name, callback);
  • name — строка, определяющая название новой команды.
  • callback — функция, которая выполняет действие команды. Может принимать аргументы.

Пример простой команды:

Cypress.Commands.add('login', (username, password) => {
    cy.get('#username').type(username);
    cy.get('#password').type(password);
    cy.get('button[type="submit"]').click();
});

После объявления команды её можно использовать в тестах:

describe('Тестирование логина', () => {
    it('Успешный вход', () => {
        cy.visit('/login');
        cy.login('user1', 'password123');
        cy.url().should('include', '/dashboard');
    });
});

Передача аргументов и обработка значений

Команды могут принимать несколько аргументов, включая объекты конфигурации:

Cypress.Commands.add('fillForm', ({ name, email, message }) => {
    cy.get('#name').type(name);
    cy.get('#email').type(email);
    cy.get('#message').type(message);
    cy.get('button[type="submit"]').click();
});

Вызов команды:

cy.fillForm({ name: 'Иван', email: 'ivan@mail.com', message: 'Привет!' });

Передача аргументов через объект повышает читаемость и масштабируемость тестов, особенно если полей формы много.

Асинхронные операции и цепочка cy

Команды в Cypress автоматически поддерживают цепочку cy. Это позволяет создавать асинхронные действия, которые корректно интегрируются с остальной частью теста.

Пример команды с ожиданием:

Cypress.Commands.add('waitAndClick', (selector, timeout = 5000) => {
    cy.get(selector, { timeout }).should('be.visible').click();
});

Использование:

cy.waitAndClick('#submit-button');

Создание команд с возвратом значения

Команды могут возвращать значение для дальнейшей обработки в цепочке cy. Важно использовать cy.wrap() для правильной интеграции с Cypress:

Cypress.Commands.add('getUserName', () => {
    return cy.get('#username').invoke('text').then((text) => {
        return text.trim();
    });
});

В тесте:

cy.getUserName().then((name) => {
    expect(name).to.equal('Иван');
});

Обработка ошибок внутри команд

Для повышения устойчивости тестов можно добавлять обработку ошибок в собственные команды. Cypress автоматически прерывает тест при падении любого действия, но иногда требуется более гибкая логика:

Cypress.Commands.add('clickIfExists', (selector) => {
    cy.get('body').then(($body) => {
        if ($body.find(selector).length) {
            cy.get(selector).click();
        }
    });
});

Команды с вложенными командами

Собственные команды могут использовать другие команды Cypress внутри себя. Это создает возможность строить более сложные и переиспользуемые действия:

Cypress.Commands.add('completeLoginFlow', (username, password) => {
    cy.visit('/login');
    cy.login(username, password);
    cy.url().should('include', '/dashboard');
});

Пространство имен и разделение команд

Для организации большого набора команд часто создают отдельные файлы внутри папки cypress/support/commands.js или отдельные модули:

// cypress/support/authCommands.js
Cypress.Commands.add('login', (username, password) => {
    cy.get('#username').type(username);
    cy.get('#password').type(password);
    cy.get('button[type="submit"]').click();
});

// cypress/support/formCommands.js
Cypress.Commands.add('fillForm', ({ name, email, message }) => {
    cy.get('#name').type(name);
    cy.get('#email').type(email);
    cy.get('#message').type(message);
    cy.get('button[type="submit"]').click();
});

В cypress/support/e2e.js их подключение обеспечивается через import './authCommands' и import './formCommands'.

Рекомендации по использованию Cypress.Commands.add()

  • Создавать команды для повторяющихся действий, чтобы минимизировать дублирование кода.
  • Использовать аргументы в виде объектов для команд с большим количеством параметров.
  • Обрабатывать асинхронность через цепочки cy и cy.wrap().
  • Разделять команды по функциональности и хранить в отдельных файлах.
  • Тщательно документировать команды, чтобы другие разработчики понимали их назначение.

Использование Cypress.Commands.add() повышает читаемость и поддерживаемость тестового кода, позволяет создавать надежные и гибкие тестовые сценарии, а также стандартизировать поведение тестов в рамках проекта.