react-formulize
Version:
A simple form validation library for React.js which wires up custom, controlled inputs through a declarative API.
443 lines (359 loc) • 17.6 kB
JavaScript
/* globals describe it before beforeEach after afterEach xit */
import { expect } from 'chai'; // eslint-disable-line
import sinon from 'sinon'; // eslint-disable-line
import { shallow, mount } from 'enzyme'; // eslint-disable-line
import { buildField, updateInput } from '../spec_helpers';
import * as validators from '../../src/helpers/validators';
describe('Validator Functionality', () => {
describe('Required', () => {
const wrapper = buildField(mount, 'required', true);
const valFunc = validators.required();
it('returns true for non-empty input', () => {
expect(valFunc('Test Input')).to.equal(true);
expect(valFunc('123')).to.equal(true);
expect(valFunc(123)).to.equal(true);
expect(valFunc(0)).to.equal(true);
});
it('returns false for empty input', () => {
expect(valFunc('')).to.equal(false);
});
it('returns false for non-valid input', () => {
expect(valFunc({ param: 'value' })).to.equal(false);
expect(valFunc(() => {})).to.equal(false);
expect(valFunc(null)).to.equal(false);
expect(valFunc(undefined)).to.equal(false);
expect(valFunc(new Promise(() => {}))).to.equal(false);
});
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
updateInput(wrapper, 'test input!');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 'test input!');
updateInput(wrapper, '');
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
});
});
describe('Email', () => {
const wrapper = buildField(mount, 'email', true);
const valFunc = validators.email();
it('returns `true` for valid email addresses', () => {
expect(valFunc('test@test.com')).to.equal(true);
expect(valFunc('test.test.test@test.com')).to.equal(true);
expect(valFunc('test@test.test.test')).to.equal(true);
expect(valFunc('test.test@test.test')).to.equal(true);
});
it('returns `false` for invalid email addresses', () => {
expect(valFunc('')).to.equal(false);
expect(valFunc('test@test.')).to.equal(false);
expect(valFunc('test@@test.test.test')).to.equal(false);
expect(valFunc('test.test@test..test')).to.equal(false);
expect(valFunc('test..test@test.test')).to.equal(false);
});
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
updateInput(wrapper, 'test@test.test');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 'test@test.test');
updateInput(wrapper, '');
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
});
it('can take a custom regular expression for validating', () => {
const newWrapper = buildField(mount, 'email', /test\@test\.test/);
expect(newWrapper.state()).to.have.property('valid', false);
expect(newWrapper.state()).to.have.property('value', '');
// Updating input to valid email which doesn't match RegEx
updateInput(newWrapper, 'valid@email.com');
expect(newWrapper.state()).to.have.property('valid', false);
expect(newWrapper.state()).to.have.property('value', 'valid@email.com');
// Updating input to matching email
updateInput(newWrapper, 'test@test.test');
expect(newWrapper.state()).to.have.property('valid', true);
expect(newWrapper.state()).to.have.property('value', 'test@test.test');
// Updating input to valid email which doesn't match RegEx
updateInput(newWrapper, 'test@test.tes');
expect(newWrapper.state()).to.have.property('valid', false);
expect(newWrapper.state()).to.have.property('value', 'test@test.tes');
});
it('can take a custom function for validating', () => {
const newWrapper = buildField(mount, 'email', (emailValue) => {
if (emailValue.indexOf('@') >= 0 && emailValue.indexOf('.') >= 0) {
return true;
}
return false;
});
expect(newWrapper.state()).to.have.property('valid', false);
expect(newWrapper.state()).to.have.property('value', '');
// Updating input to valid email which doesn't match RegEx
updateInput(newWrapper, 'invalidemail.com');
expect(newWrapper.state()).to.have.property('valid', false);
expect(newWrapper.state()).to.have.property('value', 'invalidemail.com');
// Updating input to matching email
updateInput(newWrapper, 'test@test.test');
expect(newWrapper.state()).to.have.property('valid', true);
expect(newWrapper.state()).to.have.property('value', 'test@test.test');
});
});
describe('Length', () => {
const minLen = 6;
const maxLen = 10;
const wrapper = buildField(mount, 'length', [minLen, maxLen]);
/**
* Length Validator Function
* @lengthArray {Array} - [minLen, maxLen] OR [maxLen]
*/
const valFunc = validators.length([minLen, maxLen]);
it('returns `true` for inputs `>=minLen` and `<=maxLen`', () => {
expect(valFunc('123456')).to.equal(true);
expect(valFunc('0123456789')).to.equal(true);
expect(valFunc('Test input')).to.equal(true);
expect(valFunc('\'Quote123\'')).to.equal(true);
});
it('returns `false` for inputs `<minLen` and `>maxLen`', () => {
expect(valFunc('')).to.equal(false);
expect(valFunc('12345')).to.equal(false);
expect(valFunc('012345678910')).to.equal(false);
expect(valFunc('Test Input!')).to.equal(false);
});
it('returns `false` for non-string inputs', () => {
expect(valFunc(12345678)).to.equal(false);
expect(valFunc(() => '12345678')).to.equal(false);
expect(valFunc({ value: 'Test Input' })).to.equal(false);
expect(valFunc(true)).to.equal(false);
});
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
updateInput(wrapper, 'Test Input');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 'Test Input');
updateInput(wrapper, 'Test Input!');
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', 'Test Input!');
updateInput(wrapper, '0123456789');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', '0123456789');
});
});
describe('Match', () => {
const returnValue = () => 'My input value!';
const wrapper = buildField(mount, 'match', returnValue());
const valFunc = validators.match(returnValue);
it('returns `true` for a matching input', () => {
expect(valFunc('My input value!')).to.equal(true);
});
it('returns `false` for non-matching inputs', () => {
expect(valFunc('')).to.equal(false);
expect(valFunc({ value: 'My input value!' })).to.equal(false);
expect(valFunc('My input value')).to.equal(false);
expect(valFunc(() => 'My input value!')).to.equal(false);
});
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
updateInput(wrapper, 'Wrong Input!');
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', 'Wrong Input!');
updateInput(wrapper, 'My input value!');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 'My input value!');
updateInput(wrapper, 'Will this work?');
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', 'Will this work?'); // No!
});
});
describe('Alpha', () => {
const wrapper = buildField(mount, 'alpha', true);
const valFunc = validators.alpha();
// Implemented to only supports english
it('returns `true` for strings consisting of only alphabet and space characters', () => {
expect(valFunc('')).to.equal(true);
expect(valFunc('abc')).to.equal(true);
expect(valFunc('ABC')).to.equal(true);
expect(valFunc('AaBbCc')).to.equal(true);
expect(valFunc('AaBbCc Second Word')).to.equal(true);
expect(valFunc('\t\n ')).to.equal(true);
});
it('returns `false` for text inputs with non-alphabet characters', () => {
expect(valFunc('_')).to.equal(false);
expect(valFunc('abc!')).to.equal(false);
expect(valFunc('ABC*')).to.equal(false);
expect(valFunc('$AaBbCc')).to.equal(false);
expect(valFunc('$!\.')).to.equal(false);
expect(valFunc('0123')).to.equal(false);
expect(valFunc('Is this valid?')).to.equal(false);
});
it('returns `false` for non-string inputs', () => {
expect(valFunc(() => 'Good String Input')).to.equal(false);
expect(valFunc({ value: 'Good String Input' })).to.equal(false);
expect(valFunc(1234)).to.equal(false);
expect(valFunc(true)).to.equal(false);
});
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', '');
updateInput(wrapper, 'Test Input');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 'Test Input');
updateInput(wrapper, 'Test Input!');
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', 'Test Input!');
updateInput(wrapper, 'Testing \ttabs and \nnewlines');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 'Testing \ttabs and \nnewlines');
});
});
describe('Number', () => {
const wrapper = buildField(mount, 'number', true);
const valFunc = validators.numeric();
it('returns `true` for strings consisting of only number characters', () => {
expect(valFunc('')).to.equal(true);
expect(valFunc('4e-10')).to.equal(true);
expect(valFunc('0.5E+10')).to.equal(true);
expect(valFunc('0123')).to.equal(true);
expect(valFunc(123e-10)).to.equal(true);
expect(valFunc(456e-10)).to.equal(true);
expect(valFunc(123)).to.equal(true);
});
it('returns `false` for text inputs with non-numeric/non-space characters', () => {
expect(valFunc('\t\n ')).to.equal(false);
expect(valFunc('_')).to.equal(false);
expect(valFunc('123!')).to.equal(false);
expect(valFunc('890*')).to.equal(false);
expect(valFunc('123 123 123')).to.equal(false);
expect(valFunc('1234-1234-1234-1234')).to.equal(false);
expect(valFunc('$112233')).to.equal(false);
expect(valFunc('$!\.')).to.equal(false);
expect(valFunc('Is this valid?')).to.equal(false);
});
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('value', '');
expect(wrapper.state()).to.have.property('valid', true);
updateInput(wrapper, '12345\t12345 12345');
expect(wrapper.state()).to.have.property('value', '12345\t12345 12345');
expect(wrapper.state()).to.have.property('valid', false);
updateInput(wrapper, '1234-1234-1234-1234');
expect(wrapper.state()).to.have.property('value', '1234-1234-1234-1234');
expect(wrapper.state()).to.have.property('valid', false);
updateInput(wrapper, 123, 'number');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 123);
updateInput(wrapper, 0.5e3, 'number');
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 0.5e3);
});
});
describe('Max', () => {
const criterion = 6;
const wrapper = buildField(mount, 'max', criterion, 'number');
const valFunc = validators.max(criterion);
it('returns `true` for numbers less than or equal to the criterion', () => {
expect(valFunc(-5000)).to.equal(true);
expect(valFunc('-5000')).to.equal(true);
expect(valFunc('+5')).to.equal(true);
expect(valFunc(0)).to.equal(true);
expect(valFunc(4)).to.equal(true);
expect(valFunc(+4)).to.equal(true);
expect(valFunc(6)).to.equal(true);
expect(valFunc('6')).to.equal(true);
expect(valFunc(-Infinity)).to.equal(true);
});
it('returns `false` for numbers greater than the criterion', () => {
expect(valFunc('')).to.equal(false);
expect(valFunc(7)).to.equal(false);
expect(valFunc(1000)).to.equal(false);
});
// `max` validator coerces input to a `number`
it('returns `false` for non-number & non-string-to-number inputs', () => {
expect(valFunc({ value: 3 })).to.equal(false);
expect(valFunc(() => 2)).to.equal(false);
expect(valFunc(NaN)).to.equal(false);
expect(valFunc(Infinity)).to.equal(false);
expect(valFunc(+Infinity)).to.equal(false);
});
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
updateInput(wrapper, 3);
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 3);
updateInput(wrapper, 6);
expect(wrapper.state()).to.have.property('value', 6);
expect(wrapper.state()).to.have.property('valid', true);
updateInput(wrapper, 10);
expect(wrapper.state()).to.have.property('value', 10);
expect(wrapper.state()).to.have.property('valid', false);
updateInput(wrapper, -5000);
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', -5000);
});
});
describe('Min', () => {
const criterion = 6;
const wrapper = buildField(mount, 'min', criterion);
const valFunc = validators.min(criterion);
it('returns `true` for numbers greater than or equal to the criterion', () => {
expect(valFunc(5000)).to.equal(true);
expect(valFunc('5000')).to.equal(true);
expect(valFunc('+8')).to.equal(true);
expect(valFunc(10)).to.equal(true);
expect(valFunc(84)).to.equal(true);
expect(valFunc(+6)).to.equal(true);
expect(valFunc(6)).to.equal(true);
expect(valFunc('6')).to.equal(true);
expect(valFunc(Infinity)).to.equal(true);
expect(valFunc(+Infinity)).to.equal(true);
});
it('returns `false` for numbers less than the criterion', () => {
expect(valFunc('')).to.equal(false);
expect(valFunc(-5000)).to.equal(false);
expect(valFunc('-1000')).to.equal(false);
expect(valFunc(0)).to.equal(false);
expect(valFunc(5)).to.equal(false);
expect(valFunc('4')).to.equal(false);
});
// `min` validator coerces input to a `number`
it('returns `false` for non-number & non-string-to-number inputs', () => {
expect(valFunc({ value: 3 })).to.equal(false);
expect(valFunc(() => 2)).to.equal(false);
expect(valFunc(NaN)).to.equal(false);
expect(valFunc(-Infinity)).to.equal(false);
});
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
updateInput(wrapper, 3);
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', 3);
updateInput(wrapper, 6);
expect(wrapper.state()).to.have.property('value', 6);
expect(wrapper.state()).to.have.property('valid', true);
updateInput(wrapper, 10);
expect(wrapper.state()).to.have.property('value', 10);
expect(wrapper.state()).to.have.property('valid', true);
updateInput(wrapper, -5000);
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', -5000);
});
});
describe('Custom', () => {
const isPositive = value => typeof value === 'number' && value > 0;
const wrapper = buildField(mount, 'custom', isPositive, 'number');
it('is properly used by a `Field` component to validate', () => {
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '');
updateInput(wrapper, -5);
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', -5);
updateInput(wrapper, 12);
expect(wrapper.state()).to.have.property('valid', true);
expect(wrapper.state()).to.have.property('value', 12);
updateInput(wrapper, '120');
expect(wrapper.state()).to.have.property('valid', false);
expect(wrapper.state()).to.have.property('value', '120');
});
});
});