Параметризованные сообщения

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

Статические сообщения и их ограничения

Базовый подход к описанию ошибок валидации выглядит следующим образом:

test('username', 'Имя пользователя некорректно', () => {
  enforce(username).isNotBlank();
});

Такая форма работает, но быстро становится ограниченной. Сообщение:

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

При росте числа правил появляются дублирования и потеря информативности.

Переход к параметризованным сообщениям

Vest позволяет задавать сообщение как функцию. Это ключевой механизм параметризации:

test('username', 'invalid username', () => {
  enforce(username).longerThan(3);
}).message(({ field, value }) => {
  return `Поле "${field}" слишком короткое: "${value}"`;
});

Здесь сообщение становится динамическим:

  • field — имя проверяемого поля
  • value — текущее значение
  • контекст ошибки формируется на этапе выполнения теста

Это позволяет одной и той же проверке возвращать разные сообщения в зависимости от входных данных.

Контекст параметров сообщения

Функция сообщения в Vest получает объект контекста, который может включать:

  • field — идентификатор поля
  • value — текущее значение
  • args — аргументы, переданные в enforce
  • meta — дополнительные данные, если они используются в тестовом наборе

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

test('password', 'password too short', () => {
  enforce(password).longerThan(8);
}).message(({ field, args }) => {
  const min = args[0];
  return `Поле "${field}" должно содержать минимум ${min} символов`;
});

Здесь параметр 8 становится частью текстового сообщения, что делает ошибку более точной.

Инлайновые параметризованные сообщения

Часто сообщение задаётся прямо внутри проверки через функцию:

test('age', 'invalid age', () => {
  enforce(age).greaterThan(18)
    .message(({ value }) => `Возраст ${value} не подходит для регистрации`);
});

Такой подход делает код компактным и локализованным, особенно в небольших тестах.

Использование шаблонной интерполяции

Параметризованные сообщения часто строятся через шаблонные строки:

.message(({ field, value }) =>
  `Ошибка в поле ${field}: значение "${value}" недопустимо`
);

Однако при усложнении логики лучше избегать чрезмерной вложенности и переносить генерацию текста в отдельные функции:

const createErrorMessage = ({ field, value, reason }) =>
  `Поле ${field} содержит ошибку: ${reason}. Текущее значение: ${value}`;

test('email', 'invalid email', () => {
  enforce(email).matches(/@/);
}).message(({ field, value }) =>
  createErrorMessage({
    field,
    value,
    reason: 'отсутствует символ @'
  })
);

Условная параметризация сообщений

В реальных сценариях сообщение часто зависит от условий:

test('password', 'weak password', () => {
  enforce(password).matches(/[A-Z]/)
    .message(({ value }) => {
      if (!/[A-Z]/.test(value)) {
        return 'Пароль должен содержать хотя бы одну заглавную букву';
      }
      return 'Пароль не соответствует требованиям';
    });
});

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

Локализация и параметризованные сообщения

Параметризация тесно связана с интернационализацией. Вместо жёстко заданных строк используются словари:

const messages = {
  required: ({ field }) => `Поле ${field} обязательно`,
  minLength: ({ field, args }) =>
    `Поле ${field} должно быть не короче ${args[0]} символов`
};

test('username', messages.required, () => {
  enforce(username).isNotBlank();
});

Такой подход позволяет:

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

Переиспользование генераторов сообщений

В больших проектах удобно выделять фабрики сообщений:

const minLengthMessage = (min) =>
  ({ field, value }) =>
    `Поле ${field} (${value}) должно быть минимум ${min} символов`;

test('nickname', 'too short', () => {
  enforce(nickname).longerThan(5);
}).message(minLengthMessage(5));

Это создаёт повторно используемые шаблоны для разных полей и правил.

Ошибки при параметризации сообщений

При использовании параметризованных сообщений часто возникают типичные проблемы:

  • Игнорирование контекста приводит к сообщениям без конкретики

  • Избыточная логика в message-функции усложняет поддержку и тестирование

  • Дублирование генерации строк снижает читаемость кода

  • Отсутствие стандарта форматирования приводит к несогласованному UX ошибок

Оптимальный подход — держать сообщения максимально предсказуемыми и переносить сложные вычисления в отдельные функции.

Композиция сообщений из нескольких источников

В сложных схемах валидации сообщение может собираться из нескольких уровней:

const baseMessage = ({ field }) => `Ошибка в поле ${field}`;

const detailMessage = ({ value }) => `Некорректное значение: ${value}`;

test('score', 'invalid score', () => {
  enforce(score).between(0, 100);
}).message((ctx) => `${baseMessage(ctx)}. ${detailMessage(ctx)}`);

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

Параметризация через метаданные тестов

Иногда полезно передавать дополнительные параметры через структуру тестов:

test('limit', 'limit exceeded', () => {
  enforce(limit).lessThan(maxLimit);
}, { meta: { severity: 'high' } })
.message(({ meta }) => {
  return meta.severity === 'high'
    ? 'Критическое превышение лимита'
    : 'Превышение лимита';
});

Метаданные усиливают выразительность системы сообщений и позволяют внедрять бизнес-логику в текст ошибок без нарушения структуры теста.