Булевы значения

Булевы значения играют важную роль в построении условий валидации внутри библиотеки Vest. С их помощью определяется необходимость выполнения тестов, изменение поведения suites, управление состоянием полей и логикой интерфейса. Практически каждая сложная форма использует булевы выражения для контроля сценариев проверки.

Логическая природа булевых значений

В JavaScript существует два булевых литерала:

true
false

Vest активно использует эти значения во внутренних механизмах:

  • включение и отключение тестов;
  • динамическая валидация;
  • условное выполнение групп проверок;
  • переключение режимов;
  • работа с optional-полями;
  • обработка асинхронных состояний.

Простейший пример:

const isAdmin = true;

if (isAdmin) {
  // выполнить дополнительную проверку
}

В контексте Vest булевы значения почти всегда участвуют в функциях-условиях.


Использование булевых условий в skip

Метод skip позволяет временно отключать тесты.

Базовый пример

import { create, test, skip, enforce } from 'vest';

const suite = create((data = {}) => {
  skip(!data.email, () => {
    test('email', 'Email обязателен', () => {
      enforce(data.email).isNotBlank();
    });
  });
});

Разбор логики

!data.email

Возвращает:

  • true — если email отсутствует;
  • false — если email существует.

Если условие внутри skip возвращает true, тесты внутри блока не выполняются.


Инверсия булевых значений

Оператор ! используется особенно часто.

Пример

const hasPassword = false;

console.log(!hasPassword);

Результат:

true

В Vest инверсия позволяет удобно описывать исключающие условия.

Пример валидации

skip(!data.password, () => {
  test('password', 'Пароль слишком короткий', () => {
    enforce(data.password.length).greaterThan(7);
  });
});

Проверка выполняется только при наличии пароля.


Булевы флаги состояния

Во многих suites используются флаги.

Пример

const isEditMode = true;
const isAdmin = false;

Далее флаги применяются для управления логикой.

if (isEditMode) {
  // проверять только изменённые поля
}

if (isAdmin) {
  // расширенные проверки
}

Условное выполнение тестов

Vest предоставляет возможность строить сложную логику выполнения.

Проверка только для зарегистрированных пользователей

import { create, test, enforce } from 'vest';

const suite = create((data = {}) => {
  if (data.isRegistered) {
    test('email', 'Email обязателен', () => {
      enforce(data.email).isNotBlank();
    });
  }
});

Возможные значения

isRegistered Выполнение теста
true Да
false Нет

Булевы значения и optional-поля

Не все поля формы обязательны. Булевы условия помогают гибко управлять такими сценариями.

Пример

const shouldValidatePhone = data.country === 'KZ';
if (shouldValidatePhone) {
  test('phone', 'Телефон обязателен', () => {
    enforce(data.phone).isNotBlank();
  });
}

Булевы выражения

Булевы выражения — результат логических операций.

Сравнение

const isAdult = age >= 18;

Проверка строки

const hasName = Boolean(data.name);

Проверка длины

const hasErrors = errors.length > 0;

Все подобные конструкции активно применяются в Vest.


Логические операторы

Оператор &&

Возвращает true, если оба условия истинны.

const canSubmit = isValid && isDirty;

В Vest

if (data.email && data.password) {
  test('password', 'Пароль слишком короткий', () => {
    enforce(data.password.length).greaterThan(7);
  });
}

Оператор ||

Возвращает true, если хотя бы одно условие истинно.

const canAccess = isAdmin || isModerator;

Валидация

if (data.phone || data.email) {
  test('contact', 'Контакт указан', () => {});
}

Оператор !

Инвертирует значение.

const isEmpty = !data.name;

Преобразование в boolean

JavaScript содержит механизм truthy/falsy.

Truthy значения

Считаются истинными:

'hello'
1
[]
{}
true

Falsy значения

Считаются ложными:

false
0
''
null
undefined
NaN

Проверка truthy/falsy в Vest

Пример

if (data.email) {
  test('email', 'Некорректный email', () => {
    enforce(data.email).matches(/@/);
  });
}

Здесь строка автоматически приводится к boolean.


Явное преобразование через Boolean

Пример

const hasEmail = Boolean(data.email);

Аналог:

const hasEmail = !!data.email;

Двойное отрицание !!

Очень распространённый паттерн.

Пример

const isFilled = !!data.username;

Результаты

Значение Результат
'alex' true
'' false
null false

Булевы значения в динамической валидации

Vest часто используется с реактивными интерфейсами.

Пример

const shouldValidateAddress =
  data.deliveryType === 'courier';
if (shouldValidateAddress) {
  test('address', 'Адрес обязателен', () => {
    enforce(data.address).isNotBlank();
  });
}

Сложные булевы условия

Пример

const shouldValidateTaxNumber =
  data.country === 'KZ' &&
  data.isBusiness &&
  !data.isIndividual;

Использование

if (shouldValidateTaxNumber) {
  test('taxNumber', 'ИНН обязателен', () => {
    enforce(data.taxNumber).isNotBlank();
  });
}

Булевы значения и асинхронная валидация

Булевы флаги часто управляют асинхронными тестами.

Пример

