before и after хуки

В системе валидации Vest хуки before и after используются для управления жизненным циклом выполнения правил внутри сьютов. Они позволяют выполнять побочные эффекты, подготовительные действия и постобработку, не смешивая их с логикой самих проверок. Такой подход делает валидационные сценарии более предсказуемыми и композиционно чистыми.

Общая модель выполнения сьюта

Сьют в Vest представляет собой функцию, внутри которой описываются правила валидации. При каждом запуске сьюта создаётся контекст выполнения, в рамках которого последовательно вызываются зарегистрированные правила и хуки.

Упрощённая последовательность выглядит следующим образом:

  1. Инициализация сьюта
  2. Выполнение before хуков
  3. Выполнение правил и групп правил
  4. Выполнение after хуков
  5. Завершение выполнения сьюта и формирование результата

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


Хук before

Назначение и поведение

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

Хук может быть синхронным или асинхронным, что позволяет использовать его для работы с внешними источниками данных.

Типовые сценарии использования

Инициализация состояния

Перед выполнением правил часто требуется подготовить промежуточные данные:

  • нормализация входного объекта
  • заполнение дефолтных значений
  • подготовка вычисляемых полей

Загрузка внешних данных

Если валидация зависит от серверных данных:

  • проверка уникальности значения через API
  • загрузка справочников
  • получение конфигураций пользователя

Подготовка контекста

Хук может модифицировать контекст выполнения:

  • добавление вспомогательных функций
  • установка флагов окружения
  • определение режима выполнения (strict, relaxed)

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

import { suite, test, before } from 'vest';

const validateUser = suite('user_validation', (data) => {

  before(async () => {
    data.normalizedEmail = data.email?.trim().toLowerCase();
  });

  test('email', 'invalid email format', () => {
    expect(data.normalizedEmail).toMatch(/.+@.+\..+/);
  });

});

В данном случае before выполняет нормализацию email перед запуском проверок, гарантируя единообразие данных.


Асинхронный before

Асинхронный вариант позволяет выполнять операции, требующие ожидания:

before(async () => {
  const response = await fetchUserSettings();
  data.settings = await response.json();
});

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


Влияние на порядок выполнения

before всегда выполняется один раз на запуск сьюта, независимо от количества правил внутри. Это делает его эквивалентом глобальной инициализации для конкретного сценария валидации.


Хук after

Назначение и поведение

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

В отличие от before, after не влияет на выполнение правил, так как к моменту его вызова результат уже сформирован.


Типовые сценарии использования

Логирование результатов

После завершения валидации можно отправить результаты в систему мониторинга:

  • запись ошибок в лог
  • отправка метрик
  • аналитика валидационных сценариев

Очистка ресурсов

Если в before были открыты внешние ресурсы:

  • закрытие соединений
  • сброс временных данных
  • освобождение памяти от промежуточных структур

Постобработка результатов

Иногда требуется агрегировать данные:

  • преобразование структуры ошибок
  • фильтрация несущественных сообщений
  • формирование пользовательского отчёта

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

import { suite, test, after } from 'vest';

const validateProfile = suite('profile_validation', (data) => {

  test('username', 'required field', () => {
    expect(data.username).toBeTruthy();
  });

  after((results) => {
    console.log('validation finished:', results);
  });

});

Здесь after получает итоговый объект результатов, позволяя анализировать итог выполнения всех тестов.


Асинхронный after

Как и before, after поддерживает асинхронность:

after(async (results) => {
  await sendMetrics(results);
});

Асинхронный after не влияет на возвращаемый результат сьюта, но позволяет гарантировать выполнение побочных операций до завершения процесса.


Порядок выполнения нескольких хуков

В рамках одного сьюта может быть несколько хуков before и after. Их порядок выполнения строго фиксирован.

Последовательность before

Все before хуки выполняются последовательно в порядке объявления:

before(() => {
  data.step = 1;
});

before(() => {
  data.step = 2;
});

Итоговое значение будет зависеть от последовательного изменения состояния.

Последовательность after

after хуки выполняются также в порядке регистрации, но уже после завершения всех правил:

after(() => {
  console.log('first');
});

after(() => {
  console.log('second');
});

Взаимодействие before/after с правилами

Доступ к контексту

И before, и after имеют доступ к контексту выполнения сьюта. Однако характер доступа различается:

  • before — модифицирует входные данные до начала проверок
  • after — работает с уже сформированным результатом

Изоляция состояния

Vest обеспечивает изолированное выполнение сьютов. Это означает, что изменения, внесённые в before, не протекают между различными вызовами одного и того же сьюта.


Асинхронный жизненный цикл

При наличии асинхронных хуков полный цикл выполнения приобретает следующую структуру:

  1. Запуск сьюта
  2. Выполнение всех before (ожидание завершения)
  3. Выполнение тестов и правил
  4. Формирование результата
  5. Выполнение всех after (с ожиданием завершения)
  6. Возврат результата пользователю

Такая модель обеспечивает предсказуемость даже при наличии сетевых запросов и внешних зависимостей.


Типичные ошибки при использовании хуков

Побочные эффекты в правилах вместо before

Частая ошибка — выполнение подготовительных операций внутри тестов, что приводит к дублированию логики и усложнению сопровождения.

Изменение результата в after

Попытка модифицировать результат в after не влияет на возвращаемое значение сьюта, так как результат уже сформирован к моменту вызова.

Несинхронизированные асинхронные операции

Если before или after не возвращают корректный промис, возможны гонки данных или неполная инициализация контекста.


Роль хуков в архитектуре валидации

Механизм before и after формирует слой управления жизненным циклом, отделяя бизнес-логику валидации от инфраструктурных задач. Это позволяет:

  • сохранять чистоту правил
  • централизовать подготовку данных
  • управлять побочными эффектами отдельно от проверок
  • масштабировать сложные валидационные сценарии без усложнения тестов

Такой подход делает сьюты более декларативными и устойчивыми к росту сложности логики.