Валидационные сообщения в Vest представляют собой не просто статические строки, а гибкий механизм генерации текста на основе состояния теста, входных данных и контекста выполнения. Параметризация сообщений позволяет превращать универсальные правила в осмысленные, контекстно-зависимые ошибки, которые адаптируются под конкретное поле, значение и сценарий проверки.
Базовый подход к описанию ошибок валидации выглядит следующим образом:
test('username', 'Имя пользователя некорректно', () => {
enforce(username).isNotBlank();
});
Такая форма работает, но быстро становится ограниченной. Сообщение:
При росте числа правил появляются дублирования и потеря информативности.
Vest позволяет задавать сообщение как функцию. Это ключевой механизм параметризации:
test('username', 'invalid username', () => {
enforce(username).longerThan(3);
}).message(({ field, value }) => {
return `Поле "${field}" слишком короткое: "${value}"`;
});
Здесь сообщение становится динамическим:
field — имя проверяемого поляvalue — текущее значениеЭто позволяет одной и той же проверке возвращать разные сообщения в зависимости от входных данных.
Функция сообщения в Vest получает объект контекста, который может включать:
enforceПример использования аргументов:
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'
? 'Критическое превышение лимита'
: 'Превышение лимита';
});
Метаданные усиливают выразительность системы сообщений и позволяют внедрять бизнес-логику в текст ошибок без нарушения структуры теста.