Инспекция состояния — механизм анализа результатов валидации, позволяющий получать детализированную информацию о текущем состоянии формы, отдельных полей, ошибок, предупреждений и прогресса выполнения тестов. В библиотеке Vest состояние хранится внутри suite и может быть исследовано через набор специализированных функций.
Инспекция особенно важна в следующих сценариях:
После запуска suite Vest возвращает объект состояния:
const result = validate(data);
Этот объект содержит API инспекции.
Пример:
import { create, test, enforce } from 'vest';
const validate = create((data = {}) => {
test('email', 'Email обязателен', () => {
enforce(data.email).isNotBlank();
});
test('password', 'Минимум 8 символов', () => {
enforce(data.password).longerThanOrEquals(8);
});
});
const result = validate({
email: '',
password: '123'
});
Теперь объект result содержит информацию обо всех
проверках.
Метод hasErrors() проверяет наличие ошибок.
result.hasErrors();
Результат:
true
Если ошибок нет:
false
Vest поддерживает предупреждения отдельно от ошибок.
result.hasWarnings();
Пример:
import { create, test, warn } from 'vest';
const validate = create(data => {
test('password', 'Слишком простой пароль', () => {
warn();
});
});
Проверяет общую валидность suite.
result.isValid();
Эквивалентно:
!result.hasErrors()
Если используются группы:
result.isValidByGroup('shipping');
Пример:
import { create, group, test, enforce } from 'vest';
const validate = create(data => {
group('shipping', () => {
test('city', 'Введите город', () => {
enforce(data.city).isNotBlank();
});
});
});
Проверка ошибок у конкретного поля:
result.hasErrors('email');
result.hasWarnings('password');
result.isValid('email');
Возвращает массив ошибок.
result.getErrors();
Результат:
[
'Email обязателен',
'Минимум 8 символов'
]
result.getErrors('email');
Результат:
[
'Email обязателен'
]
result.getWarnings();
result.getWarnings('password');
Vest поддерживает асинхронную валидацию. Поэтому состояние выполнения тестов играет важную роль.
Проверяет наличие незавершённых проверок.
result.isPending();
result.isPending('username');
import { create, test } from 'vest';
const validate = create(data => {
test('username', 'Имя уже занято', async () => {
const response = await fetch('/check-username');
const json = await response.json();
if (!json.available) {
throw new Error();
}
});
});
Во время выполнения:
result.isPending('username');
вернёт:
true
Позволяет определить, выполнялась ли проверка.
result.isTested('email');
Это особенно важно при пошаговых формах.
const result = validate({
email: ''
});
result.isTested('email');
Результат:
true
А для поля, которое не проверялось:
result.isTested('password');
Результат:
false
Vest разделяет ошибки и предупреждения.
Ошибки блокируют отправку формы, предупреждения — нет.
import { create, test, warn } from 'vest';
const validate = create(data => {
test('password', 'Пароль слишком простой', () => {
if (data.password === '12345678') {
warn();
}
});
});
result.hasWarnings('password');
Получение текста:
result.getWarnings('password');
Группы позволяют логически разделять форму.
import { create, group, test, enforce } from 'vest';
const validate = create(data => {
group('profile', () => {
test('firstName', 'Введите имя', () => {
enforce(data.firstName).isNotBlank();
});
test('lastName', 'Введите фамилию', () => {
enforce(data.lastName).isNotBlank();
});
});
group('security', () => {
test('password', 'Минимум 8 символов', () => {
enforce(data.password).longerThanOrEquals(8);
});
});
});
result.hasErrorsByGroup('profile');
result.getErrorsByGroup('profile');
result.isValidByGroup('security');
Метод get() возвращает внутреннее состояние suite.
const state = result.get();
Структура содержит:
{
tests: {
email: {...},
password: {...}
},
errorCount: 2,
valid: false
}
Точная структура зависит от версии Vest.
const state = result.get();
console.log(state.errorCount);
console.log(state.warningCount);
Vest позволяет запускать только часть проверок.
import { create, only, test, enforce } from 'vest';
const validate = create(data => {
only('email');
test('email', 'Введите email', () => {
enforce(data.email).isNotBlank();
});
test('password', 'Введите пароль', () => {
enforce(data.password).isNotBlank();
});
});
result.isTested('email'); // true
result.isTested('password'); // false
import { create, skip, test } from 'vest';
const validate = create(data => {
skip('password');
test('email', 'Введите email', () => {});
test('password', 'Введите пароль', () => {});
});
result.isTested('password');
Результат:
false
Инспекция состояния особенно полезна в React-приложениях.
function EmailField({ result }) {
const errors = result.getErrors('email');
return (
<div>
{errors.map(error => (
<div key={error}>
{error}
</div>
))}
</div>
);
}
{
result.isPending('username') && (
<Spinner />
)
}
<button disabled={!result.isValid()}>
Отправить
</button>
{
result.hasWarnings('password') && (
<PasswordWarning />
)
}
Vest напрямую не хранит touched, однако состояние можно
моделировать через isTested().
const showError =
result.isTested('email') &&
result.hasErrors('email');
Асинхронные проверки требуют контроля состояния выполнения.
if (result.isPending('email')) {
console.log('Проверка...');
}
if (result.hasErrors('email')) {
console.log(result.getErrors('email'));
}
console.log(result.get());
const state = result.get();
console.log(state.tests);
Крупные приложения часто создают слой абстракции.
function fieldState(result, fieldName) {
return {
errors: result.getErrors(fieldName),
warnings: result.getWarnings(fieldName),
pending: result.isPending(fieldName),
valid: result.isValid(fieldName),
tested: result.isTested(fieldName)
};
}
Использование:
const emailState = fieldState(result, 'email');
const fields = ['email', 'password'];
const hasErrors = fields.some(field =>
result.hasErrors(field)
);
function createFormState(result) {
return {
valid: result.isValid(),
pending: result.isPending(),
errors: result.getErrors(),
warnings: result.getWarnings()
};
}
const step1Valid =
result.isValid('email') &&
result.isValid('password');
result.isValidByGroup('step1');
При больших формах частые вызовы методов инспекции могут создавать лишние вычисления.
const emailErrors = result.getErrors('email');
const emailPending = result.isPending('email');
Вместо:
result.getErrors('email');
result.getErrors('email');
result.getErrors('email');
import { create, test, enforce } from 'vest';
const validate = create(data => {
test('email', 'Введите email', () => {
enforce(data.email).isNotBlank();
});
test('password', 'Минимум 8 символов', () => {
enforce(data.password).longerThanOrEquals(8);
});
});
const result = validate({
email: '',
password: '123'
});
console.log(result.isValid());
console.log(result.hasErrors());
console.log(result.getErrors());
console.log(result.getErrors('email'));
console.log(result.isValid('password'));
console.log(result.isTested('email'));
Система инспекции Vest строится вокруг нескольких ключевых принципов:
Это делает библиотеку пригодной для сложных enterprise-форм с большим количеством зависимых проверок и динамической логикой интерфейса.