Динамическая структура тестов в Vest строится вокруг идеи декларативного описания правил валидации с возможностью их генерации, модификации и ветвления во время выполнения. В отличие от статических наборов проверок, где каждая тест-функция фиксирована, динамическая модель позволяет формировать тестовые сценарии на основе входных данных, состояния формы и внешних условий.
Базовая архитектура Vest опирается на функцию test,
которая регистрирует проверку внутри набора правил. Динамическая
структура возникает за счёт того, что набор таких вызовов формируется не
статически, а в процессе исполнения функции-валидации.
Ключевым моментом является отсутствие жёсткой фиксации количества и состава тестов до момента выполнения. Это позволяет:
import { suite, test, enforce } from 'vest';
const validateUser = (data) => {
return suite('user', () => {
if (data.type === 'admin') {
test('adminCode', 'Неверный код администратора', () => {
enforce(data.adminCode).equals('SECRET');
});
}
test('username', 'Некорректное имя пользователя', () => {
enforce(data.username).isNotBlank();
});
});
};
В данном примере структура тестов изменяется в зависимости от
значения data.type. Набор проверок не фиксирован, а
формируется во время выполнения.
Одним из центральных механизмов динамической структуры является условное добавление тестов. Условия могут зависеть от:
Условная логика позволяет формировать дерево тестов, в котором отдельные ветви активируются только при выполнении определённых условий.
suite('payment', () => {
if (data.paymentMethod === 'card') {
test('cardNumber', () => {
enforce(data.cardNumber).matches(/^\d{16}$/);
});
test('cvv', () => {
enforce(data.cvv).lengthEquals(3);
});
}
if (data.paymentMethod === 'crypto') {
test('wallet', () => {
enforce(data.wallet).isNotEmpty();
});
}
});
В такой структуре каждая ветка тестов представляет собой независимый поднабор, активируемый динамически.
Динамическая структура усиливается возможностью композиции. Тестовые блоки могут быть вынесены в отдельные функции и включены в основной набор условий при необходимости. Это создаёт модульную систему валидации.
const addressTests = (data) => {
test('city', () => {
enforce(data.city).isNotBlank();
});
test('zip', () => {
enforce(data.zip).matches(/^\d{5}$/);
});
};
suite('checkout', () => {
test('email', () => {
enforce(data.email).isEmail();
});
if (data.requiresShipping) {
addressTests(data);
}
});
Композиция позволяет строить переиспользуемые фрагменты динамической структуры, которые включаются по мере необходимости.
Одним из распространённых сценариев является динамическое создание тестов на основе массивов. Это особенно важно при работе с формами, содержащими произвольное количество элементов.
suite('tags', () => {
data.tags.forEach((tag, index) => {
test(`tag-${index}`, () => {
enforce(tag).isNotBlank();
});
});
});
Такая модель делает структуру тестов зависимой от размера входных данных, что невозможно в статической системе валидации.
В Vest тесты могут быть связаны логически, даже если они не зависят друг от друга напрямую. Динамическая структура позволяет изменять поведение последующих тестов в зависимости от результатов предыдущих через внешние состояния или вычисления.
suite('profile', () => {
let isAdult = false;
test('age', () => {
isAdult = data.age >= 18;
enforce(data.age).greaterThan(0);
});
if (isAdult) {
test('drivingLicense', () => {
enforce(data.drivingLicense).isNotEmpty();
});
}
});
Хотя такая модель требует аккуратного управления состоянием, она позволяет формировать условные ветвления внутри одного набора правил.
Динамическая структура тестов в Vest обладает свойством ленивого построения: тесты регистрируются только при вызове функции валидации, а не при импорте модуля. Это даёт возможность:
Ленивая регистрация особенно важна при работе с формами, где структура может меняться от шага к шагу.
Динамическая структура может быть вложенной, формируя иерархию
тестов. Вложенность выражается через композицию suite
внутри suite, где каждый уровень добавляет собственный
контекст.
suite('account', () => {
test('email', () => {
enforce(data.email).isEmail();
});
suite('security', () => {
test('password', () => {
enforce(data.password).longerThan(8);
});
if (data.twoFactorEnabled) {
test('otp', () => {
enforce(data.otp).lengthEquals(6);
});
}
});
});
Такая структура формирует дерево проверок, где каждый узел может иметь собственные условия активации.
Внутренняя логика может включать механизмы пропуска тестов. Хотя тест зарегистрирован, он может быть фактически не выполнен в зависимости от состояния данных. Это создаёт эффект динамической фильтрации.
Фильтрация используется для оптимизации:
Динамика усиливается возможностью параметризации. Один и тот же набор логики может применяться к разным полям или наборам данных.
const requiredField = (fieldName, value) => {
test(fieldName, () => {
enforce(value).isNotBlank();
});
};
suite('form', () => {
requiredField('firstName', data.firstName);
requiredField('lastName', data.lastName);
requiredField('city', data.city);
});
Параметризация позволяет строить шаблонные тестовые блоки, которые расширяются в зависимости от контекста.
Динамическая структура тестов используется для построения адаптивных схем, где набор правил изменяется в зависимости от пользовательского сценария. Такие схемы характерны для многошаговых форм, где каждый шаг открывает новый набор условий.
Структура может меняться:
Каждое изменение приводит к перестроению дерева тестов без изменения базовой логики.
В динамической модели допускается смешивание фиксированных и условных блоков. Это создаёт гибридную структуру, где базовые проверки всегда присутствуют, а расширенные подключаются по условиям.
suite('order', () => {
test('productId', () => {
enforce(data.productId).isNotBlank();
});
if (data.discountApplied) {
test('discountCode', () => {
enforce(data.discountCode).isNotEmpty();
});
}
test('quantity', () => {
enforce(data.quantity).greaterThan(0);
});
});
Такая организация обеспечивает баланс между стабильной основой и изменяемыми ветвями логики.
Внутренне динамические тесты формируют дерево исполнения, где каждый
узел соответствует вызову test или вложенной
suite. Это дерево не фиксируется заранее, а строится во
время выполнения функции валидации.
Свойства такого дерева:
Именно эта модель делает структуру гибкой и адаптивной к сложным сценариям проверки данных.