В архитектуре Vest ключевым строительным блоком является suite — набор правил валидации, объединённых в единый декларативный блок. Статический suite формируется один раз при объявлении и не зависит от внешних параметров выполнения. Его структура фиксирована и заранее известна до момента запуска валидации.
Статический suite характеризуется тем, что:
Типичный пример статического suite:
import { create, test, enforce } from 'vest';
const suite = create((data = {}) => {
test('username', 'Имя пользователя обязательно', () => {
enforce(data.username).isNotEmpty();
});
test('email', 'Некорректный email', () => {
enforce(data.email).matches(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
});
});
В этом примере структура проверки полностью фиксирована: всегда
проверяются username и email, независимо от
входных данных или внешнего состояния.
Статические suite особенно эффективны в сценариях:
С точки зрения исполнения статический suite позволяет системе кешировать логику выполнения, поскольку набор тестов не изменяется между вызовами. Это снижает накладные расходы на пересборку графа проверок.
Динамический suite представляет собой функцию, которая генерирует набор проверок в зависимости от входных параметров, состояния или контекста выполнения. В отличие от статического подхода, структура валидации формируется во время выполнения.
Основная идея динамического suite заключается в том, что набор
test вызовов не фиксирован заранее, а зависит от
условий.
Характерные признаки:
Пример динамического suite:
import { create, test, enforce } from 'vest';
const suite = create((data = {}) => {
test('username', 'Имя пользователя обязательно', () => {
enforce(data.username).isNotEmpty();
});
if (data.type === 'business') {
test('companyName', 'Название компании обязательно', () => {
enforce(data.companyName).isNotEmpty();
});
}
if (data.age < 18) {
test('parentEmail', 'Требуется email родителя', () => {
enforce(data.parentEmail).isNotEmpty();
});
}
});
В этом случае набор проверок зависит от значения type и
age. Таким образом, suite становится адаптивным и формирует
различные сценарии валидации без необходимости создания отдельных
функций.
Динамические suite применяются в случаях:
Различие между подходами заключается не только в структуре, но и в модели исполнения.
Статические suite:
Динамические suite:
С точки зрения внутренней работы Vest, статические suite проще кэшировать и переиспользовать. Динамические требуют повторной оценки структуры при каждом вызове, поскольку условия могут изменять набор тестов.
Одним из ключевых механизмов динамических suite является использование условий внутри тела функции. Это позволяет включать или исключать проверки без изменения общей структуры API.
Пример условной генерации:
const suite = create((data = {}) => {
const isAdmin = data.role === 'admin';
test('username', 'Обязательное поле', () => {
enforce(data.username).isNotEmpty();
});
if (isAdmin) {
test('accessLevel', 'Уровень доступа обязателен для администратора', () => {
enforce(data.accessLevel).greaterThan(0);
});
}
});
Такой подход позволяет локализовать бизнес-логику внутри одного suite, избегая разбиения на множество отдельных функций.
Статические suite хорошо подходят для композиции. Поскольку их структура фиксирована, их можно безопасно объединять без риска изменения поведения.
Пример композиции:
const baseSuite = create((data) => {
test('username', 'Обязательно', () => {
enforce(data.username).isNotEmpty();
});
});
const emailSuite = create((data) => {
test('email', 'Некорректный email', () => {
enforce(data.email).matches(/.+@.+\..+/);
});
});
const combinedSuite = create((data) => {
baseSuite(data);
emailSuite(data);
});
Композиция позволяет формировать модульную архитектуру валидации, где каждая часть отвечает за свою область ответственности.
Динамические suite также могут быть композиционными, однако их поведение становится менее предсказуемым из-за условий внутри каждого блока.
const roleSuite = (data) => {
if (data.role === 'manager') {
test('teamSize', 'Укажите размер команды', () => {
enforce(data.teamSize).greaterThan(0);
});
}
};
const suite = create((data) => {
test('username', 'Обязательно', () => {
enforce(data.username).isNotEmpty();
});
roleSuite(data);
});
Здесь композиция выполняется на уровне функций, а не на уровне заранее определённой структуры.
Статические suite выигрывают за счёт:
Динамические suite требуют:
Однако динамический подход позволяет уменьшить количество лишних проверок, исключая нерелевантные тесты до их выполнения.
В системе Vest важную роль играет возможность повторного использования результатов валидации. Статические suite позволяют эффективнее реализовать частичное кеширование, поскольку структура тестов остаётся неизменной.
Динамические suite ограничивают такую оптимизацию, так как изменение условий может менять набор тестов даже при одинаковых входных данных для отдельных полей.
В реальных приложениях часто используется гибридный подход:
Пример гибридной структуры:
const baseSuite = (data) => {
test('username', 'Обязательно', () => {
enforce(data.username).isNotEmpty();
});
};
const suite = create((data) => {
baseSuite(data);
if (data.mode === 'extended') {
test('bio', 'Описание слишком короткое', () => {
enforce(data.bio).longerThan(10);
});
}
});
Такой подход позволяет балансировать между предсказуемостью и гибкостью, сохраняя управляемость логики валидации.