Hooks: before, beforeEach, after, afterEach

Cypress предоставляет встроенные хуки, позволяющие управлять жизненным циклом тестов. Они используются для подготовки состояния перед выполнением тестов и очистки после них. Правильное использование хуков упрощает поддержку тестового кода и повышает его стабильность.


before

Хук before выполняется один раз перед всеми тестами в блоке describe. Он применяется для действий, которые необходимо выполнить один раз на весь набор тестов: установка окружения, аутентификация, загрузка данных.

describe('Работа с формой авторизации', () => {
  before(() => {
    cy.visit('/login');
    cy.fixture('users.json').as('usersData'); // загрузка фикстуры один раз
  });

  it('Проверка успешного входа', function () {
    cy.get('input[name="username"]').type(this.usersData.validUser.username);
    cy.get('input[name="password"]').type(this.usersData.validUser.password);
    cy.get('button[type="submit"]').click();
    cy.url().should('include', '/dashboard');
  });

  it('Проверка неуспешного входа', function () {
    cy.get('input[name="username"]').type(this.usersData.invalidUser.username);
    cy.get('input[name="password"]').type(this.usersData.invalidUser.password);
    cy.get('button[type="submit"]').click();
    cy.contains('Неверные учетные данные').should('be.visible');
  });
});

Ключевые моменты использования before:

  • Выполняется один раз перед всеми тестами внутри describe.
  • Хорошо подходит для загрузки данных и авторизации.
  • Не стоит использовать для действий, которые должны повторяться перед каждым тестом.

beforeEach

Хук beforeEach выполняется перед каждым тестом внутри блока describe. Используется для подготовки состояния перед каждым тестом: сброс базы данных, очистка формы, установка начальных значений.

describe('Тестирование корзины', () => {
  beforeEach(() => {
    cy.visit('/shop');
    cy.clearCookies();
    cy.clearLocalStorage();
  });

  it('Добавление товара в корзину', () => {
    cy.get('.product').first().click();
    cy.get('button.add-to-cart').click();
    cy.get('.cart-count').should('contain', '1');
  });

  it('Удаление товара из корзины', () => {
    cy.get('.product').first().click();
    cy.get('button.add-to-cart').click();
    cy.get('.cart-count').should('contain', '1');
    cy.get('.cart-item-remove').click();
    cy.get('.cart-count').should('contain', '0');
  });
});

Особенности beforeEach:

  • Повторяется перед каждым тестом, обеспечивая чистое состояние.
  • Идеально подходит для изоляции тестов и предотвращения влияния одного теста на другой.
  • Можно использовать вложенные хуки beforeEach — внутренний будет выполняться после внешнего.

after

Хук after выполняется один раз после всех тестов внутри блока describe. Используется для глобальной очистки ресурсов: удаление тестовых данных, завершение сессий, закрытие соединений.

describe('Управление пользователями', () => {
  before(() => {
    cy.loginAdmin(); // один раз логинимся как администратор
  });

  after(() => {
    cy.deleteTestUsers(); // один раз удаляем созданных пользователей
  });

  it('Создание нового пользователя', () => {
    cy.createUser({ username: 'testUser', password: '1234' });
    cy.contains('Пользователь создан').should('be.visible');
  });
});

Рекомендации по использованию after:

  • Применять для глобальной очистки ресурсов.
  • Не использовать для восстановления состояния между тестами — для этого предназначен afterEach.
  • Хорошо комбинируется с внешними ресурсами, такими как базы данных или API.

afterEach

Хук afterEach выполняется после каждого теста внутри блока describe. Применяется для восстановления состояния после теста: очистка данных, удаление временных файлов, сброс cookies.

describe('Форма обратной связи', () => {
  beforeEach(() => {
    cy.visit('/feedback');
  });

  afterEach(() => {
    cy.clearLocalStorage();
  });

  it('Отправка корректной формы', () => {
    cy.get('input[name="email"]').type('user@example.com');
    cy.get('textarea[name="message"]').type('Тестовое сообщение');
    cy.get('button[type="submit"]').click();
    cy.contains('Спасибо за ваше сообщение').should('be.visible');
  });

  it('Попытка отправки пустой формы', () => {
    cy.get('button[type="submit"]').click();
    cy.contains('Поле обязательно для заполнения').should('be.visible');
  });
});

Особенности afterEach:

  • Выполняется после каждого теста, независимо от его успешности или ошибки.
  • Позволяет предотвращать накопление данных, влияющих на последующие тесты.
  • Часто используется совместно с beforeEach для полной изоляции тестов.

Взаимодействие хуков

Cypress поддерживает вложенные хуки, и порядок их выполнения определяется иерархией блоков describe:

  1. before внешнего блока
  2. before внутреннего блока
  3. beforeEach внешнего блока
  4. beforeEach внутреннего блока
  5. Выполнение теста
  6. afterEach внутреннего блока
  7. afterEach внешнего блока
  8. after внутреннего блока
  9. after внешнего блока

Это позволяет строить сложные сценарии с различными уровнями подготовки и очистки.


Практические рекомендации

  • Использовать before и after для действий, которые нужны один раз на весь блок тестов.
  • beforeEach и afterEach применять для изоляции тестов, чтобы исключить зависимость одного теста от другого.
  • При работе с API и базой данных использовать хуки для установки и удаления тестовых данных.
  • Сочетать хуки с фикстурами (cy.fixture) для повторного использования тестовых данных.
  • Не дублировать действия в тестах, если их можно вынести в хуки — это повышает читаемость и поддержку кода.

Хуки в Cypress позволяют создать чистую и предсказуемую среду тестирования, минимизировать побочные эффекты и ускорить процесс разработки автоматизированных тестов.