Files
web-core/tests/hooks/useValidatedFields.test.tsx
Beatrice Dellacà d7e144620e
All checks were successful
continuous-integration/drone/push Build is passing
add unit tests
2026-02-24 11:14:24 +01:00

159 lines
4.9 KiB
TypeScript

import { act } from 'react';
import { describe, expect, it } from 'vitest';
import { useValidatedFields } from '../../src/hooks/useValidatedFields';
import { renderHook } from '../helpers/renderHook';
type FormValues = {
password: string;
confirmPassword: string;
};
function validate(values: FormValues) {
return {
password: values.password.length < 3 ? 'Password too short' : undefined,
confirmPassword:
values.confirmPassword !== values.password ? 'Passwords do not match' : undefined,
};
}
describe('useValidatedFields', () => {
it('initializes values and keeps errors hidden until fields are touched', () => {
const { result } = renderHook(() =>
useValidatedFields({
initialValues: { password: '', confirmPassword: '' },
validate,
}),
);
expect(result.current.values).toEqual({ password: '', confirmPassword: '' });
expect(result.current.errors).toEqual({});
expect(result.current.isValid).toBe(false);
});
it('setFieldValue touches and validates by default', () => {
const { result } = renderHook(() =>
useValidatedFields({
initialValues: { password: '', confirmPassword: '' },
validate,
}),
);
act(() => {
result.current.setFieldValue('password', 'ab');
});
expect(result.current.values.password).toBe('ab');
expect(result.current.errors.password).toBe('Password too short');
});
it('setFieldValue can skip touch and validation', () => {
const { result } = renderHook(() =>
useValidatedFields({
initialValues: { password: '', confirmPassword: '' },
validate,
}),
);
act(() => {
result.current.setFieldValue('password', 'ab', { touch: false, validate: false });
});
expect(result.current.values.password).toBe('ab');
expect(result.current.errors).toEqual({});
});
it('validateAll can avoid touching fields when requested', () => {
const { result } = renderHook(() =>
useValidatedFields({
initialValues: { password: 'abcd', confirmPassword: 'abce' },
validate,
}),
);
let validationErrors: ReturnType<typeof validate> | undefined;
act(() => {
validationErrors = result.current.validateAll({ touchAll: false });
});
expect(validationErrors).toEqual({
password: undefined,
confirmPassword: 'Passwords do not match',
});
expect(result.current.errors).toEqual({});
});
it('validateAll touches all fields by default', () => {
const { result } = renderHook(() =>
useValidatedFields({
initialValues: { password: '', confirmPassword: '' },
validate,
}),
);
act(() => {
result.current.validateAll();
});
expect(result.current.errors.password).toBe('Password too short');
expect(result.current.errors.confirmPassword).toBeUndefined();
});
it('supports setFieldError, setErrors and clearErrors', () => {
const { result } = renderHook(() =>
useValidatedFields({
initialValues: { password: 'abcd', confirmPassword: 'abcd' },
validate,
}),
);
act(() => {
result.current.setFieldError('password', 'Server-side password issue');
});
expect(result.current.errors.password).toBe('Server-side password issue');
act(() => {
result.current.setErrors({
password: undefined,
confirmPassword: 'Still invalid',
});
});
expect(result.current.errors.confirmPassword).toBe('Still invalid');
act(() => {
result.current.clearErrors();
});
expect(result.current.errors).toEqual({});
});
it('setValues with clearErrors resets touched state and revalidates', () => {
const { result } = renderHook(() =>
useValidatedFields({
initialValues: { password: '', confirmPassword: '' },
validate,
}),
);
act(() => {
result.current.setFieldValue('password', 'ab');
});
expect(result.current.errors.password).toBe('Password too short');
act(() => {
result.current.setValues(
{
password: 'abcd',
confirmPassword: 'abcd',
},
{ clearErrors: true },
);
});
expect(result.current.values).toEqual({
password: 'abcd',
confirmPassword: 'abcd',
});
expect(result.current.errors).toEqual({});
expect(result.current.isValid).toBe(true);
});
});