Условная валидация позволяет изменять набор проверок в зависимости от состояния данных формы, контекста или значений других полей. В контексте Vest этот подход является одним из ключевых механизмов построения гибких схем проверки, так как библиотека ориентирована на декларативное описание правил с возможностью динамического управления логикой.
Условная валидация строится на идее, что правило не обязано выполняться всегда. Оно может:
В Vest нет отдельного «магического» оператора для условий — вместо этого используется обычный JavaScript, что делает систему предсказуемой и расширяемой.
Основной сценарий условной валидации связан с доступом к текущим данным формы внутри тестов.
import { create, test } from 'vest';
const validation = create((data = {}) => {
test('email', 'Email обязателен', () => {
if (!data.emailRequired) return;
expect(data.email).toBeTruthy();
});
test('email', 'Некорректный email', () => {
if (!data.email) return;
expect(data.email).toMatch(/.+@.+\..+/);
});
});
В этом примере логика проверки зависит от флага
emailRequired. Если он выключен, правило полностью
пропускается.
Ключевой момент заключается в том, что пропуск теста — это не ошибка, а штатное поведение, позволяющее строить динамические схемы.
Часто одно поле зависит от другого. Например, адрес доставки требуется только при выборе доставки курьером.
const validation = create((data = {}) => {
test('address', 'Адрес обязателен при доставке курьером', () => {
if (data.deliveryType !== 'courier') return;
expect(data.address).toBeTruthy();
});
});
Здесь условие встроено непосредственно в тест. Такой подход масштабируется без необходимости создавать отдельные схемы или переключать валидаторы.
Условная валидация часто используется для полного исключения поля из проверки.
test('companyName', 'Название компании обязательно', () => {
if (!data.isCompany) return;
expect(data.companyName).toBeTruthy();
});
Если пользователь выбирает «частное лицо», поле
companyName перестаёт участвовать в валидации.
Важный аспект: исключение поля через return внутри теста
означает, что поле не влияет на общий статус ошибки.
Сложные формы часто содержат цепочки зависимостей:
test('vatNumber', 'Номер НДС обязателен для компаний из ЕС', () => {
if (!data.isCompany) return;
if (data.country !== 'EU') return;
expect(data.vatNumber).toBeTruthy();
});
Такие конструкции позволяют строить каскадные правила без отдельной системы зависимостей.
Vest поддерживает передачу контекста валидации, что позволяет отделять данные формы от внешних параметров.
const validation = create((data = {}, ctx = {}) => {
test('password', 'Слабый пароль', () => {
if (!ctx.strictMode) return;
expect(data.password).toMatch(/^(?=.*[A-Z])(?=.*\d).{8,}$/);
});
});
Контекст используется для режимов:
Иногда логика применяется не к одному полю, а к набору связанных проверок.
const validation = create((data = {}) => {
if (data.paymentMethod === 'card') {
test('cardNumber', 'Некорректный номер карты', () => {
expect(data.cardNumber).toMatch(/^\d{16}$/);
});
test('cvv', 'Некорректный CVV', () => {
expect(data.cvv).toMatch(/^\d{3}$/);
});
}
});
Такой подход позволяет структурировать правила на уровне блоков, а не отдельных тестов.
Одним из наиболее распространённых паттернов является ранний
return, который полностью отключает проверку.
test('discountCode', 'Промокод недействителен', () => {
if (!data.discountEnabled) return;
expect(isValidCode(data.discountCode)).toBe(true);
});
Этот стиль делает логику линейной и легко читаемой, особенно при большом количестве условий.
Условная логика также применяется в асинхронных тестах, например при проверке уникальности через API.
test('username', 'Имя пользователя уже занято', async () => {
if (!data.username) return;
const exists = await api.checkUsername(data.username);
expect(exists).toBe(false);
});
Здесь условие предотвращает лишний запрос, если поле пустое.
При росте формы повторяющиеся условия можно выносить в функции:
const isCompanyUser = (data) => data.type === 'company';
test('companyId', 'ID компании обязателен', () => {
if (!isCompanyUser(data)) return;
expect(data.companyId).toBeTruthy();
});
Такой подход снижает дублирование и упрощает сопровождение.
В рамках Vest предпочтительно держать условия внутри тестов, сохраняя предсказуемую структуру выполнения.
Условия могут комбинироваться для построения более сложных сценариев:
test('shippingDate', 'Некорректная дата доставки', () => {
if (!data.deliveryType) return;
if (data.deliveryType !== 'scheduled') return;
if (!data.shippingDate) return;
expect(new Date(data.shippingDate).getTime()).toBeGreaterThan(Date.now());
});
Такой подход позволяет постепенно «сужать» область применения проверки.
При проектировании больших форм ключевая задача — избежать разрастания вложенности. Вместо сложных конструкций предпочтительно:
Это позволяет сохранять читаемость даже при десятках взаимозависимых полей.