beforeEach() и afterEach() хуки

В тестировании с использованием Protractor для Angular-приложений важное место занимают хуки beforeEach() и afterEach(). Они обеспечивают подготовку окружения перед выполнением каждого теста и очистку после него, что позволяет создавать независимые, повторяемые и стабильные тестовые сценарии.


Назначение beforeEach()

beforeEach() выполняется до каждого тестового блока it(). Основные задачи:

  • Настройка начального состояния приложения.
  • Инициализация объектов Page Object или других вспомогательных структур.
  • Выполнение действий, общих для всех тестов, например, авторизация пользователя.
  • Настройка данных в базе или тестовом окружении.

Пример использования:

describe('Тестирование формы входа', () => {
  let loginPage;

  beforeEach(() => {
    loginPage = new LoginPage();
    browser.get('/login'); // Переход на страницу логина перед каждым тестом
  });

  it('должен показывать ошибку при неправильном пароле', async () => {
    await loginPage.enterUsername('user1');
    await loginPage.enterPassword('wrongPassword');
    await loginPage.submit();
    const error = await loginPage.getErrorMessage();
    expect(error).toContain('Неверный пароль');
  });

  it('должен успешно авторизоваться с правильными данными', async () => {
    await loginPage.enterUsername('user1');
    await loginPage.enterPassword('correctPassword');
    await loginPage.submit();
    const url = await browser.getCurrentUrl();
    expect(url).toBe('/dashboard');
  });
});

Ключевые моменты:

  • Каждый it() блок получает “чистое” состояние, обеспечивая изоляцию тестов.
  • Можно использовать асинхронные операции с async/await.
  • Созданные объекты или переменные доступны внутри тестов через область видимости describe().

Назначение afterEach()

afterEach() выполняется после каждого тестового блока it(). Основные цели:

  • Очистка или сброс состояния приложения после теста.
  • Закрытие сессий, удаление созданных тестовых данных.
  • Логирование или скриншоты при падении теста.

Пример:

describe('Тестирование формы входа', () => {
  let loginPage;

  beforeEach(() => {
    loginPage = new LoginPage();
    browser.get('/login');
  });

  afterEach(async () => {
    const logs = await browser.manage().logs().get('browser');
    if (logs.length > 0) {
      console.warn('Логи браузера после теста:', logs);
    }
  });

  it('должен показать ошибку при пустом поле пароля', async () => {
    await loginPage.enterUsername('user1');
    await loginPage.submit();
    const error = await loginPage.getErrorMessage();
    expect(error).toContain('Пароль обязателен');
  });
});

Особенности использования:

  • Асинхронные действия требуют async/await.
  • Можно использовать совместно с beforeEach() для полного цикла подготовки и очистки.
  • В сложных сценариях afterEach() помогает отлавливать ошибки, например, автоматически делать скриншоты при падении теста:
afterEach(async function() {
  if (this.currentTest.state === 'failed') {
    const png = await browser.takeScreenshot();
    require('fs').writeFileSync(`screenshots/${this.currentTest.title}.png`, png, {encoding: 'base64'});
  }
});

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

beforeEach() и afterEach() часто применяются вместе для обеспечения консистентности тестового окружения. Последовательность выполнения:

  1. beforeEach() — подготовка состояния.
  2. it() — выполнение теста.
  3. afterEach() — очистка и логирование.

Пример:

describe('Работа с элементами страницы', () => {
  let dashboardPage;

  beforeEach(() => {
    dashboardPage = new DashboardPage();
    browser.get('/dashboard');
  });

  afterEach(async () => {
    await dashboardPage.resetFilters(); // сброс фильтров после каждого теста
  });

  it('должен отображать таблицу с данными', async () => {
    const table = await dashboardPage.getTableRows();
    expect(table.length).toBeGreaterThan(0);
  });

  it('должен фильтровать данные по имени', async () => {
    await dashboardPage.applyFilter('name', 'John');
    const rows = await dashboardPage.getTableRows();
    rows.forEach(row => expect(row.name).toContain('John'));
  });
});

Практические советы

  • Для больших проектов рекомендуется создавать отдельные вспомогательные функции или Page Object методы, которые вызываются в beforeEach() для подготовки состояния.
  • afterEach() удобно использовать для чистки тестовых данных, особенно если тесты модифицируют базу.
  • В асинхронном коде обязательно использовать await, иначе beforeEach() и afterEach() могут завершиться раньше, чем будут выполнены действия на странице.
  • Хуки работают только внутри describe() блоков, глобально их использовать нельзя.

Вывод

beforeEach() и afterEach() обеспечивают изоляцию и предсказуемость тестов, создавая единый шаблон подготовки и очистки. Они позволяют писать повторяемые, стабильные и поддерживаемые тесты, минимизируя влияние одного теста на другой.

Ключевое правило: каждый тест должен быть независимым, и хуки — основной инструмент для соблюдения этого принципа в Protractor.