const shouldCheckUsername =
  data.username.length > 3;
if (shouldCheckUsername) {
  test.memo(
    'username',
    'Имя уже занято',
    async () => {
      const exists = await api.userExists(data.username);

      enforce(exists).equals(false);
    }
  );
}

Использование ternary-оператора

Тернарный оператор возвращает одно из двух значений.

Синтаксис

condition ? value1 : value2

Пример

const minLength =
  data.isAdmin ? 12 : 8;

В тесте

test('password', 'Пароль слишком короткий', () => {
  enforce(data.password.length)
    .greaterThan(minLength - 1);
});

Булевы значения и only

Метод only позволяет запускать проверки только для конкретных полей.

Пример

import { only } from 'vest';
only(data.fieldName);

Обычно условие строится через boolean.

if (data.isSingleFieldValidation) {
  only(data.fieldName);
}

Булевы значения и omitWhen

Vest предоставляет API для условного исключения тестов.

Пример

import { omitWhen } from 'vest';
omitWhen(data.isGuest, () => {
  test('passport', 'Паспорт обязателен', () => {
    enforce(data.passport).isNotBlank();
  });
});

Поведение

isGuest Выполнение
true тест пропускается
false тест выполняется

Булевы значения и группировка логики

Крупные формы часто содержат множество условий.

Плохой пример

if (
  data.country === 'KZ' &&
  data.type === 'company' &&
  data.isVerified &&
  !data.isBlocked
) {
}

Хороший пример

const isKazakhstanCompany =
  data.country === 'KZ' &&
  data.type === 'company';

const canValidate =
  isKazakhstanCompany &&
  data.isVerified &&
  !data.isBlocked;
if (canValidate) {
  // проверки
}

Такой подход делает suites значительно читаемее.


Булевы функции-предикаты

Часто используются отдельные функции.

Пример

function shouldValidateEmail(data) {
  return data.notificationsEnabled;
}
if (shouldValidateEmail(data)) {
  test('email', 'Email обязателен', () => {
    enforce(data.email).isNotBlank();
  });
}

Булевы значения в массивах

Методы массивов часто возвращают boolean.

some

const hasInvalidUsers =
  users.some(user => !user.email);

every

const allFilled =
  users.every(user => user.email);

Булевы значения и результаты Vest

Результаты suite также содержат булевы методы.

Проверка наличия ошибок

const result = suite(data);

result.hasErrors();

Возвращает:

true

или

false

Проверка конкретного поля

result.hasErrors('email');

Проверка валидности

result.isValid();

Использование булевых результатов

Пример

const result = suite(data);

const canSubmit = result.isValid();
if (canSubmit) {
  submitForm();
}

Комбинирование состояний формы

Пример

const canSave =
  result.isValid() &&
  !isSubmitting &&
  isDirty;

Частые ошибки

Использование строк вместо boolean

Плохой вариант:

const isAdmin = 'true';

Правильный вариант:

const isAdmin = true;

Слишком сложные условия

Плохо:

if (
  a &&
  b &&
  !c &&
  d &&
  (e || f) &&
  !g
) {
}

Лучше:

const canProceed =
  a &&
  b &&
  !c;

const hasPermission =
  d &&
  (e || f);

if (canProceed && hasPermission && !g) {
}

Практический пример полной suite

import {
  create,
  test,
  enforce,
  skip,
  omitWhen
} from 'vest';

const suite = create((data = {}) => {
  const isBusiness =
    data.accountType === 'business';

  const shouldValidateAddress =
    data.delivery === 'courier';

  const hasPassword =
    !!data.password;

  test('username', 'Введите имя', () => {
    enforce(data.username).isNotBlank();
  });

  skip(!hasPassword, () => {
    test('password', 'Минимум 8 символов', () => {
      enforce(data.password.length)
        .greaterThan(7);
    });
  });

  if (shouldValidateAddress) {
    test('address', 'Введите адрес', () => {
      enforce(data.address).isNotBlank();
    });
  }

  omitWhen(!isBusiness, () => {
    test('companyName', 'Введите название компании', () => {
      enforce(data.companyName).isNotBlank();
    });
  });
});

Рекомендации по использованию boolean в Vest

Вынос сложных условий в переменные

const shouldValidatePhone =
  data.country === 'KZ' &&
  data.notificationsEnabled;

Использование говорящих имён

Хорошо:

const isAdmin = true;
const hasErrors = false;
const canSubmit = true;

Плохо:

const flag = true;
const value = false;

Минимизация вложенности

Плохо:

if (a) {
  if (b) {
    if (c) {
    }
  }
}

Лучше:

if (a && b && c) {
}

Булевы значения как основа архитектуры валидации

Практически вся динамика Vest строится вокруг логических решений:

  • выполнять тест или нет;
  • скрывать ошибки или показывать;
  • запускать async-проверку или пропускать;
  • валидировать поле или считать его optional;
  • разрешать submit формы или блокировать.

Грамотное использование boolean-логики делает suites:

  • читаемыми;
  • расширяемыми;
  • предсказуемыми;
  • удобными для поддержки;
  • устойчивыми к росту сложности формы.