Зависимые проверки представляют собой модель валидации, при которой результат проверки одного поля определяется значением другого поля, состоянием формы или внешним контекстом. В Vest это реализуется через функциональный подход, позволяющий строить условия выполнения тестов, динамически включать или отключать правила и использовать данные формы как источник логики валидации.
В основе зависимых проверок лежит идея контекстной обусловленности:
В отличие от статических схем валидации, где правила фиксированы, зависимые проверки формируют динамическое дерево условий, пересчитываемое при каждом изменении состояния данных.
Vest использует функцию test и общий контекст
data, который передаётся в каждую проверку. Это позволяет
получать доступ ко всей форме внутри любого теста.
import { create, test, enforce } from 'vest';
const suite = create((data) => {
test('password', 'Пароль обязателен', () => {
enforce(data.password).isNotEmpty();
});
test('confirmPassword', 'Пароли не совпадают', () => {
enforce(data.confirmPassword).equals(data.password);
});
});
Здесь вторая проверка напрямую зависит от значения
password. Любое изменение первого поля автоматически влияет
на результат второго.
Одним из ключевых механизмов зависимых проверок является условное выполнение тестов.
test('companyName', 'Название компании обязательно', () => {
if (data.isCompany) {
enforce(data.companyName).isNotEmpty();
}
});
В этом примере поле companyName становится обязательным
только при включённом флаге isCompany. Подобная логика
позволяет строить формы с динамическими требованиями.
skip как механизма управления зависимостямиВ Vest существует механизм пропуска тестов, который часто используется для зависимых проверок.
test('vatNumber', 'ИНН обязателен для компаний', () => {
if (!data.isCompany) {
return;
}
enforce(data.vatNumber).isNotEmpty();
});
Логика становится декларативной: тест существует, но активируется только при выполнении условия.
Сложные формы часто требуют проверки не двух, а сразу нескольких полей, где каждое влияет на другое.
test('startDate', 'Дата начала должна быть раньше окончания', () => {
enforce(new Date(data.startDate)).lessThanOrEquals(new Date(data.endDate));
});
test('endDate', 'Дата окончания должна быть позже начала', () => {
enforce(new Date(data.endDate)).greaterThanOrEquals(new Date(data.startDate));
});
Обе проверки взаимозависимы и формируют двустороннюю связь. Такая модель предотвращает логические ошибки в данных, даже если пользователь редактирует любое из полей.
Когда зависимость охватывает несколько условий одновременно, логика объединяется в один тестовый блок.
test('discount', 'Скидка недоступна для бесплатного тарифа', () => {
if (data.plan === 'free' && data.discount > 0) {
enforce(data.discount).equals(0);
}
});
Здесь зависимость строится от комбинации значений plan и
discount. Подобные конструкции часто используются в
тарифных системах и административных панелях.
Vest позволяет строить переиспользуемые функции проверки, которые принимают данные формы и создают локальные зависимости.
const isAdult = (data) => data.age >= 18;
test('driversLicense', 'Права доступны только совершеннолетним', () => {
if (!isAdult(data)) return;
enforce(data.driversLicense).isNotEmpty();
});
Здесь зависимость вынесена в отдельную функцию, что позволяет повторно использовать её в разных частях валидации.
В сложных сценариях набор тестов может зависеть от входных данных на уровне самой схемы валидации.
const suite = create((data) => {
if (data.type === 'individual') {
test('firstName', 'Имя обязательно', () => {
enforce(data.firstName).isNotEmpty();
});
}
if (data.type === 'company') {
test('companyName', 'Название компании обязательно', () => {
enforce(data.companyName).isNotEmpty();
});
}
});
Такой подход позволяет создавать формы, которые фактически меняют свою структуру в зависимости от выбранного режима.
Зависимые проверки влияют на стратегию пересчёта валидации. Vest оптимизирует выполнение тестов следующим образом:
Это особенно важно в больших формах с десятками или сотнями полей.
В сложных структурах данные могут быть вложенными, что добавляет дополнительный уровень зависимостей.
test('address.zip', 'Индекс обязателен', () => {
enforce(data.address.zip).isNotEmpty();
});
test('address.country', 'Страна обязательна', () => {
enforce(data.address.country).isNotEmpty();
});
Проверки работают внутри вложенных объектов, сохраняя ту же модель зависимостей, что и для плоских структур.
При проектировании валидации важно учитывать конфликтующие зависимости, когда разные тесты накладывают противоречивые условия.
test('age', 'Возраст должен быть в допустимом диапазоне', () => {
enforce(data.age).greaterThanOrEquals(0);
enforce(data.age).lessThanOrEquals(120);
});
test('age', 'Возраст несовместим с выбранной услугой', () => {
if (data.service === 'insurance' && data.age < 18) {
enforce(false).equals(true);
}
});
Такая модель позволяет комбинировать базовые и контекстные ограничения, не смешивая их в одном условии.
Зависимые проверки могут формировать цепочки, где одно поле влияет на второе, второе на третье и так далее.
test('step1', () => {
enforce(data.step1).isNotEmpty();
});
test('step2', () => {
if (!data.step1) return;
enforce(data.step2).isNotEmpty();
});
test('step3', () => {
if (!data.step2) return;
enforce(data.step3).isNotEmpty();
});
Такая структура используется в многошаговых формах, где каждый шаг зависит от успешного завершения предыдущего.
В реальных приложениях зависимые проверки часто отражают бизнес-логику:
Vest предоставляет низкоуровневую, но гибкую модель, позволяющую выражать такие правила без необходимости создания отдельного DSL или сложных схем конфигурации.
Завершающим аспектом зависимых проверок является поддержание целостности данных. При изменении одного поля система должна гарантировать пересчёт всех связанных тестов, сохраняя консистентное состояние результата валидации без частично устаревших ошибок или пропущенных проверок.