react-swift-form
Version:
React library fro form validation
1,689 lines (1,640 loc) • 67.7 kB
text/typescript
import type { IError } from '../types';
import { defaultSymbol, initialError } from '../constants';
import {
displayErrors,
focusError,
getAllError,
getCustomMessage,
getData,
getErrorObject,
getFieldMessages,
getFilteredErrors,
getManualError,
getNativeError,
getNativeErrorKey,
getNativeErrors,
getValidatorError,
getValidatorIds,
hasError,
isLocalValidator,
isValidator,
isValidatorObject,
mergeErrors,
setMainError,
setValidatorError,
validateForm,
} from './validator';
describe('validator helper', () => {
let form: HTMLFormElement;
let input1: HTMLInputElement;
let input2: HTMLInputElement;
let input3: HTMLInputElement;
let input4: HTMLInputElement;
beforeEach(() => {
form = document.createElement('form');
input1 = document.createElement('input');
input1.setAttribute('name', 'foo');
input1.setAttribute('value', '');
form.appendChild(input1);
input2 = document.createElement('input');
input2.setAttribute('name', 'bar');
input2.setAttribute('value', '');
form.appendChild(input2);
input3 = document.createElement('input');
input3.setAttribute('name', 'radio');
input3.setAttribute('type', 'checkbox');
input3.setAttribute('value', '1');
form.appendChild(input3);
input4 = document.createElement('input');
input4.setAttribute('name', 'radio');
input4.setAttribute('type', 'checkbox');
input4.setAttribute('value', '2');
form.appendChild(input4);
});
describe('displayErrors', () => {
it('should not display any error if there is no error (non native form validation)', () => {
const errors = initialError;
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
displayErrors({
display: true,
errors,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
formErrors.mockClear();
displayErrors({
display: true,
errors,
form,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
formErrors.mockClear();
displayErrors({
display: false,
errors,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
formErrors.mockClear();
displayErrors({
display: true,
errors,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
displayErrors({
display: true,
errors,
form,
names: ['foo'],
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
});
it('should focus the error field (non native form validation)', () => {
const errors: IError = {
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
};
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const spy = jest.spyOn(input1, 'focus');
displayErrors({
display: true,
errors,
focusOnError: true,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(spy).toHaveBeenCalled();
spy.mockClear();
displayErrors({
display: true,
errors,
focusOnError: true,
form,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(spy).toHaveBeenCalled();
spy.mockClear();
displayErrors({
display: false,
errors,
focusOnError: true,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(spy).not.toHaveBeenCalled();
spy.mockClear();
displayErrors({
display: false,
errors,
focusOnError: true,
form,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
});
it('should display the input errors (non native input validation)', () => {
const errors: IError = {
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
};
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const fooErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const barErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const validators = [
{
id: 'foo',
names: ['foo'],
setErrors: fooErrors,
},
{
id: 'bar',
names: ['bar'],
setErrors: barErrors,
},
];
const localFields = { foo: fooErrors };
displayErrors({
display: true,
errors,
focusOnError: false,
form,
localFields,
names: ['foo'],
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(fooErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
});
expect(formErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
});
expect(barErrors).not.toHaveBeenCalled();
formErrors.mockClear();
fooErrors.mockClear();
displayErrors({
display: true,
errors,
focusOnError: false,
form,
localFields,
names: ['foo'],
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(fooErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
});
expect(formErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
});
expect(barErrors).not.toHaveBeenCalled();
formErrors.mockClear();
fooErrors.mockClear();
displayErrors({
display: false,
errors,
focusOnError: false,
form,
localFields,
names: ['foo'],
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(fooErrors.mock.results[0].value).toEqual({
all: {},
global: {},
manual: {},
native: {},
validator: {},
});
expect(formErrors.mock.results[0].value).toEqual({
all: {},
global: {},
manual: {},
native: {},
validator: {},
});
expect(barErrors).not.toHaveBeenCalled();
formErrors.mockClear();
fooErrors.mockClear();
displayErrors({
display: false,
errors,
focusOnError: false,
form,
localFields,
names: ['foo'],
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(formErrors).not.toHaveBeenCalled();
expect(fooErrors).not.toHaveBeenCalled();
expect(barErrors).not.toHaveBeenCalled();
});
it('should focus the error field (non native input validation)', () => {
const errors: IError = {
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
};
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const fooErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const barErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const validators = [
{
id: 'foo',
names: ['foo'],
setErrors: fooErrors,
},
{
id: 'foo',
names: ['foo'],
setErrors: fooErrors,
validator: () => 'validator',
},
{
id: 'bar',
names: ['bar'],
setErrors: barErrors,
},
{
id: 'bar',
names: ['bar'],
setErrors: barErrors,
validator: () => '',
},
];
const localFields = { foo: fooErrors };
const spy = jest.spyOn(input1, 'focus');
displayErrors({
display: true,
errors,
focusOnError: true,
form,
localFields,
names: ['foo', 'bar'],
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(fooErrors).toHaveBeenCalled();
expect(barErrors).toHaveBeenCalled();
expect(spy).toHaveBeenCalled();
spy.mockClear();
displayErrors({
display: true,
errors,
focusOnError: true,
form,
localFields,
names: ['foo', 'bar'],
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(spy).toHaveBeenCalled();
spy.mockClear();
displayErrors({
display: false,
errors,
focusOnError: true,
form,
localFields,
names: ['foo', 'bar'],
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(spy).not.toHaveBeenCalled();
spy.mockClear();
displayErrors({
display: false,
errors,
focusOnError: true,
form,
localFields,
names: ['foo', 'bar'],
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
});
it('should trigger form reportValidity function (native form validation)', () => {
const errors = initialError;
const formSpy = jest.spyOn(form, 'reportValidity');
const inputSpy = jest.spyOn(input1, 'reportValidity');
displayErrors({
display: true,
errors,
form,
revalidate: true,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockClear();
inputSpy.mockClear();
displayErrors({
display: true,
errors,
form,
revalidate: false,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockClear();
inputSpy.mockClear();
displayErrors({
display: false,
errors,
form,
revalidate: true,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockClear();
inputSpy.mockClear();
displayErrors({
display: false,
errors,
form,
revalidate: false,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockRestore();
inputSpy.mockClear();
});
it('should trigger input reportValidity function (native input validation)', () => {
input1.setAttribute('required', '');
const formSpy = jest.spyOn(form, 'reportValidity');
const inputSpy = jest.spyOn(input1, 'reportValidity');
displayErrors({
display: true,
errors: initialError,
form,
names: ['foo'],
revalidate: true,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockClear();
inputSpy.mockClear();
displayErrors({
display: true,
errors: initialError,
form,
names: ['foo'],
revalidate: false,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockClear();
inputSpy.mockClear();
displayErrors({
display: false,
errors: initialError,
form,
names: ['foo'],
revalidate: true,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockClear();
inputSpy.mockClear();
displayErrors({
display: false,
errors: initialError,
form,
names: ['foo'],
revalidate: false,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockRestore();
inputSpy.mockClear();
const errors: IError = {
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
};
displayErrors({
display: true,
errors,
focusOnError: false,
form,
names: ['foo'],
revalidate: true,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).toHaveBeenCalled();
formSpy.mockRestore();
inputSpy.mockClear();
displayErrors({
display: true,
errors,
focusOnError: false,
form,
names: ['foo'],
revalidate: false,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).toHaveBeenCalled();
formSpy.mockRestore();
inputSpy.mockClear();
displayErrors({
display: false,
errors,
focusOnError: false,
form,
names: ['foo'],
revalidate: true,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).toHaveBeenCalled();
formSpy.mockRestore();
inputSpy.mockClear();
displayErrors({
display: false,
errors,
focusOnError: false,
form,
names: ['foo'],
revalidate: false,
setErrors: () => '',
useNativeValidation: true,
validators: [],
});
expect(formSpy).not.toHaveBeenCalled();
expect(inputSpy).not.toHaveBeenCalled();
formSpy.mockRestore();
inputSpy.mockRestore();
});
it('should not display the local errors on the form (filterLocalErrors=true)', () => {
const errors: IError = {
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: false, names: ['foo'] },
},
};
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const inputErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const validators = [
{
id: 'foo',
names: ['foo'],
setErrors: inputErrors,
},
{
id: 'foo',
names: ['foo'],
setErrors: inputErrors,
validator: () => 'validator',
},
];
const localFields = { foo: inputErrors };
displayErrors({
display: true,
errors,
filterLocalErrors: true,
form,
localFields,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: false, names: ['foo'] },
},
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
inputErrors.mockClear();
formErrors.mockClear();
displayErrors({
display: true,
errors,
filterLocalErrors: true,
form,
localFields,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: false, names: ['foo'] },
},
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
inputErrors.mockClear();
formErrors.mockClear();
displayErrors({
display: false,
errors,
filterLocalErrors: true,
form,
localFields,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors.mock.results[0].value).toEqual(initialError);
expect(formErrors.mock.results[0].value).toEqual(initialError);
inputErrors.mockClear();
formErrors.mockClear();
displayErrors({
display: false,
errors,
filterLocalErrors: true,
form,
localFields,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors).not.toHaveBeenCalled();
expect(formErrors).not.toHaveBeenCalled();
});
it('should display the form errors (non native form validation)', () => {
const errors: IError = {
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
};
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
displayErrors({
display: true,
errors,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
});
formErrors.mockClear();
displayErrors({
display: true,
errors,
form,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
});
formErrors.mockClear();
displayErrors({
display: false,
errors,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
formErrors.mockClear();
});
it('should display the global error on the local field (filterLocalErrors=true)', () => {
const errors: IError = {
all: { foo: 'error' },
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
};
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const inputErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
const validators = [
{
id: 'fooo',
names: ['foo'],
setErrors: inputErrors,
},
{
id: 'foo',
names: ['foo'],
validator: () => 'validator',
},
];
const localFields = { foo: inputErrors };
displayErrors({
display: true,
errors,
filterLocalErrors: true,
form,
localFields,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
});
expect(formErrors.mock.results[0].value).toEqual({
all: {},
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'validator', global: true, id: 'foo', names: ['foo'] },
manual: {},
native: {},
validator: {},
});
inputErrors.mockClear();
formErrors.mockClear();
displayErrors({
display: true,
errors,
filterLocalErrors: true,
form,
localFields,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: { foo: 'error' },
validator: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
});
expect(formErrors.mock.results[0].value).toEqual({
all: {},
global: {
foo: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'validator', global: true, id: 'foo', names: ['foo'] },
manual: {},
native: {},
validator: {},
});
inputErrors.mockClear();
formErrors.mockClear();
displayErrors({
display: false,
errors,
filterLocalErrors: true,
form,
localFields,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors.mock.results[0].value).toEqual(initialError);
expect(formErrors.mock.results[0].value).toEqual(initialError);
inputErrors.mockClear();
formErrors.mockClear();
displayErrors({
display: false,
errors,
filterLocalErrors: true,
form,
localFields,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors).not.toHaveBeenCalled();
expect(formErrors).not.toHaveBeenCalled();
});
it('should display global validators on the form (filterLocalErrors=true)', () => {
const errors: IError = {
all: { foo: 'error' },
global: {
foo: { error: 'error', global: true, names: ['foo'] },
},
main: { error: 'error', global: true, id: 'foo', names: ['foo'] },
manual: {},
native: {},
validator: {
foo: { error: 'error', global: true, names: ['foo'] },
},
};
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(initialError) : d,
);
displayErrors({
display: true,
errors,
filterLocalErrors: true,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {
foo: { error: 'error', global: true, names: ['foo'] },
},
main: { error: 'error', global: true, id: 'foo', names: ['foo'] },
manual: {},
native: {},
validator: {
foo: { error: 'error', global: true, names: ['foo'] },
},
});
formErrors.mockClear();
displayErrors({
display: true,
errors,
filterLocalErrors: true,
form,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual({
all: { foo: 'error' },
global: {
foo: { error: 'error', global: true, names: ['foo'] },
},
main: { error: 'error', global: true, id: 'foo', names: ['foo'] },
manual: {},
native: {},
validator: {
foo: { error: 'error', global: true, names: ['foo'] },
},
});
formErrors.mockClear();
displayErrors({
display: false,
errors,
filterLocalErrors: true,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value).toEqual(initialError);
formErrors.mockClear();
displayErrors({
display: false,
errors,
filterLocalErrors: true,
form,
revalidate: false,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors).not.toHaveBeenCalled();
});
it('should return the previous error when the error are the same', () => {
const errors: IError = {
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: {},
native: {},
validator: {
foo: { error: 'error', global: false, names: ['foo'] },
},
};
const prevErrors = {
all: { foo: 'error' },
global: {},
main: { error: 'error', global: false, id: 'foo', names: ['foo'] },
manual: {},
native: {},
validator: {
foo: { error: 'error', global: false, names: ['foo'] },
},
};
const formErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(prevErrors) : d,
);
const inputErrors = jest.fn((d: IError | ((error: IError) => IError)) =>
typeof d === 'function' ? d(prevErrors) : d,
);
displayErrors({
display: true,
errors,
filterLocalErrors: true,
form,
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators: [],
});
expect(formErrors.mock.results[0].value === prevErrors).toEqual(true);
formErrors.mockClear();
inputErrors.mockClear();
const validators = [
{
id: 'fooo',
names: ['foo'],
setErrors: inputErrors,
},
{
id: 'foo',
names: ['foo'],
validator: () => 'validator',
},
];
const localFields = { foo: inputErrors };
displayErrors({
display: true,
errors,
filterLocalErrors: true,
form,
localFields,
names: ['foo'],
revalidate: true,
setErrors: formErrors,
useNativeValidation: false,
validators,
});
expect(inputErrors.mock.results[0].value === prevErrors).toEqual(true);
formErrors.mockClear();
inputErrors.mockClear();
});
});
describe('focusError', () => {
it('should not set the focus (no error)', () => {
const spy = jest.spyOn(input1, 'focus');
expect(
focusError(Array.from(form.elements) as HTMLInputElement[]),
).toEqual(false);
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
});
it('should set the focus on the right field', () => {
const spy1 = jest.spyOn(input1, 'focus');
const spy2 = jest.spyOn(input2, 'focus');
expect(
focusError(Array.from(form.elements) as HTMLInputElement[], {
error: 'error',
global: false,
id: 'foo',
names: ['foo'],
}),
).toEqual(true);
expect(spy1).toHaveBeenCalled();
expect(spy2).not.toHaveBeenCalled();
spy1.mockClear();
spy2.mockClear();
expect(
focusError(Array.from(form.elements) as HTMLInputElement[], {
error: 'error',
global: false,
id: 'foobar',
names: ['foo', 'bar'],
}),
).toEqual(true);
expect(spy1).toHaveBeenCalled();
expect(spy2).not.toHaveBeenCalled();
spy1.mockClear();
spy2.mockClear();
expect(
focusError(Array.from(form.elements) as HTMLInputElement[], {
error: 'error',
global: false,
id: 'bar',
names: ['bar'],
}),
).toEqual(true);
expect(spy1).not.toHaveBeenCalled();
expect(spy2).toHaveBeenCalled();
spy1.mockRestore();
spy2.mockRestore();
});
it('should not set the focus (error is for another field)', () => {
const spy = jest.spyOn(input1, 'focus');
expect(
focusError(Array.from(form.elements) as HTMLInputElement[], {
error: 'error',
global: false,
id: 'baz',
names: ['baz'],
}),
).toEqual(false);
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
});
});
describe('getAllError', () => {
it('should get the all error object', () => {
expect(getAllError({}, {})).toEqual({});
expect(getAllError({ foo: 'native' }, {})).toEqual({ foo: 'native' });
expect(
getAllError(
{},
{ foobar: { error: 'validator', global: true, names: ['foo'] } },
{ foo: null },
),
).toEqual({ foo: 'validator' });
expect(getAllError({ foo: '' }, {}, { foo: 'manual' })).toEqual({
foo: 'manual',
});
expect(getAllError({ foo: 'native' }, {}, { foo: null })).toEqual({
foo: 'native',
});
expect(
getAllError(
{ foo: 'native' },
{ foobar: { error: 'validator', global: true, names: ['foo'] } },
),
).toEqual({ foo: 'native' });
expect(
getAllError(
{ foo: 'native' },
{ foobar: { error: 'validator', global: true, names: ['foo'] } },
{ foo: 'manual' },
),
).toEqual({ foo: 'native' });
});
});
describe('getCustomMessage', () => {
it('should return the custom message if exists', () => {
expect(getCustomMessage(null)).toEqual('');
expect(getCustomMessage('')).toEqual('');
expect(getCustomMessage('custom')).toEqual('custom');
expect(getCustomMessage('custom', { custom: 'Custom message' })).toEqual(
'Custom message',
);
});
});
describe('getData', () => {
it('should return all form data', () => {
input1.setAttribute('value', '42');
input2.setAttribute('value', 'baz');
expect(getData({ form })).toEqual({
bar: 'baz',
foo: '42',
});
expect(getData({ form, values: { foo: 42 } })).toEqual({
bar: 'baz',
foo: 42,
});
});
it('should return values for multiple fields', () => {
const form = document.createElement('form');
const email = document.createElement('input');
email.setAttribute('name', 'email');
email.setAttribute('type', 'email');
email.setAttribute('multiple', '');
email.setAttribute('value', 'foo@bar, bar@baz');
form.appendChild(email);
const select = document.createElement('select');
select.setAttribute('name', 'select');
select.setAttribute('multiple', '');
const option1 = document.createElement('option');
option1.setAttribute('value', 'opt1');
option1.setAttribute('selected', '');
select.appendChild(option1);
const option2 = document.createElement('option');
option2.setAttribute('value', 'opt2');
option2.setAttribute('selected', '');
select.appendChild(option2);
form.appendChild(select);
expect(getData({ form })).toEqual({
email: ['foo@bar', 'bar@baz'],
select: ['opt1', 'opt2'],
});
expect(getData({ form, values: { select: [1, 2] } })).toEqual({
email: ['foo@bar', 'bar@baz'],
select: [1, 2],
});
});
it('should return filtered form data', () => {
input1.setAttribute('value', '42');
input2.setAttribute('value', 'baz');
expect(getData({ form, names: ['foo'], values: {} })).toEqual({
foo: '42',
});
expect(
getData({ form, names: ['foo'], values: { bar: 'foo', foo: 42 } }),
).toEqual({
foo: 42,
});
});
it('should return transformed form data', () => {
input1.setAttribute('value', '42');
input2.setAttribute('value', 'baz');
expect(getData({ form, transformers: { foo: Number } })).toEqual({
bar: 'baz',
foo: 42,
});
expect(
getData({ form, names: ['foo'], transformers: { foo: Number } }),
).toEqual({
foo: 42,
});
expect(
getData({ form, transformers: { bar: Number }, values: { bar: '12' } }),
).toEqual({
bar: 12,
foo: '42',
});
});
it('should return all selected options', () => {
const select = document.createElement('select');
select.setAttribute('name', 'select');
select.setAttribute('multiple', '');
const option1 = document.createElement('option');
option1.setAttribute('value', 'option 1');
option1.setAttribute('selected', '');
select.appendChild(option1);
const option2 = document.createElement('option');
option2.setAttribute('value', 'option 2');
option2.setAttribute('selected', '');
select.appendChild(option2);
const option3 = document.createElement('option');
option3.setAttribute('value', 'option 3');
select.appendChild(option3);
form.appendChild(select);
expect(getData({ form, names: ['select'] })).toEqual({
select: ['option 1', 'option 2'],
});
});
});
describe('getErrorObject', () => {
it('should create the error object', () => {
expect(getErrorObject({ nativeErrors: {}, validatorErrors: {} })).toEqual(
{
all: {},
global: {},
manual: {},
native: {},
validator: {},
},
);
expect(
getErrorObject({
nativeErrors: { foo: 'native' },
validatorErrors: {},
}),
).toEqual({
all: { foo: 'native' },
global: {},
main: { error: 'native', global: false, id: 'foo', names: ['foo'] },
manual: {},
native: { foo: 'native' },
validator: {},
});
expect(
getErrorObject({
nativeErrors: {},
validatorErrors: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
}),
).toEqual({
all: { foo: 'validator' },
global: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
main: {
error: 'validator',
global: true,
id: 'foobar',
names: ['foo'],
},
manual: {},
native: {},
validator: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
});
expect(
getErrorObject({
manualErrors: { foo: 'manual' },
nativeErrors: {},
validatorErrors: {},
}),
).toEqual({
all: { foo: 'manual' },
global: {},
main: { error: 'manual', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: {},
validator: {},
});
expect(
getErrorObject({
nativeErrors: { foo: 'native' },
validatorErrors: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
}),
).toEqual({
all: { foo: 'native' },
global: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'native', global: false, id: 'foo', names: ['foo'] },
manual: {},
native: { foo: 'native' },
validator: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
});
expect(
getErrorObject({
manualErrors: { foo: 'manual' },
nativeErrors: {},
validatorErrors: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
}),
).toEqual({
all: { foo: 'manual' },
global: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
main: { error: 'manual', global: false, id: 'foo', names: ['foo'] },
manual: { foo: 'manual' },
native: {},
validator: {
foobar: { error: 'validator', global: true, names: ['foo'] },
},
});
});
});
describe('getFieldMessages', () => {
it('should merge custom messages', () => {
const validators = [
{
id: 'foo',
messages: { valueMissing: 'Did you miss something ?' },
names: ['foo'],
validator: () => '',
},
];
expect(getFieldMessages(validators)).toEqual({
[defaultSymbol]: {},
foo: { valueMissing: 'Did you miss something ?' },
});
expect(
getFieldMessages(validators, {
badInput: 'badInput',
}),
).toEqual({
[defaultSymbol]: { badInput: 'badInput' },
foo: { valueMissing: 'Did you miss something ?' },
});
expect(
getFieldMessages(validators, {
valueMissing: 'valueMissing',
}),
).toEqual({
[defaultSymbol]: { valueMissing: 'valueMissing' },
foo: { valueMissing: 'Did you miss something ?' },
});
});
});
describe('getFilteredErrors', () => {
it('should filter errors', () => {
expect(getFilteredErrors({ foo: 'error' })).toEqual({ foo: 'error' });
expect(getFilteredErrors({ foo: 'error' }, ['foo'])).toEqual({
foo: 'error',
});
expect(getFilteredErrors({ foo: 'error' }, ['bar'])).toEqual({});
});
});
describe('getManualError', () => {
it('should not return any error', () => {
const spy = jest.spyOn(input1, 'setCustomValidity');
expect(getManualError({ form })).toEqual({});
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
});
it('should return the manual error', () => {
const spy = jest.spyOn(input1, 'setCustomValidity');
expect(getManualError({ errors: { foo: 'manual' }, form })).toEqual({
foo: 'manual',
});
expect(spy).toHaveBeenCalledWith('manual');
spy.mockRestore();
});
it('should return the manual error with custom message', () => {
const spy = jest.spyOn(input1, 'setCustomValidity');
expect(
getManualError({
errors: { foo: 'manual' },
fieldMessages: { foo: { manual: 'Manual error' } },
form,
}),
).toEqual({
foo: 'Manual error',
});
expect(spy).toHaveBeenCalledWith('Manual error');
spy.mockRestore();
});
it('should return the manual error with custom message fallback', () => {
const spy = jest.spyOn(input1, 'setCustomValidity');
expect(
getManualError({
errors: { foo: 'manual' },
fieldMessages: { [defaultSymbol]: { manual: 'Manual error' } },
form,
}),
).toEqual({
foo: 'Manual error',
});
expect(spy).toHaveBeenCalledWith('Manual error');
spy.mockRestore();
});
});
describe('getNativeError', () => {
it('should not return any error (valid)', () => {
expect(getNativeError({ input: input1 })).toEqual('');
});
it('should return the native required error', () => {
input1.setAttribute('required', '');
expect(getNativeError({ input: input1 })).toEqual(
'Constraints not satisfied',
);
});
it('should return the custom required error', () => {
input1.setAttribute('required', '');
expect(
getNativeError({
input: input1,
messages: { valueMissing: 'Did you miss something ?' },
}),
).toEqual('Did you miss something ?');
});
});
describe('getNativeErrorKey', () => {
it('should not return any error key', () => {
expect(getNativeErrorKey()).toEqual(null);
expect(getNativeErrorKey(input1.validity)).toEqual(null);
});
it('should return the form native error key (required)', () => {
input1.setAttribute('required', '');
expect(getNativeErrorKey(input1.validity)).toEqual('valueMissing');
});
});
describe('getNativeErrors', () => {
it('should not return any error (valid)', () => {
expect(getNativeErrors({ fieldMessages: {}, form })).toEqual({
bar: '',
foo: '',
radio: '',
});
});
it('should return native error', () => {
input1.setAttribute('required', '');
expect(getNativeErrors({ fieldMessages: {}, form })).toEqual({
bar: '',
foo: 'Constraints not satisfied',
radio: '',
});
});
it('should return native error with custom message', () => {
input1.setAttribute('required', '');
expect(
getNativeErrors({
fieldMessages: { foo: { valueMissing: 'Did you miss something ?' } },
form,
}),
).toEqual({
bar: '',
foo: 'Did you miss something ?',
radio: '',
});
expect(
getNativeErrors({
fieldMessages: {
[defaultSymbol]: { valueMissing: 'Did you miss something ?' },
},
form,
}),
).toEqual({
bar: '',
foo: 'Did you miss something ?',
radio: '',
});
});
});
describe('getValidatorError', () => {
it('should not return any error (empty array)', async () => {
expect(await getValidatorError({ form })).toEqual([]);
});
it('should not return any error (no validators)', async () => {
const validators = [{ id: 'foo', names: ['foo'], setErrors: () => null }];
expect(await getValidatorError({ form, validators })).toEqual(['']);
});
it('should return the validator error', async () => {
const validators = [
{
id: 'foo',
names: ['foo'],
validator: () => 'validator',
},
];
expect(await getValidatorError({ form, validators })).toEqual([
'validator',
]);
});
it('should return the async validator error', async () => {
const validators = [
{
id: 'foo',
names: ['foo'],
validator: () => Promise.resolve('validator'),
},
];
expect(await getValidatorError({ form, validators })).toEqual([
'validator',
]);
});
});
describe('setValidatorError', () => {
it('should not return any error (no validators)', () => {
const spy = jest.spyOn(input1, 'setCustomValidity');
expect(
setValidatorError({ form, validatorResults: [], validators: [] }),
).toEqual({});
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
});
it('should not return any error (no error)', () => {
const spy = jest.spyOn(input1, 'setCustomValidity');
expect(
setValidatorError({
form,
validatorResults: [''],
validators: [
{
id: 'foo',
names: ['foo'],
validator: () => 'validator',
},
],
}),
).toEqual({});
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
});
it('should return the validator error', () => {
const spy = jest.spyOn(input1, 'setCustomValidity');
expect(
setValidatorError({
form,
validatorResults: ['validator'],
validators: [
{
id: 'foo',
names: ['foo'],
validator: () => 'validator',
},
],
}),
).toEqual({
foo: { error: 'validator', global: true, names: ['foo'] },
});
expect(spy).toHaveBeenCalledWith('validator');
spy.mockRestore();
});
it('should return the validator error but not call setCustomValidity because of existing native error', () => {
const spy = jest.spyOn(input1, 'setCustomValidity');
input1.setAttribute('required', '');
expect(
setValidatorError({
form,
validatorResults: ['validator'],