При построении сложных схем проверки данных в приложениях на JavaScript возникает необходимость отслеживать:
В библиотеке Vest отсутствует встроенная полноценная система логирования уровня enterprise, однако архитектура фреймворка позволяет организовать детальное отслеживание процесса валидации через:
Каждый suite в Vest представляет собой функцию, внутри которой выполняются тесты.
Базовый пример:
import { create, test, enforce } from 'vest';
const suite = create((data = {}) => {
test('email', 'Некорректный email', () => {
enforce(data.email).isEmail();
});
test('password', 'Пароль слишком короткий', () => {
enforce(data.password).longerThanOrEquals(8);
});
});
При запуске:
const result = suite({
email: 'wrong',
password: '123'
});
Vest формирует внутренний execution context, содержащий:
Логирование строится вокруг этих данных.
Объект результата — главный источник информации для логирования.
console.log(result.isValid());
console.log(result.hasErrors('email'));
console.log(result.getErrors('email'));
console.log(result.getErrors());
Пример результата:
{
email: ['Некорректный email'],
password: ['Пароль слишком короткий']
}
Наиболее простой подход — логирование после выполнения suite.
const result = suite(formData);
console.log('Validation result:', {
valid: result.isValid(),
errors: result.getErrors(),
warnings: result.getWarnings()
});
Результат:
Validation result: {
valid: false,
errors: {
email: ['Некорректный email']
},
warnings: {}
}
Vest позволяет организовать логирование внутри test callback.
test('email', 'Некорректный email', () => {
console.log('[VALIDATION] Проверка email');
enforce(data.email).isEmail();
console.log('[VALIDATION] Email прошёл проверку');
});
Если проверка завершится исключением:
test('email', 'Некорректный email', () => {
console.log('Start email validation');
enforce(data.email).isEmail();
console.log('Finish email validation');
});
Второй лог не выполнится.
Для отслеживания ошибок рекомендуется оборачивать проверки.
test('password', 'Пароль слишком короткий', () => {
console.log('Password validation started');
try {
enforce(data.password).longerThanOrEquals(8);
console.log('Password validation success');
} catch (e) {
console.error('Password validation failed', e);
throw e;
}
});
На практике логирование быстро становится дублирующимся.
Решение — выделение отдельного сервиса.
export const validationLogger = {
info(message, meta = {}) {
console.log('[VALIDATION]', message, meta);
},
error(message, meta = {}) {
console.error('[VALIDATION ERROR]', message, meta);
},
warn(message, meta = {}) {
console.warn('[VALIDATION WARNING]', message, meta);
}
};
Использование:
import { validationLogger } from './logger';
test('email', 'Некорректный email', () => {
validationLogger.info('Email validation started', {
value: data.email
});
enforce(data.email).isEmail();
validationLogger.info('Email validation completed');
});
Часто необходимо фиксировать данные, переданные в suite.
const suite = create((data = {}) => {
console.log('Incoming validation data:', data);
test('email', 'Некорректный email', () => {
enforce(data.email).isEmail();
});
});
Нельзя логировать:
console.log(data.password);
console.log({
...data,
password: '***'
});
Vest поддерживает async validation.
test('email', 'Email уже существует', async () => {
console.log('Checking email uniqueness');
const exists = await api.checkEmail(data.email);
console.log('Email check finished');
enforce(exists).isFalsy();
});
Валидация может стать узким местом производительности.
test('email', 'Некорректный email', () => {
const start = performance.now();
enforce(data.email).isEmail();
const end = performance.now();
console.log(`Validation time: ${end - start} ms`);
});
Полезно при отладке сложных форм.
const validateForm = data => {
console.group('Validation session');
console.log('Input:', data);
const result = suite(data);
console.log('Is valid:', result.isValid());
console.log('Errors:', result.getErrors());
console.groupEnd();
return result;
};
Группировка делает логи читаемыми.
console.group('Email validation');
console.log('Input:', data.email);
enforce(data.email).isEmail();
console.log('Status: success');
console.groupEnd();
Vest поддерживает selective validation.
import { only } from 'vest';
const result = suite(data, only('email'));
Можно логировать выполняемые поля:
console.log('Validated fields:', ['email']);
Vest поддерживает warnings.
import { warn } from 'vest';
test('password', 'Слабый пароль', () => {
warn();
enforce(data.password).matches(/[A-Z]/);
});
Логирование:
console.log(result.getWarnings());
Крупные приложения используют middleware-подход.
function withLogging(suite) {
return data => {
console.log('Validation started');
const started = Date.now();
const result = suite(data);
const finished = Date.now();
console.log('Validation completed');
console.log('Duration:', finished - started);
console.log('Errors:', result.getErrors());
return result;
};
}
Использование:
const loggedSuite = withLogging(suite);
loggedSuite(formData);
Иногда необходимо отдельно фиксировать только проблемные поля.
const errors = result.getErrors();
Object.entries(errors).forEach(([field, messages]) => {
console.error('Field validation failed', {
field,
messages
});
});
По умолчанию Vest концентрируется на ошибках.
Для аудита иногда необходимо логировать успешные тесты.
test('username', 'Некорректный username', () => {
enforce(data.username).longerThan(3);
console.log('Username validation success');
});
Vest легко интегрируется с:
import winston from 'winston';
const logger = winston.createLogger({
transports: [
new winston.transports.Console()
]
});
Использование:
logger.info('Validation started');
const result = suite(data);
logger.info('Validation completed', {
valid: result.isValid(),
errors: result.getErrors()
});
В React логирование часто связывается с жизненным циклом формы.
const onSub mit = () => {
const result = suite(formData);
console.log('Form submit validation', {
valid: result.isValid(),
errors: result.getErrors()
});
if (result.isValid()) {
sendForm();
}
};
Асинхронные проверки могут находиться в состоянии ожидания.
console.log(result.isPending());
Проверка конкретного поля:
console.log(result.isPending('email'));
При сложных зависимостях важно понимать execution order.
test('email', 'Некорректный email', () => {
console.log('1. Email validation');
enforce(data.email).isEmail();
});
test('password', 'Некорректный пароль', () => {
console.log('2. Password validation');
enforce(data.password).longerThan(8);
});
Vest поддерживает условные проверки.
if (data.hasCompany) {
console.log('Company validation enabled');
test('companyName', 'Введите название компании', () => {
enforce(data.companyName).isNotBlank();
});
}
Валидация может зависеть от runtime-состояния.
const rules = getValidationRules();
console.log('Active rules:', rules);
В формах с live validation важно отслеживать количество запусков.
let validationCounter = 0;
const validate = data => {
validationCounter++;
console.log('Validation run:', validationCounter);
return suite(data);
};
Строковые логи неудобны для анализа.
Лучше использовать JSON-подход.
console.log({
type: 'validation',
field: 'email',
status: 'failed',
timestamp: Date.now()
});
Для критически важных систем ведётся журнал проверок.
const auditRecord = {
userId: user.id,
form: 'registration',
valid: result.isValid(),
errors: result.getErrors(),
createdAt: new Date().toISOString()
};
Vest может переиспользовать previous state.
console.log('Validation restarted');
При оптимизации важно понимать:
Практичный подход — отдельный режим диагностики.
const DEBUG_VALIDATION = true;
function debugLog(...args) {
if (DEBUG_VALIDATION) {
console.log(...args);
}
}
Использование:
debugLog('Validation started');
Логирование может:
const isProduction =
process.env.NODE_ENV === 'production';
if (!isProduction) {
console.log('Validation debug');
}
Продвинутый подход — автоматическое перехватывание вызовов.
function createLoggedEnforce(enforce) {
return new Proxy(enforce, {
apply(target, thisArg, args) {
console.log('Enforce called with:', args);
return Reflect.apply(target, thisArg, args);
}
});
}
В крупных системах создаётся единый мониторинг.
class ValidationMonitor {
constructor() {
this.history = [];
}
log(entry) {
this.history.push({
...entry,
timestamp: Date.now()
});
}
getHistory() {
return this.history;
}
}
Использование:
const monitor = new ValidationMonitor();
monitor.log({
field: 'email',
status: 'failed'
});
Собранные данные позволяют определить:
const stats = {
emailFailures: 120,
passwordFailures: 88,
averageValidationTime: 14
};
console.log(user.password);
console.log('validation');
console.log('validation');
console.log('validation');
console.log('error');
Без успешных проверок сложнее анализировать execution flow.
Для production-среды предпочтительнее: