All checks were successful
continuous-integration/drone/push Build is passing
159 lines
4.9 KiB
TypeScript
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);
|
|
});
|
|
});
|