├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .travis.yml ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __test__ ├── .eslintrc ├── .setup.js ├── AvBaseInput.spec.js ├── AvCheckbox.spec.js ├── AvCheckboxGroup.spec.js ├── AvFeedback.spec.js ├── AvField.spec.js ├── AvForm.spec.js ├── AvGroup.spec.js ├── AvInput.spec.js ├── AvInputContainer.spec.js ├── AvRadio.spec.js ├── AvRadioGroup.spec.js ├── AvValidator.date.spec.js ├── AvValidator.dateRange.spec.js ├── AvValidator.email.spec.js ├── AvValidator.match.spec.js ├── AvValidator.max.spec.js ├── AvValidator.maxchecked.spec.js ├── AvValidator.maxlength.spec.js ├── AvValidator.min.spec.js ├── AvValidator.minchecked.spec.js ├── AvValidator.minlength.spec.js ├── AvValidator.npi.spec.js ├── AvValidator.number.spec.js ├── AvValidator.pattern.spec.js ├── AvValidator.phone.spec.js ├── AvValidator.required.spec.js ├── AvValidator.step.spec.js └── AvValidator.url.spec.js ├── docs ├── lib │ ├── Components │ │ ├── CheckboxPage.js │ │ ├── FormPage.js │ │ ├── ValidatorsPage.js │ │ └── index.js │ ├── Home │ │ └── index.js │ ├── NotFound │ │ └── index.js │ ├── UI │ │ ├── Footer.js │ │ ├── Layout.js │ │ ├── Nav.js │ │ └── index.js │ ├── app.js │ ├── examples │ │ ├── Checkbox.js │ │ ├── CheckboxDefault.js │ │ ├── CheckboxFalseValue.js │ │ ├── CheckboxTrueValue.js │ │ ├── Form.js │ │ ├── FormFeedback.js │ │ ├── FormModel.js │ │ ├── FormOnInvalidSubmit.js │ │ ├── FormOnSubmit.js │ │ ├── FormOnValidSubmit.js │ │ ├── ValidationAsync.js │ │ ├── ValidationCustomMessage.js │ │ ├── ValidationDate.js │ │ ├── ValidationDateRange.js │ │ ├── ValidationDateTime.js │ │ ├── ValidationEmail.js │ │ ├── ValidationMatch.js │ │ ├── ValidationMax.js │ │ ├── ValidationMaxChecked.js │ │ ├── ValidationMaxLength.js │ │ ├── ValidationMin.js │ │ ├── ValidationMinChecked.js │ │ ├── ValidationMinLength.js │ │ ├── ValidationNpi.js │ │ ├── ValidationNumber.js │ │ ├── ValidationPattern.js │ │ ├── ValidationPhone.js │ │ ├── ValidationRequired.js │ │ ├── ValidationStep.js │ │ └── import-basic.js │ └── routes.js └── static │ ├── docs.css │ ├── favicon.ico │ ├── logo.png │ └── prism.js ├── mocha-webpack.opts ├── package-lock.json ├── package.json ├── scripts ├── docs ├── publish └── release ├── src ├── AvBaseInput.js ├── AvCheckbox.js ├── AvCheckboxGroup.js ├── AvFeedback.js ├── AvField.js ├── AvForm.js ├── AvGroup.js ├── AvInput.js ├── AvInputContainer.js ├── AvRadio.js ├── AvRadioGroup.js ├── AvValidator │ ├── date.js │ ├── dateRange.js │ ├── email.js │ ├── index.js │ ├── match.js │ ├── max.js │ ├── maxchecked.js │ ├── maxlength.js │ ├── min.js │ ├── minchecked.js │ ├── minlength.js │ ├── npi.js │ ├── number.js │ ├── pattern.js │ ├── phone.js │ ├── required.js │ ├── step.js │ ├── url.js │ └── utils.js └── index.js ├── webpack.base.config.js ├── webpack.config.js ├── webpack.dev.config.js └── webpack.test.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015-loose", "stage-0", "react"], 3 | "plugins": ["transform-runtime", "transform-proto-to-assign", "transform-class-properties"], 4 | "env": { 5 | "test": { 6 | "plugins": [ 7 | ["istanbul", { 8 | "exclude": [ 9 | "**/*.spec.js", 10 | ".tmp/**/*" 11 | ] 12 | }] 13 | ] 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/coverage/ 2 | dist/ 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends" : "eslint-config-availity/react", 3 | "rules": { 4 | "semi" : [2, "always"], 5 | "no-unused-vars": ["error", { "varsIgnorePattern": "^(unused|omit)" }], 6 | "comma-dangle": [2, "always-multiline"] 7 | }, 8 | "parserOptions": { 9 | "sourceType": "module", 10 | "ecmaFeatures": { 11 | "jsx": true 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /__test__/coverage 2 | node_modules 3 | /dist 4 | /build 5 | /lib 6 | /.tmp -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10 4 | cache: 5 | directories: 6 | - node_modules 7 | script: 8 | - npm run ci 9 | after_success: 10 | - npm run report-coverage 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "jira-plugin.workingProject": "" 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Availity 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/Availity/availity-reactstrap-validation.svg?branch=master)](https://travis-ci.org/Availity/availity-reactstrap-validation) [![Coverage Status](https://coveralls.io/repos/github/Availity/availity-reactstrap-validation/badge.svg?branch=master)](https://coveralls.io/github/Availity/availity-reactstrap-validation?branch=master) 2 | 3 | # availity-reactstrap-validation 4 | 5 | Easy to use React validation components compatible for reactstrap. 6 | 7 | ## Important Update - 4th January, 2021 8 | 9 | This library has been **depreciated** in the favour of [another one](https://availity.github.io/availity-react/form/index). Please, plan your next projects and update your previous ones accordingly. 10 | [This Guide](https://availity.github.io/availity-react/form/migrating) might be useful for you in order to migrate to the new library. 11 | 12 | ## Installation 13 | 14 | Install `availity-reactstrap-validation` and `reactstrap` via NPM 15 | 16 | ```sh 17 | npm install --save availity-reactstrap-validation reactstrap 18 | ``` 19 | 20 | If applicable, install a `Promise` polyfill. For example: 21 | 22 | ```sh 23 | npm install es6-promise --save 24 | ``` 25 | 26 | The polyfill can be applied into your web application by using tools like Webpack or Babel. 27 | 28 | Import the components you need, example: 29 | 30 | ```js 31 | import { AvField } from 'availity-reactstrap-validation'; 32 | ``` 33 | 34 | ## Development 35 | 36 | Install dependencies: 37 | 38 | ```sh 39 | npm install 40 | ``` 41 | 42 | Run examples at [http://localhost:8080/](http://localhost:8080/) with Webpack dev server: 43 | 44 | ```sh 45 | npm start 46 | ``` 47 | 48 | Run tests: 49 | 50 | ```sh 51 | npm test 52 | ``` 53 | 54 | Run tests & coverage report: 55 | 56 | ```sh 57 | npm run test:coverage 58 | ``` 59 | 60 | Watch tests: 61 | 62 | ```sh 63 | npm run test:watch 64 | ``` 65 | 66 | ## Disclaimer 67 | Open source software components distributed or made available in the Availity Materials are licensed to Company under the terms of the applicable open source license agreements, which may be found in text files included in the Availity Materials. 68 | 69 | ## LICENSE [MIT](LICENSE) 70 | -------------------------------------------------------------------------------- /__test__/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends" : "eslint-config-availity/react", 3 | "env": { 4 | "mocha": true, 5 | "node": true 6 | }, 7 | "globals": { 8 | "sinon": true, 9 | "expect": true 10 | }, 11 | "rules": { 12 | "semi" : [2, "always"], 13 | "comma-dangle": [2, "always-multiline"] 14 | }, 15 | "parserOptions": { 16 | "sourceType": "module", 17 | "ecmaFeatures": { 18 | "jsx": true 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /__test__/.setup.js: -------------------------------------------------------------------------------- 1 | var jsdom = require('jsdom'); 2 | const { JSDOM } = jsdom; 3 | var chai = require('chai'); 4 | var sinon = require('sinon'); 5 | var sinonChai = require('sinon-chai'); 6 | var chaiAsPromised = require('chai-as-promised'); 7 | var chaiEnzyme = require('chai-enzyme'); 8 | 9 | var exposedProperties = ['window', 'navigator', 'document']; 10 | 11 | chai.use(sinonChai); 12 | chai.use(chaiAsPromised); 13 | chai.use(chaiEnzyme()); 14 | 15 | chai.config.includeStack = true; 16 | global.expect = chai.expect; 17 | global.AssertionError = chai.AssertionError; 18 | global.Assertion = chai.Assertion; 19 | global.assert = chai.assert; 20 | global.expect = chai.expect; 21 | global.sinon = sinon; 22 | 23 | const { document } = new JSDOM('', { 24 | url: 'http://localhost/' 25 | }).window; 26 | global.document = document; 27 | global.window = document.defaultView; 28 | Object.keys(document.defaultView).forEach(property => { 29 | if (typeof global[property] === 'undefined') { 30 | exposedProperties.push(property); 31 | global[property] = document.defaultView[property]; 32 | } 33 | }); 34 | 35 | global.navigator = { 36 | userAgent: 'node.js' 37 | }; 38 | -------------------------------------------------------------------------------- /__test__/AvCheckbox.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import { AvCheckbox } from 'availity-reactstrap-validation'; 4 | import { Input } from 'reactstrap'; 5 | 6 | let options; 7 | let props; 8 | let inputState; 9 | let component; 10 | 11 | describe('AvCheckbox', () => { 12 | let touched; 13 | let dirty; 14 | let bad; 15 | let error; 16 | 17 | beforeEach(() => { 18 | touched = false; 19 | dirty = false; 20 | bad = false; 21 | error = false; 22 | options = { 23 | context: { 24 | Group: { 25 | getProps: () => ({ 26 | name: 'test', 27 | }), 28 | }, 29 | FormCtrl: { 30 | inputs: {}, 31 | getDefaultValue: ()=> {}, 32 | getInputState: ()=> ({}), 33 | hasError: () => error, 34 | isDirty: () => dirty, 35 | isTouched: () => touched, 36 | isBad: () => bad, 37 | isDisabled: () => false, 38 | isReadOnly: () => false, 39 | setDirty: ()=> {}, 40 | setTouched: ()=> {}, 41 | setBad: ()=> {}, 42 | register: ()=> {}, 43 | unregister: ()=> {}, 44 | validate: ()=> {}, 45 | getValidationEvent: ()=> {}, 46 | validation: {}, 47 | parent: null, 48 | }, 49 | }, 50 | }; 51 | }); 52 | 53 | it('should render a reactstrap Input', () => { 54 | const wrapper = shallow(, options); 55 | 56 | expect(wrapper.type()).to.not.be.undefined; 57 | }); 58 | 59 | it('should have "is-untouched" class when untouched', () => { 60 | const wrapper = shallow(, options); 61 | 62 | expect(wrapper.find(Input).hasClass('is-untouched')).to.be.true; 63 | expect(wrapper.find(Input).hasClass('is-touched')).to.be.false; 64 | }); 65 | 66 | it('should have "is-pristine" class when not dirty', () => { 67 | const wrapper = shallow(, options); 68 | 69 | expect(wrapper.find(Input).hasClass('is-pristine')).to.be.true; 70 | expect(wrapper.find(Input).hasClass('is-dirty')).to.be.false; 71 | }); 72 | 73 | it('should have "av-valid" not "is-invalid" class when valid', () => { 74 | const wrapper = shallow(, options); 75 | 76 | expect(wrapper.find(Input).hasClass('av-valid')).to.be.true; 77 | expect(wrapper.find(Input).hasClass('is-invalid')).to.be.false; 78 | }); 79 | 80 | it('should have "is-touched" class when touched', () => { 81 | touched = true; 82 | const wrapper = shallow(, options); 83 | 84 | expect(wrapper.find(Input).hasClass('is-untouched')).to.be.false; 85 | expect(wrapper.find(Input).hasClass('is-touched')).to.be.true; 86 | }); 87 | 88 | it('should have "is-pristine" class when not dirty', () => { 89 | dirty = true; 90 | const wrapper = shallow(, options); 91 | 92 | expect(wrapper.find(Input).hasClass('is-pristine')).to.be.false; 93 | expect(wrapper.find(Input).hasClass('is-dirty')).to.be.true; 94 | }); 95 | 96 | it('should have "is-invalid" not "av-valid" class when invalid and touched', () => { 97 | error = true; 98 | touched = true; 99 | const wrapper = shallow(, options); 100 | 101 | expect(wrapper.find(Input).hasClass('av-valid')).to.be.false; 102 | expect(wrapper.find(Input).hasClass('is-invalid')).to.be.true; 103 | }); 104 | 105 | it('should toString the value to add it to the DOM via Input', () => { 106 | const wrapper = shallow(, options); 107 | expect(wrapper.find(Input).prop('value')).to.eql('yes'); 108 | }); 109 | 110 | describe('on change handler', () => { 111 | beforeEach(() => { 112 | touched = false; 113 | dirty = false; 114 | bad = false; 115 | error = false; 116 | inputState = 'danger'; 117 | props = { 118 | name: 'fieldName', 119 | value: 'testValue', 120 | }; 121 | options = { 122 | context: { 123 | Group: { 124 | getProps: () => ({ 125 | name: 'test', 126 | }), 127 | update: sinon.spy(), 128 | }, 129 | FormCtrl: { 130 | inputs: {}, 131 | getDefaultValue: sinon.spy(), 132 | getInputState: sinon.stub().returns(inputState), 133 | hasError: () => error, 134 | isDirty: () => dirty, 135 | isTouched: () => touched, 136 | isBad: () => bad, 137 | setDirty: sinon.spy(), 138 | setTouched: sinon.spy(), 139 | setBad: sinon.spy(), 140 | register: sinon.spy(), 141 | unregister: sinon.spy(), 142 | validate: sinon.spy(), 143 | getValidationEvent: () => 'formCtrlValidationEvent', 144 | validation: {}, 145 | parent: null, 146 | }, 147 | }, 148 | }; 149 | 150 | component = new AvCheckbox(props); 151 | component.context = options.context; 152 | }); 153 | 154 | it('should update group value on change', () => { 155 | const event = {}; 156 | component.onChangeHandler(event); 157 | expect(options.context.Group.update).to.have.been.calledWith(event, props.value); 158 | }); 159 | 160 | it('should run props on change if it\'s there', () => { 161 | props.onChange = sinon.spy(); 162 | component.onChangeHandler(); 163 | expect(props.onChange).to.have.been.called; 164 | }); 165 | }); 166 | 167 | }); 168 | -------------------------------------------------------------------------------- /__test__/AvCheckboxGroup.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import { AvCheckboxGroup, AvFeedback } from 'availity-reactstrap-validation'; 4 | 5 | let options; 6 | 7 | describe('AvCheckboxGroup', () => { 8 | let touched; 9 | let dirty; 10 | let bad; 11 | let error; 12 | 13 | beforeEach(() => { 14 | touched = false; 15 | dirty = false; 16 | bad = false; 17 | error = false; 18 | options = { 19 | context: { 20 | FormCtrl: { 21 | inputs: {}, 22 | getDefaultValue: ()=> {}, 23 | getInputState: ()=> ({}), 24 | hasError: () => error, 25 | isDirty: () => dirty, 26 | isTouched: () => touched, 27 | isBad: () => bad, 28 | isDisabled: () => false, 29 | isReadOnly: () => false, 30 | setDirty: sinon.spy(), 31 | setTouched: sinon.spy(), 32 | setBad: sinon.spy(), 33 | register: sinon.spy(), 34 | unregister: sinon.spy(), 35 | validate: sinon.spy(), 36 | getValidationEvent: ()=> {}, 37 | validation: {}, 38 | parent: null, 39 | }, 40 | }, 41 | }; 42 | }); 43 | 44 | it('should render a reactstrap Input', () => { 45 | const wrapper = shallow(, options); 46 | 47 | expect(wrapper.type()).to.not.eql(undefined); 48 | }); 49 | 50 | it('should register a validation', () => { 51 | const wrapper = shallow(, options); 52 | const instance = wrapper.instance(); 53 | expect(instance.validations.required.value).to.be.true; 54 | }); 55 | 56 | it('should register then remove a disabled validation', () => { 57 | const wrapper = shallow(, options); 58 | const instance = wrapper.instance(); 59 | expect(instance.validations.required.value).to.be.true; 60 | wrapper.setProps({required: false}); 61 | expect(instance.validations.required).to.be.undefined; 62 | }); 63 | 64 | it('should return the set value', ()=> { 65 | const wrapper = shallow(, options); 66 | const component = wrapper.instance(); 67 | component.value = 'boop'; 68 | expect(component.getValue()).to.equal('boop'); 69 | }); 70 | 71 | it('should unregister when unmounted', ()=> { 72 | const wrapper = shallow(, options); 73 | wrapper.unmount(); 74 | expect(options.context.FormCtrl.unregister).to.have.been.called; 75 | }); 76 | 77 | it('should give default value from value prop', () => { 78 | const wrapper = shallow(, options); 79 | const component = wrapper.instance(); 80 | expect(component.value).to.eql('momo;jojo;bobo'); 81 | }); 82 | 83 | it('should give default value from defaultValue prop when there is no value prop', () => { 84 | const wrapper = shallow(, options); 85 | const component = wrapper.instance(); 86 | expect(component.value).to.eql('momo'); 87 | }); 88 | 89 | it('should update the value when the value prop changes', () => { 90 | const wrapper = shallow(, options); 91 | const component = wrapper.instance(); 92 | expect(component.getValue()).to.equal('momo'); 93 | wrapper.setProps({value: 'yoyo'}); 94 | expect(component.getValue()).to.equal('yoyo'); 95 | }); 96 | 97 | it('should update the validations when the props change', () => { 98 | const wrapper = shallow(, options); 99 | const component = wrapper.instance(); 100 | const spy = sinon.spy(component, 'updateValidations'); 101 | wrapper.setProps({required: true}); 102 | expect(spy).to.have.been.called; 103 | }); 104 | 105 | it('should not update the validations when the props did not change', () => { 106 | const wrapper = shallow(, options); 107 | const component = wrapper.instance(); 108 | const spy = sinon.spy(component, 'updateValidations'); 109 | wrapper.setProps({defaultValue: 'momo'}); 110 | expect(spy).to.not.have.been.called; 111 | }); 112 | 113 | it('should give default value from context', () => { 114 | const wrapper = shallow(, options); 115 | const component = wrapper.instance(); 116 | component.context.FormCtrl.getDefaultValue = () => { 117 | return 'jiri'; 118 | }; 119 | expect(component.getDefaultValue()).to.eql({key: 'defaultValue', value: 'jiri'}); 120 | }); 121 | 122 | it('should give default fallback when no one set up their stuff', () => { 123 | const wrapper = shallow(, options); 124 | const component = wrapper.instance(); 125 | expect(component.getDefaultValue()).to.eql({key: 'defaultValue', value: []}); 126 | }); 127 | 128 | it('should reset properly', () => { 129 | const wrapper = shallow(, options); 130 | const component = wrapper.instance(); 131 | component.setState = sinon.spy(); 132 | component.reset(); 133 | expect(component.value).to.equal('momo'); 134 | expect(component.setState).to.have.been.calledWith({value: 'momo'}); 135 | expect(options.context.FormCtrl.setDirty).to.have.been.calledWith('test', false); 136 | expect(options.context.FormCtrl.setTouched).to.have.been.calledWith('test', false); 137 | expect(options.context.FormCtrl.setBad).to.have.been.calledWith('test', false); 138 | expect(options.context.FormCtrl.validate).to.have.been.calledWith('test'); 139 | }); 140 | 141 | it('should reset properly and call props reset', () => { 142 | const spy = sinon.spy(); 143 | const wrapper = shallow(, options); 144 | const component = wrapper.instance(); 145 | component.reset(); 146 | expect(spy).to.have.been.calledWith('momo'); 147 | }); 148 | 149 | it('should disconnect child context from form registration and validation', () => { 150 | const wrapper = shallow(, options); 151 | const component = wrapper.instance(); 152 | options.context.FormCtrl.register.reset(); 153 | options.context.FormCtrl.validate.reset(); 154 | component.getChildContext().FormCtrl.register('charmander'); 155 | component.getChildContext().FormCtrl.validate('squirtle'); 156 | expect(options.context.FormCtrl.register).to.not.have.been.called; 157 | expect(options.context.FormCtrl.validate).to.not.have.been.called; 158 | }); 159 | 160 | it('should update the group via child context', () => { 161 | const wrapper = shallow(, options); 162 | const component = wrapper.instance(); 163 | component.setState = sinon.spy(); 164 | component.getChildContext().Group.update({ target: { checked: true } }, 'momo'); 165 | expect(component.value).to.deep.equal(['momo']); 166 | expect(component.setState).to.have.been.calledWith({value: ['momo']}); 167 | expect(options.context.FormCtrl.validate).to.have.been.called; 168 | }); 169 | 170 | it('should trigger the change callback when the value is updated', () => { 171 | const spy = sinon.spy(); 172 | const wrapper = shallow(, options); 173 | const component = wrapper.instance(); 174 | const event = {}; 175 | component.getChildContext().Group.update(event, 'momo').then(() => { 176 | expect(spy).to.have.been.calledWith(event, 'momo'); 177 | }); 178 | }); 179 | 180 | it('should render validation message when sent', () => { 181 | options.context.FormCtrl.getInputState = () => { 182 | return {'errorMessage': 'WHAT ARE YOU DOING?!'}; 183 | }; 184 | const wrapper = shallow(, options); 185 | expect(wrapper.find(AvFeedback).prop('children')).to.equal('WHAT ARE YOU DOING?!'); 186 | }); 187 | 188 | it('should show a legend if we defined a label', () => { 189 | const wrapper = shallow(, options); 190 | expect(wrapper.contains(test)).to.be.true; 191 | }); 192 | }); 193 | -------------------------------------------------------------------------------- /__test__/AvFeedback.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import { AvFeedback } from 'availity-reactstrap-validation'; 4 | import { FormFeedback } from 'reactstrap'; 5 | 6 | const state = {}; 7 | const options = { 8 | context: { 9 | FormCtrl: {}, 10 | Group: { 11 | getInputState: () => state, 12 | }, 13 | }, 14 | }; 15 | 16 | describe('AvFeedback', () => { 17 | describe('when there is an error', () => { 18 | beforeEach(() => { 19 | state.color = 'danger'; 20 | }); 21 | 22 | it('should render with "FormFeedback"', () => { 23 | const wrapper = shallow(Yo!, options); 24 | 25 | expect(wrapper.type()).to.equal(FormFeedback); 26 | }); 27 | 28 | it('should render children inside the FormFeedback', () => { 29 | const wrapper = shallow(Yo!, options); 30 | 31 | expect(wrapper.prop('children')).to.equal('Yo!'); 32 | }); 33 | 34 | it('should render with the props passed in', () => { 35 | const wrapper = shallow( 36 | Yo!, 37 | options 38 | ); 39 | 40 | expect(wrapper.prop('style').textAlign).to.equal('center'); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /__test__/AvGroup.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount } from 'enzyme'; 3 | import { AvGroup } from 'availity-reactstrap-validation'; 4 | import { FormGroup } from 'reactstrap'; 5 | 6 | describe('AvGroup', function() { 7 | beforeEach(() => { 8 | this.inputState = {color:'danger'}; 9 | this.props = { 10 | name: 'fieldName', 11 | }; 12 | this.registerSpy = sinon.spy(); 13 | this.context = { 14 | FormCtrl: { 15 | getInputState: sinon.stub().returns(this.inputState), 16 | register: this.registerSpy, 17 | }, 18 | }; 19 | this.options = {context: this.context}; 20 | }); 21 | 22 | it('should render with "FormGroup"', () => { 23 | const wrapper = shallow(Yo!, this.options); 24 | 25 | expect(wrapper.type()).to.equal(FormGroup); 26 | }); 27 | 28 | it('should render color prop based on inputState', () => { 29 | const wrapper = shallow(Yo!, this.options); 30 | 31 | expect(wrapper.prop('className')).to.equal(`text-${this.inputState.color}`); 32 | }); 33 | 34 | it('should render children inside the FormGroup', () => { 35 | const wrapper = shallow(Yo!, this.options); 36 | 37 | expect(wrapper.prop('children')).to.equal('Yo!'); 38 | }); 39 | 40 | it('should render with the props passed in', () => { 41 | const wrapper = shallow(Yo!, this.options); 42 | 43 | expect(wrapper.prop('style').textAlign).to.equal('center'); 44 | }); 45 | 46 | it('should intercept an input registration', () => { 47 | const wrapper = mount(Yo!, this.options); 48 | expect(wrapper.node.FormCtrl.register).to.not.equal(this.registerSpy); 49 | const input = {props: this.props}; 50 | wrapper.node.FormCtrl.register(input); 51 | expect(wrapper.state('input')).to.equal(input); 52 | expect(this.registerSpy).to.have.been.calledWith(input); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /__test__/AvInput.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import { AvInput } from 'availity-reactstrap-validation'; 4 | import { Input } from 'reactstrap'; 5 | 6 | let options; 7 | 8 | describe('AvInput', () => { 9 | let touched; 10 | let dirty; 11 | let bad; 12 | let error; 13 | 14 | beforeEach(() => { 15 | touched = false; 16 | dirty = false; 17 | bad = false; 18 | error = false; 19 | options = { 20 | context: { 21 | FormCtrl: { 22 | inputs: {}, 23 | getDefaultValue: ()=> {}, 24 | getInputState: ()=> {}, 25 | hasError: () => error, 26 | isDirty: () => dirty, 27 | isTouched: () => touched, 28 | isBad: () => bad, 29 | isDisabled: () => false, 30 | isReadOnly: () => false, 31 | setDirty: ()=> {}, 32 | setTouched: ()=> {}, 33 | setBad: ()=> {}, 34 | register: ()=> {}, 35 | unregister: ()=> {}, 36 | validate: ()=> {}, 37 | validationEvent: ()=> {}, 38 | parent: null, 39 | }, 40 | }, 41 | }; 42 | }); 43 | 44 | it('should render a reactstrap Input', () => { 45 | const wrapper = shallow(, options); 46 | 47 | expect(wrapper.type()).to.equal(Input); 48 | }); 49 | 50 | it('should have "is-untouched" class when untouched', () => { 51 | const wrapper = shallow(, options); 52 | expect(wrapper.hasClass('is-untouched')).to.be.true; 53 | expect(wrapper.hasClass('is-touched')).to.be.false; 54 | }); 55 | 56 | it('should have "is-pristine" class when not dirty', () => { 57 | const wrapper = shallow(, options); 58 | 59 | expect(wrapper.hasClass('is-pristine')).to.be.true; 60 | expect(wrapper.hasClass('is-dirty')).to.be.false; 61 | }); 62 | 63 | it('should have "av-valid" not "is-invalid" class when valid', () => { 64 | const wrapper = shallow(, options); 65 | 66 | expect(wrapper.hasClass('av-valid')).to.be.true; 67 | expect(wrapper.hasClass('is-invalid')).to.be.false; 68 | }); 69 | 70 | it('should not have "is-bad-input" class when the input is not "bad"', () => { 71 | const wrapper = shallow(, options); 72 | 73 | expect(wrapper.hasClass('is-bad-input')).to.be.false; 74 | }); 75 | 76 | it('should have "is-touched" class when touched', () => { 77 | touched = true; 78 | const wrapper = shallow(, options); 79 | 80 | expect(wrapper.hasClass('is-untouched')).to.be.false; 81 | expect(wrapper.hasClass('is-touched')).to.be.true; 82 | }); 83 | 84 | it('should have "is-pristine" class when not dirty', () => { 85 | dirty = true; 86 | const wrapper = shallow(, options); 87 | 88 | expect(wrapper.hasClass('is-pristine')).to.be.false; 89 | expect(wrapper.hasClass('is-dirty')).to.be.true; 90 | }); 91 | 92 | it('should have "is-invalid" not "av-valid" class when invalid and touched', () => { 93 | error = true; 94 | touched = true; 95 | const wrapper = shallow(, options); 96 | 97 | expect(wrapper.hasClass('av-valid')).to.be.false; 98 | expect(wrapper.hasClass('is-invalid')).to.be.true; 99 | }); 100 | 101 | it('should not have "is-bad-input" class when the input is not "bad"', () => { 102 | bad = true; 103 | const wrapper = shallow(, options); 104 | 105 | expect(wrapper.hasClass('is-bad-input')).to.be.true; 106 | }); 107 | 108 | it('should allow custom classes', () => { 109 | const wrapper = shallow(, options); 110 | 111 | expect(wrapper.hasClass('yo-yo')).to.be.true; 112 | }); 113 | 114 | it('should pass props through to reactstrap\'s Input', () => { 115 | const wrapper = shallow(, options); 116 | 117 | expect(wrapper.prop('type')).to.equal('number'); 118 | }); 119 | }); 120 | -------------------------------------------------------------------------------- /__test__/AvInputContainer.spec.js: -------------------------------------------------------------------------------- 1 | import { AvInputContainer } from 'availity-reactstrap-validation'; 2 | 3 | describe('BaseInput', function() { 4 | beforeEach(() => { 5 | this.inputs = {}; 6 | this.updaters = {}; 7 | this.component = new AvInputContainer(); 8 | this.component._inputs = this.inputs; 9 | this.component._updaters = this.inputs; 10 | }); 11 | 12 | describe('component will mount', () => { 13 | it('should get the default value', () => { 14 | this.component.componentWillMount(); 15 | expect(this.component._inputs).to.eql({}); 16 | }); 17 | }); 18 | 19 | describe('register input', () => { 20 | it('should throw if the input does not have name', () => { 21 | expect( 22 | this.component.registerInput.bind(this.component, { 23 | props: { type: 'text' }, 24 | }) 25 | ).to.throw('no "name" prop'); 26 | }); 27 | 28 | it('should throw if the input does not have props', () => { 29 | expect(this.component.registerInput.bind(this.component, {})).to.throw( 30 | 'no "name" prop' 31 | ); 32 | }); 33 | 34 | it('should throw if the input is undefined', () => { 35 | expect(this.component.registerInput.bind(this.component)).to.throw( 36 | 'no "name" prop' 37 | ); 38 | }); 39 | 40 | describe('other input types', () => { 41 | it('should add the input to the inputs object', () => { 42 | const input = { props: { name: 'name', type: 'text' } }; 43 | this.component.registerInput(input); 44 | expect(this.inputs[input.props.name]).to.equal(input); 45 | }); 46 | }); 47 | }); 48 | 49 | describe('unregister input', () => { 50 | it('should throw if the input does not have name', () => { 51 | expect( 52 | this.component.unregisterInput.bind(this.component, { 53 | props: { type: 'text' }, 54 | }) 55 | ).to.throw('no "name" prop'); 56 | }); 57 | 58 | describe('other input types', () => { 59 | it('should remove the input to the inputs object', () => { 60 | const input = { props: { name: 'name', type: 'text' } }; 61 | this.inputs[input.props.name] = input; 62 | this.component.unregisterInput(input); 63 | expect(this.inputs[input.props.name]).to.not.exist; 64 | }); 65 | 66 | it('should not care that the input is not registered', () => { 67 | const input = { props: { name: 'name', type: 'text' } }; 68 | delete this.inputs[input.props.name]; 69 | this.component.unregisterInput(input); 70 | expect(this.inputs[input.props.name]).to.not.exist; 71 | }); 72 | }); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /__test__/AvRadio.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import { AvRadio } from 'availity-reactstrap-validation'; 4 | import { Input, Label, FormGroup } from 'reactstrap'; 5 | 6 | let options; 7 | let props; 8 | let inputState; 9 | let component; 10 | 11 | describe('AvRadio', () => { 12 | let touched; 13 | let dirty; 14 | let bad; 15 | let error; 16 | 17 | beforeEach(() => { 18 | touched = false; 19 | dirty = false; 20 | bad = false; 21 | error = false; 22 | options = { 23 | context: { 24 | Group: { 25 | getProps: () => ({ 26 | name: 'test', 27 | }), 28 | }, 29 | FormCtrl: { 30 | inputs: {}, 31 | getDefaultValue: ()=> {}, 32 | getInputState: ()=> ({}), 33 | hasError: () => error, 34 | isDirty: () => dirty, 35 | isTouched: () => touched, 36 | isBad: () => bad, 37 | isDisabled: () => false, 38 | isReadOnly: () => false, 39 | setDirty: ()=> {}, 40 | setTouched: ()=> {}, 41 | setBad: ()=> {}, 42 | register: ()=> {}, 43 | unregister: ()=> {}, 44 | validate: ()=> {}, 45 | getValidationEvent: ()=> {}, 46 | validation: {}, 47 | parent: null, 48 | }, 49 | }, 50 | }; 51 | }); 52 | 53 | it('should render a reactstrap Input', () => { 54 | const wrapper = shallow(, options); 55 | 56 | expect(wrapper.type()).to.not.be.undefined; 57 | }); 58 | 59 | it('should have "is-untouched" class when untouched', () => { 60 | const wrapper = shallow(, options); 61 | 62 | expect(wrapper.find(Input).hasClass('is-untouched')).to.be.true; 63 | expect(wrapper.find(Input).hasClass('is-touched')).to.be.false; 64 | }); 65 | 66 | it('should have "is-pristine" class when not dirty', () => { 67 | const wrapper = shallow(, options); 68 | 69 | expect(wrapper.find(Input).hasClass('is-pristine')).to.be.true; 70 | expect(wrapper.find(Input).hasClass('is-dirty')).to.be.false; 71 | }); 72 | 73 | it('should have "av-valid" not "is-invalid" class when valid', () => { 74 | const wrapper = shallow(, options); 75 | 76 | expect(wrapper.find(Input).hasClass('av-valid')).to.be.true; 77 | expect(wrapper.find(Input).hasClass('is-invalid')).to.be.false; 78 | }); 79 | 80 | it('should have "is-touched" class when touched', () => { 81 | touched = true; 82 | const wrapper = shallow(, options); 83 | 84 | expect(wrapper.find(Input).hasClass('is-untouched')).to.be.false; 85 | expect(wrapper.find(Input).hasClass('is-touched')).to.be.true; 86 | }); 87 | 88 | it('should have "is-pristine" class when not dirty', () => { 89 | dirty = true; 90 | const wrapper = shallow(, options); 91 | 92 | expect(wrapper.find(Input).hasClass('is-pristine')).to.be.false; 93 | expect(wrapper.find(Input).hasClass('is-dirty')).to.be.true; 94 | }); 95 | 96 | it('should have "is-invalid" not "av-valid" class when invalid and touched', () => { 97 | error = true; 98 | touched = true; 99 | const wrapper = shallow(, options); 100 | 101 | expect(wrapper.find(Input).hasClass('av-valid')).to.be.false; 102 | expect(wrapper.find(Input).hasClass('is-invalid')).to.be.true; 103 | }); 104 | 105 | it('should toString the value to add it to the DOM via Input', () => { 106 | const wrapper = shallow(, options); 107 | expect(wrapper.find(Input).prop('value')).to.eql('yes'); 108 | }); 109 | 110 | describe('on change handler', () => { 111 | beforeEach(() => { 112 | touched = false; 113 | dirty = false; 114 | bad = false; 115 | error = false; 116 | inputState = 'danger'; 117 | props = { 118 | name: 'fieldName', 119 | value: 'testValue', 120 | }; 121 | options = { 122 | context: { 123 | Group: { 124 | getProps: () => ({ 125 | name: 'test', 126 | }), 127 | update: sinon.spy(), 128 | }, 129 | FormCtrl: { 130 | inputs: {}, 131 | getDefaultValue: sinon.spy(), 132 | getInputState: sinon.stub().returns(inputState), 133 | hasError: () => error, 134 | isDirty: () => dirty, 135 | isTouched: () => touched, 136 | isBad: () => bad, 137 | setDirty: sinon.spy(), 138 | setTouched: sinon.spy(), 139 | setBad: sinon.spy(), 140 | register: sinon.spy(), 141 | unregister: sinon.spy(), 142 | validate: sinon.spy(), 143 | getValidationEvent: () => 'formCtrlValidationEvent', 144 | validation: {}, 145 | parent: null, 146 | }, 147 | }, 148 | }; 149 | 150 | component = new AvRadio(props); 151 | component.context = options.context; 152 | }); 153 | 154 | it('should update group value on change', () => { 155 | const event = {}; 156 | component.onChangeHandler(event); 157 | expect(options.context.Group.update).to.have.been.calledWith(event, props.value); 158 | }); 159 | 160 | it('should run props on change if it\'s there', () => { 161 | props.onChange = sinon.spy(); 162 | component.onChangeHandler(); 163 | expect(props.onChange).to.have.been.called; 164 | }); 165 | }); 166 | 167 | }); 168 | -------------------------------------------------------------------------------- /__test__/AvRadioGroup.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import { AvRadioGroup, AvFeedback } from 'availity-reactstrap-validation'; 4 | import { FormGroup } from 'reactstrap'; 5 | 6 | let options; 7 | 8 | describe('AvRadioGroup', () => { 9 | let touched; 10 | let dirty; 11 | let bad; 12 | let error; 13 | 14 | beforeEach(() => { 15 | touched = false; 16 | dirty = false; 17 | bad = false; 18 | error = false; 19 | options = { 20 | context: { 21 | FormCtrl: { 22 | inputs: {}, 23 | getDefaultValue: ()=> {}, 24 | getInputState: ()=> ({}), 25 | hasError: () => error, 26 | isDirty: () => dirty, 27 | isTouched: () => touched, 28 | isBad: () => bad, 29 | isDisabled: () => false, 30 | isReadOnly: () => false, 31 | setDirty: sinon.spy(), 32 | setTouched: sinon.spy(), 33 | setBad: sinon.spy(), 34 | register: sinon.spy(), 35 | unregister: sinon.spy(), 36 | validate: sinon.spy(), 37 | getValidationEvent: ()=> {}, 38 | validation: {}, 39 | parent: null, 40 | }, 41 | }, 42 | }; 43 | }); 44 | 45 | it('should render a reactstrap Input', () => { 46 | const wrapper = shallow(, options); 47 | 48 | expect(wrapper.type()).to.not.eql(undefined); 49 | }); 50 | 51 | it('should register a validation', () => { 52 | const wrapper = shallow(, options); 53 | const instance = wrapper.instance(); 54 | expect(instance.validations.required.value).to.be.true; 55 | }); 56 | 57 | it('should register then remove a disabled validation', () => { 58 | const wrapper = shallow(, options); 59 | const instance = wrapper.instance(); 60 | expect(instance.validations.required.value).to.be.true; 61 | wrapper.setProps({required: false}); 62 | expect(instance.validations.required).to.be.undefined; 63 | }); 64 | 65 | it('should return the set value', ()=> { 66 | const wrapper = shallow(, options); 67 | const component = wrapper.instance(); 68 | component.value = 'boop'; 69 | expect(component.getValue()).to.equal('boop'); 70 | }); 71 | 72 | it('should unregister when unmounted', ()=> { 73 | const wrapper = shallow(, options); 74 | wrapper.unmount(); 75 | expect(options.context.FormCtrl.unregister).to.have.been.called; 76 | }); 77 | 78 | it('should give default value from value prop', () => { 79 | const wrapper = shallow(, options); 80 | const component = wrapper.instance(); 81 | expect(component.value).to.eql('momo'); 82 | }); 83 | 84 | it('should give default value from defaultValue prop when there is no value prop', () => { 85 | const wrapper = shallow(, options); 86 | const component = wrapper.instance(); 87 | expect(component.value).to.eql('momo'); 88 | }); 89 | 90 | it('should update the value when the value prop changes', () => { 91 | const wrapper = shallow(, options); 92 | const component = wrapper.instance(); 93 | expect(component.getValue()).to.equal('momo'); 94 | wrapper.setProps({value: 'yoyo'}); 95 | expect(component.getValue()).to.equal('yoyo'); 96 | }); 97 | 98 | it('should update the validations when the props change', () => { 99 | const wrapper = shallow(, options); 100 | const component = wrapper.instance(); 101 | const spy = sinon.spy(component, 'updateValidations'); 102 | wrapper.setProps({required: true}); 103 | expect(spy).to.have.been.called; 104 | }); 105 | 106 | it('should not update the validations when the props did not change', () => { 107 | const wrapper = shallow(, options); 108 | const component = wrapper.instance(); 109 | const spy = sinon.spy(component, 'updateValidations'); 110 | wrapper.setProps({defaultValue: 'momo'}); 111 | expect(spy).to.not.have.been.called; 112 | }); 113 | 114 | it('should give default value from context', () => { 115 | const wrapper = shallow(, options); 116 | const component = wrapper.instance(); 117 | component.context.FormCtrl.getDefaultValue = () => { 118 | return 'jiri'; 119 | }; 120 | expect(component.getDefaultValue()).to.eql({key: 'defaultValue', value: 'jiri'}); 121 | }); 122 | 123 | it('should give default fallback when no one set up their stuff', () => { 124 | const wrapper = shallow(, options); 125 | const component = wrapper.instance(); 126 | expect(component.getDefaultValue()).to.eql({key: 'defaultValue', value: ''}); 127 | }); 128 | 129 | it('should reset properly', () => { 130 | const wrapper = shallow(, options); 131 | const component = wrapper.instance(); 132 | component.setState = sinon.spy(); 133 | component.reset(); 134 | expect(component.value).to.equal('momo'); 135 | expect(component.setState).to.have.been.calledWith({value: 'momo'}); 136 | expect(options.context.FormCtrl.setDirty).to.have.been.calledWith('test', false); 137 | expect(options.context.FormCtrl.setTouched).to.have.been.calledWith('test', false); 138 | expect(options.context.FormCtrl.setBad).to.have.been.calledWith('test', false); 139 | expect(options.context.FormCtrl.validate).to.have.been.calledWith('test'); 140 | }); 141 | 142 | it('should reset properly and call props reset', () => { 143 | const spy = sinon.spy(); 144 | const wrapper = shallow(, options); 145 | const component = wrapper.instance(); 146 | component.reset(); 147 | expect(spy).to.have.been.calledWith('momo'); 148 | }); 149 | 150 | it('should disconnect child context from form registration and validation', () => { 151 | const wrapper = shallow(, options); 152 | const component = wrapper.instance(); 153 | options.context.FormCtrl.register.reset(); 154 | options.context.FormCtrl.validate.reset(); 155 | component.getChildContext().FormCtrl.register('charmander'); 156 | component.getChildContext().FormCtrl.validate('squirtle'); 157 | expect(options.context.FormCtrl.register).to.not.have.been.called; 158 | expect(options.context.FormCtrl.validate).to.not.have.been.called; 159 | }); 160 | 161 | it('should update the group via child context', () => { 162 | const wrapper = shallow(, options); 163 | const component = wrapper.instance(); 164 | component.setState = sinon.spy(); 165 | component.getChildContext().Group.update({}, 'momo'); 166 | expect(component.value).to.equal('momo'); 167 | expect(component.setState).to.have.been.calledWith({value: 'momo'}); 168 | expect(options.context.FormCtrl.validate).to.have.been.called; 169 | }); 170 | 171 | it('should trigger the change callback when the value is updated', () => { 172 | const spy = sinon.spy(); 173 | const wrapper = shallow(, options); 174 | const component = wrapper.instance(); 175 | const event = {}; 176 | component.getChildContext().Group.update(event, 'momo').then(() => { 177 | expect(spy).to.have.been.calledWith(event, 'momo'); 178 | }); 179 | }); 180 | 181 | it('should render validation message when sent', () => { 182 | options.context.FormCtrl.getInputState = () => { 183 | return {'errorMessage': 'WHAT ARE YOU DOING?!'}; 184 | }; 185 | const wrapper = shallow(, options); 186 | expect(wrapper.find(AvFeedback).prop('children')).to.equal('WHAT ARE YOU DOING?!'); 187 | }); 188 | 189 | it('should show a legend if we defined a label', () => { 190 | const wrapper = shallow(, options); 191 | expect(wrapper.contains(test)).to.be.true; 192 | }); 193 | }); 194 | -------------------------------------------------------------------------------- /__test__/AvValidator.date.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | import {inputTypeOverride} from 'availity-reactstrap-validation/AvValidator/utils'; 3 | 4 | const fn = AvValidator.date; 5 | const input = {props: {type: 'text'}}; 6 | const context = {}; 7 | 8 | describe('Date Validation', () => { 9 | it('should not require a value', () => { 10 | expect(fn('', context, undefined, input)).to.be.true; 11 | }); 12 | 13 | describe('error message', () => { 14 | it('should allow the error message to be overridden', () => { 15 | expect(fn('abc 123', context, {errorMessage: 'Custom'}, input)).to.equal('Custom'); 16 | }); 17 | 18 | it('should use the custom format in the default message', () => { 19 | expect(fn('abc 123', context, {format: 'YYYY-MM-DD'}, input)).to.equal('Format needs to be YYYY-MM-DD'); 20 | }); 21 | 22 | it('should use the default format in the default message', () => { 23 | expect(fn('abc 123', context, undefined, input)).to.equal('Format needs to be MM/DD/YYYY'); 24 | }); 25 | 26 | }); 27 | 28 | describe('non-date input type', () => { 29 | beforeEach(() => { 30 | input.props.type = 'text'; 31 | }); 32 | 33 | it('should accept MM/DD/YYYY format by default', () => { 34 | expect(fn('10/12/2014', context, undefined, input)).to.be.true; 35 | }); 36 | 37 | it('should accept ISO (YYYY-MM-DD) format by default', () => { 38 | expect(fn('2014-10-12', context, undefined, input)).to.be.true; 39 | }); 40 | 41 | it('should allow format to be customized', () => { 42 | expect(fn('2014-12-14', context, {format: 'YYYY-MM-DD'}, input)).to.be.true; 43 | }); 44 | 45 | it('should ensure the format matches the customized format', () => { 46 | expect(fn('10/12/2014', context, {format: 'YYYY-MM-DD'}, input)).to.equal('Format needs to be YYYY-MM-DD'); 47 | }); 48 | }); 49 | 50 | describe('date input type', () => { 51 | describe('without browser date input type support', () => { 52 | beforeEach(() => { 53 | inputTypeOverride('date', false); 54 | input.props.type = 'date'; 55 | }); 56 | 57 | it('should accept MM/DD/YYYY format by default', () => { 58 | expect(fn('10/12/2014', context, undefined, input)).to.be.true; 59 | }); 60 | 61 | it('should accept ISO (YYYY-MM-DD) format by default', () => { 62 | expect(fn('2014-10-12', context, undefined, input)).to.be.true; 63 | }); 64 | 65 | it('should allow format to be customized', () => { 66 | expect(fn('2014-12-14', context, {format: 'YYYY-MM-DD'}, input)).to.be.true; 67 | }); 68 | 69 | it('should ensure the format matches the customized format', () => { 70 | expect(fn('10/12/2014', context, {format: 'YYYY-MM-DD'}, input)).to.equal('Format needs to be YYYY-MM-DD'); 71 | }); 72 | }); 73 | 74 | describe('with browser date input type support', () => { 75 | beforeEach(() => { 76 | inputTypeOverride('date', true); 77 | input.props.type = 'date'; 78 | }); 79 | 80 | it('should accept ISO (YYYY-MM-DD) format by default', () => { 81 | expect(fn('2014-10-12', context, undefined, input)).to.be.true; 82 | }); 83 | 84 | it('should accept MM/DD/YYYY format by default', () => { 85 | expect(fn('10/12/2014', context, undefined, input)).to.be.true; 86 | }); 87 | 88 | it('should allow format to be customized', () => { 89 | expect(fn('10-12-2014', context, {format: 'DD-MM-YYYY'}, input)).to.be.true; 90 | }); 91 | }); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /__test__/AvValidator.dateRange.spec.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | import {AvValidator} from 'availity-reactstrap-validation'; 3 | import {inputTypeOverride} from 'availity-reactstrap-validation/AvValidator/utils'; 4 | 5 | const fn = AvValidator.dateRange; 6 | const input = {props: {type: 'text'}}; 7 | const context = {}; 8 | let date0; 9 | let date1; 10 | let date2; 11 | 12 | describe('Date Range Validation', () => { 13 | beforeEach(() => { 14 | date0 = moment(new Date()); 15 | date1 = moment(new Date()); 16 | date2 = moment(new Date()); 17 | }); 18 | 19 | it('should not require a value', () => { 20 | expect(fn('', context, undefined, input)).to.be.true; 21 | }); 22 | 23 | describe('error message', () => { 24 | it('should allow the error message to be overridden', () => { 25 | expect(fn('abc 123', context, {errorMessage: 'Custom'}, input)).to.equal('Custom'); 26 | }); 27 | 28 | it('should use the custom format in the default message', () => { 29 | expect(fn('abc 123', context, { 30 | format: 'YYYY-MM-DD', 31 | displayFormat: 'YYYY-MM-DD', 32 | start: {value: '2014-10-12'}, 33 | end: {value: '2015-10-12'} 34 | }, input)).to.equal('Date must be between 2014-10-12 and 2015-10-12'); 35 | }); 36 | 37 | it('should use the default format in the default message', () => { 38 | expect(fn('abc 123', context, { 39 | format: 'YYYY-MM-DD', 40 | start: {value: '2014-10-12'}, 41 | end: {value: '2015-10-12'} 42 | }, input)).to.equal('Date must be between 10/12/2014 and 10/12/2015'); 43 | }); 44 | 45 | }); 46 | 47 | describe('with units', () => { 48 | it('should return true when date is within range of the current date', () => { 49 | expect(fn(date0.format('YYYY-MM-DD'), context, { 50 | format: 'YYYY-MM-DD', 51 | start: {value: -1, units: 'day'}, 52 | end: {value: 1, units: 'day'} 53 | }, input)).to.be.true; 54 | }); 55 | 56 | it('should return true when date is the same as the start date', () => { 57 | expect(fn(date0.format('YYYY-MM-DD'), context, { 58 | format: 'YYYY-MM-DD', 59 | start: {value: 0, units: 'day'}, 60 | end: {value: 1, units: 'day'} 61 | }, input)).to.be.true; 62 | }); 63 | 64 | it('should return true when date is the same as the end date', () => { 65 | expect(fn(date0.format('YYYY-MM-DD'), context, { 66 | format: 'YYYY-MM-DD', 67 | start: {value: -1, units: 'day'}, 68 | end: {value: 0, units: 'day'} 69 | }, input)).to.be.true; 70 | }); 71 | 72 | it('should return an error message when date is not within range of the current date', () => { 73 | expect(fn(date0.format('YYYY-MM-DD'), context, { 74 | format: 'YYYY-MM-DD', 75 | start: {value: -5, units: 'day'}, 76 | end: {value: -1, units: 'day'} 77 | }, input)).to.equal(`Date must be between ${date1.add(-5, 'day').format('MM/DD/YYYY')} and ${date2.add(-1, 'day').format('MM/DD/YYYY')}`); 78 | }); 79 | }); 80 | 81 | describe('without units', () => { 82 | it('should return true when date is within range of the current date', () => { 83 | expect(fn(date0.format('YYYY-MM-DD'), context, { 84 | format: 'YYYY-MM-DD', 85 | start: {value: date1.add(-1, 'day').format('YYYY-MM-DD')}, 86 | end: {value: date2.add(1, 'day').format('YYYY-MM-DD')} 87 | }, input)).to.be.true; 88 | }); 89 | 90 | it('should return true when date is the same as the start date', () => { 91 | expect(fn(date0.format('YYYY-MM-DD'), context, { 92 | format: 'YYYY-MM-DD', 93 | start: {value: date1.format('YYYY-MM-DD')}, 94 | end: {value: date2.add(1, 'day').format('YYYY-MM-DD')} 95 | }, input)).to.be.true; 96 | }); 97 | 98 | it('should return true when date is the same as the end date', () => { 99 | expect(fn(date0.format('YYYY-MM-DD'), context, { 100 | format: 'YYYY-MM-DD', 101 | start: {value: date1.add(-1, 'day').format('YYYY-MM-DD')}, 102 | end: {value: date2.format('YYYY-MM-DD')} 103 | }, input)).to.be.true; 104 | }); 105 | 106 | it('should return an error message when date is not within range of the current date', () => { 107 | expect(fn(date0.format('YYYY-MM-DD'), context, { 108 | format: 'YYYY-MM-DD', 109 | start: {value: date1.add(-5, 'day').format('YYYY-MM-DD')}, 110 | end: {value: date2.add(-1, 'day').format('YYYY-MM-DD')} 111 | }, input)).to.equal(`Date must be between ${date1.format('MM/DD/YYYY')} and ${date2.format('MM/DD/YYYY')}`); 112 | }); 113 | 114 | it('should allow the start and end formats to be different than the user format', () => { 115 | expect(fn(date0.format('YYYY-MM-DD'), context, { 116 | format: 'YYYY-MM-DD', 117 | start: {value: date1.add(-5, 'day').format('DD-MM-YYYY'), format: 'DD-MM-YYYY'}, 118 | end: {value: date2.add(-1, 'day').format('YYYY/MM/DD'), format: 'YYYY/MM/DD'} 119 | }, input)).to.equal(`Date must be between ${date1.format('MM/DD/YYYY')} and ${date2.format('MM/DD/YYYY')}`); 120 | }); 121 | }); 122 | 123 | describe('non-date input type', () => { 124 | beforeEach(() => { 125 | input.props.type = 'text'; 126 | }); 127 | 128 | it('should accept MM/DD/YYYY by default', () => { 129 | expect(fn(date0.format('MM/DD/YYYY'), context, { 130 | start: {value: -1, units: 'day'}, 131 | end: {value: 1, units: 'day'} 132 | }, input)).to.be.true; 133 | }); 134 | 135 | it('should accept YYYY-MM-DD by default', () => { 136 | expect(fn(date0.format('YYYY-MM-DD'), context, { 137 | start: {value: -1, units: 'day'}, 138 | end: {value: 1, units: 'day'} 139 | }, input)).to.be.true; 140 | }); 141 | 142 | it('should allow the format to be overridden', () => { 143 | expect(fn(date0.format('DD-MM-YYYY'), context, { 144 | format: 'DD-MM-YYYY', 145 | start: {value: -1, units: 'day'}, 146 | end: {value: 1, units: 'day'} 147 | }, input)).to.be.true; 148 | }); 149 | }); 150 | 151 | describe('date input type', () => { 152 | describe('without browser date input type support', () => { 153 | beforeEach(() => { 154 | inputTypeOverride('date', false); 155 | input.props.type = 'date'; 156 | }); 157 | 158 | it('should accept MM/DD/YYYY by default', () => { 159 | expect(fn(date0.format('MM/DD/YYYY'), context, { 160 | start: {value: -1, units: 'day'}, 161 | end: {value: 1, units: 'day'} 162 | }, input)).to.be.true; 163 | }); 164 | 165 | it('should accept YYYY-MM-DD by default', () => { 166 | expect(fn(date0.format('YYYY-MM-DD'), context, { 167 | start: {value: -1, units: 'day'}, 168 | end: {value: 1, units: 'day'} 169 | }, input)).to.be.true; 170 | }); 171 | 172 | it('should allow the format to be overridden', () => { 173 | expect(fn(date0.format('DD-MM-YYYY'), context, { 174 | format: 'DD-MM-YYYY', 175 | start: {value: -1, units: 'day'}, 176 | end: {value: 1, units: 'day'} 177 | }, input)).to.be.true; 178 | }); 179 | }); 180 | 181 | describe('with browser date input type support', () => { 182 | beforeEach(() => { 183 | inputTypeOverride('date', true); 184 | input.props.type = 'date'; 185 | }); 186 | 187 | it('should accept YYYY-MM-DD by default', () => { 188 | expect(fn(date0.format('YYYY-MM-DD'), context, { 189 | start: {value: -1, units: 'day'}, 190 | end: {value: 1, units: 'day'} 191 | }, input)).to.be.true; 192 | }); 193 | 194 | it('should accept MM/DD/YYYY by default', () => { 195 | expect(fn(date0.format('MM/DD/YYYY'), context, { 196 | start: {value: -1, units: 'day'}, 197 | end: {value: 1, units: 'day'} 198 | }, input)).to.be.true; 199 | }); 200 | 201 | it('should allow the format to be overridden', () => { 202 | expect(fn(date0.format('DD-MM-YYYY'), context, { 203 | format: 'DD-MM-YYYY', 204 | start: {value: -1, units: 'day'}, 205 | end: {value: 1, units: 'day'} 206 | }, input)).to.be.true; 207 | }); 208 | }); 209 | }); 210 | }); 211 | -------------------------------------------------------------------------------- /__test__/AvValidator.email.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.email; 4 | 5 | describe('Email Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('should return true for a valid email', () => { 11 | expect(fn('evan.sharp@availity.com')).to.be.true; 12 | expect(fn('evan.sharp+more-things@availity.com')).to.be.true; 13 | expect(fn('evan.sharp@availity.com.co')).to.be.true; 14 | expect(fn('evan.sharp@development.availity.com')).to.be.true; 15 | expect(fn('Evan.Sharp@Availity.com')).to.be.true; 16 | }); 17 | 18 | it('should return false for an invalid email', () => { 19 | expect(fn('evan.sharp@availity')).to.be.false; 20 | expect(fn('evan.sharp@')).to.be.false; 21 | expect(fn('@availity.com')).to.be.false; 22 | expect(fn('evan.sharp@.com')).to.be.false; 23 | expect(fn('evan.sharp')).to.be.false; 24 | expect(fn('availity.com')).to.be.false; 25 | expect(fn('Evan@Sharp@Availity.com')).to.be.false; 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /__test__/AvValidator.match.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.match; 4 | const now = new Date(); 5 | const context = { 6 | field1: "", 7 | field2: "something", 8 | field3: now, 9 | field4: 4, 10 | field5: {value: "something"}, 11 | }; 12 | 13 | describe('Match Validation', () => { 14 | it('should not require a value', () => { 15 | expect(fn('')).to.be.true; 16 | }); 17 | 18 | it('should return false by default when fields do not match', () => { 19 | expect(fn('something', context, {value: 'field1'})).to.be.false; 20 | }); 21 | 22 | it('should return custom error message if provided when fields do not match', () => { 23 | expect(fn('something', context, {value: 'field1', errorMessage: 'No match!'})).to.equal('No match!'); 24 | }); 25 | 26 | it('should match a string to a string', () => { 27 | expect(fn(context.field2, context, {value: 'field2'})).to.be.true; 28 | }); 29 | 30 | it('should match an object to an object', () => { 31 | expect(fn(context.field3, context, {value: 'field3'})).to.be.true; 32 | }); 33 | 34 | it('should match a number to a number', () => { 35 | expect(fn(context.field4, context, {value: 'field4'})).to.be.true; 36 | }); 37 | 38 | it('should not match a string to a number', () => { 39 | expect(fn('4', context, {value: 'field4'})).to.be.false; 40 | }); 41 | 42 | it('should not match a string to an object', () => { 43 | expect(fn('something', context, {value: 'field5'})).to.be.false; 44 | }); 45 | 46 | it('should not match something to nothing', () => { 47 | expect(fn('something', context, {value: 'field1'})).to.be.false; 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /__test__/AvValidator.max.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.max; 4 | 5 | describe('Max Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('should accept input array as an alias for maxChecked', () => { 11 | expect(fn(undefined, undefined, {value: 1}, {value: ['a', 'b']})).to.be.false; 12 | expect(fn(undefined, undefined, {value: 2}, {value: ['a']})).to.be.true; 13 | }); 14 | 15 | it('should return true if the value is less than the constraint', () => { 16 | expect(fn(1, undefined, {value: 5})).to.be.true; 17 | }); 18 | 19 | it('should true if the value is the same as than the constraint', () => { 20 | expect(fn(5, undefined, {value: 5})).to.be.true; 21 | }); 22 | 23 | it('should return false by default when field is over the max', () => { 24 | expect(fn(10, undefined, {value: 5})).to.be.false; 25 | }); 26 | 27 | it('should return custom error message if provided when field is over the max', () => { 28 | expect(fn(10, undefined, {value: 5, errorMessage: 'Too much!'})).to.equal('Too much!'); 29 | }); 30 | 31 | it('should accept string input', () => { 32 | expect(fn('1', undefined, {value: '2'})).to.be.true; 33 | expect(fn('1', undefined, {value: 2})).to.be.true; 34 | expect(fn('1', undefined, {value: '0'})).to.be.false; 35 | expect(fn('1', undefined, {value: 0})).to.be.false; 36 | }); 37 | 38 | it('should accept string constraint input', () => { 39 | expect(fn('1', undefined, {value: '2'})).to.be.true; 40 | expect(fn(1, undefined, {value: '2'})).to.be.true; 41 | expect(fn('3', undefined, {value: '2'})).to.be.false; 42 | expect(fn(3, undefined, {value: '2'})).to.be.false; 43 | }); 44 | 45 | it('should accept numeric input', () => { 46 | expect(fn(1, undefined, {value: '2'})).to.be.true; 47 | expect(fn(1, undefined, {value: 2})).to.be.true; 48 | expect(fn(1, undefined, {value: '0'})).to.be.false; 49 | expect(fn(1, undefined, {value: 0})).to.be.false; 50 | }); 51 | 52 | it('should accept numeric constraint input', () => { 53 | expect(fn('1', undefined, {value: 2})).to.be.true; 54 | expect(fn(1, undefined, {value: 2})).to.be.true; 55 | expect(fn('3', undefined, {value: 2})).to.be.false; 56 | expect(fn(3, undefined, {value: 2})).to.be.false; 57 | }); 58 | 59 | it('should not accept non numeric input', () => { 60 | expect(fn('1a', undefined, {value: 2})).to.be.false; 61 | expect(fn('a1', undefined, {value: 2})).to.be.false; 62 | expect(fn('1.1.1', undefined, {value: 2})).to.be.false; 63 | }); 64 | 65 | it('should accept decimal input', () => { 66 | expect(fn('1.5', undefined, {value: 2})).to.be.true; 67 | expect(fn(1.5, undefined, {value: 2})).to.be.true; 68 | expect(fn('1.5', undefined, {value: 1})).to.be.false; 69 | expect(fn(1.5, undefined, {value: 1})).to.be.false; 70 | }); 71 | 72 | it('should accept decimal constraint input', () => { 73 | expect(fn(1.5, undefined, {value: 2.2})).to.be.true; 74 | expect(fn(1.5, undefined, {value: '2.2'})).to.be.true; 75 | expect(fn(3.5, undefined, {value: 2.2})).to.be.false; 76 | expect(fn(3.5, undefined, {value: '2.2'})).to.be.false; 77 | }); 78 | 79 | it('should compare dates when date validation is on', () => { 80 | expect(fn('2016-10-09', undefined, {value: '2016-10-10'}, {validations: {date: {value: true}}})).to.be.true; 81 | expect(fn('2016-10-10', undefined, {value: '2016-10-10'}, {validations: {date: {value: true}}})).to.be.true; 82 | expect(fn('2016-10-11', undefined, {value: '2016-10-10'}, {validations: {date: {value: true}}})).to.be.false; 83 | expect(fn('2016-10-12', undefined, {value: '2016-10-10'}, {validations: {date: {value: true}}})).to.be.false; 84 | }); 85 | 86 | it('should compare dates when the field is of type date', () => { 87 | expect(fn('2016-10-09', undefined, {value: '2016-10-10'}, {props: {type: 'date'}})).to.be.true; 88 | expect(fn('2016-10-10', undefined, {value: '2016-10-10'}, {props: {type: 'date'}})).to.be.true; 89 | expect(fn('2016-10-11', undefined, {value: '2016-10-10'}, {props: {type: 'date'}})).to.be.false; 90 | expect(fn('2016-10-12', undefined, {value: '2016-10-10'}, {props: {type: 'date'}})).to.be.false; 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /__test__/AvValidator.maxchecked.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.maxChecked; 4 | 5 | describe('Max Checked Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('have an alias of maxChecked', () => { 11 | expect(fn).to.equal(AvValidator.maxChecked); 12 | }); 13 | 14 | it('should return false if the value is greater than the constraint', () => { 15 | expect(fn(undefined, undefined, {value: 1}, {value: ['a', 'b']})).to.be.false; 16 | }); 17 | 18 | it('should return true if the value is the same as the constraint', () => { 19 | expect(fn(undefined, undefined, {value: 2}, {value: ['a', 'b']})).to.be.true; 20 | }); 21 | 22 | it('should return false when field is over the max', () => { 23 | expect(fn(undefined, undefined, {value: 1}, {value: ['a', 'b']})).to.be.false; 24 | }); 25 | 26 | it('should return custom error message if provided when field is over the max', () => { 27 | expect(fn(undefined, undefined, {value: 1, errorMessage: 'Too much!'}, {value: ['a', 'b']})).to.equal('Too much!'); 28 | }); 29 | 30 | it('should accept string constraint input', () => { 31 | expect(fn(undefined, undefined, {value: '2'}, {value: ['a']})).to.be.true; 32 | expect(fn(undefined, undefined, {value: '1'}, {value: ['a', 'b']})).to.be.false; 33 | }); 34 | 35 | it('should accept numeric constraint input', () => { 36 | expect(fn(undefined, undefined, {value: 2}, {value: ['a', 'b']})).to.be.true; 37 | expect(fn(undefined, undefined, {value: 1}, {value: ['a', 'b']})).to.be.false; 38 | }); 39 | 40 | it('should not accept non-numeric constraint input', () => { 41 | expect(fn(undefined, undefined, {value: '1a'}, {value: ['a']})).to.be.false; 42 | expect(fn(undefined, undefined, {value: 'a1'}, {value: ['a']})).to.be.false; 43 | expect(fn(undefined, undefined, {value: '1.1.1'}, {value: ['a']})).to.be.false; 44 | }); 45 | 46 | it('should not accept decimal constraint input', () => { 47 | expect(fn(undefined, undefined, {value: 20.2}, {value: ['a', 'b', 'c']})).to.be.false; 48 | expect(fn(undefined, undefined, {value: '20.2'}, {value: ['a', 'b', 'c']})).to.be.false; 49 | expect(fn(undefined, undefined, {value: 2.2}, {value: ['a']})).to.be.false; 50 | expect(fn(undefined, undefined, {value: '2.2'}, {value: ['a']})).to.be.false; 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /__test__/AvValidator.maxlength.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.maxlength; 4 | 5 | describe('Max Length Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('have an alias of maxLength', () => { 11 | expect(fn).to.equal(AvValidator.maxLength); 12 | }); 13 | 14 | it('should return true if the value length is greater than the constraint', () => { 15 | expect(fn('123', undefined, {value: 5})).to.be.true; 16 | }); 17 | 18 | it('should true if the value is the same as than the constraint', () => { 19 | expect(fn('12345', undefined, {value: 5})).to.be.true; 20 | }); 21 | 22 | it('should return false by default when field is over the max', () => { 23 | expect(fn('123456', undefined, {value: 5})).to.be.false; 24 | }); 25 | 26 | it('should return custom error message if provided when field is over the max', () => { 27 | expect(fn('123456', undefined, {value: 5, errorMessage: 'Not enough!'})).to.equal('Not enough!'); 28 | }); 29 | 30 | it('should accept string input', () => { 31 | expect(fn('12345', undefined, {value: '2'})).to.be.false; 32 | expect(fn('12345', undefined, {value: 2})).to.be.false; 33 | expect(fn('1', undefined, {value: '2'})).to.be.true; 34 | expect(fn('1', undefined, {value: 2})).to.be.true; 35 | }); 36 | 37 | it('should accept string constraint input', () => { 38 | expect(fn('12345', undefined, {value: '2'})).to.be.false; 39 | expect(fn('1', undefined, {value: '2'})).to.be.true; 40 | }); 41 | 42 | it('should not accept numeric input', () => { 43 | expect(fn(10, undefined, {value: '3'})).to.be.false; 44 | expect(fn(2, undefined, {value: 3})).to.be.false; 45 | }); 46 | 47 | it('should accept numeric constraint input', () => { 48 | expect(fn('123456', undefined, {value: 2})).to.be.false; 49 | expect(fn('123', undefined, {value: 6})).to.be.true; 50 | }); 51 | 52 | it('should accept numeric input', () => { 53 | expect(fn('0p5p', undefined, {value: 5})).to.be.true; 54 | expect(fn('0001', undefined, {value: 5})).to.be.true; 55 | expect(fn('1.1.', undefined, {value: 6})).to.be.true; 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /__test__/AvValidator.min.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.min; 4 | 5 | describe('Min Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('should accept input array as an alias for minChecked', () => { 11 | expect(fn(undefined, undefined, {value: 1}, {value: ['a', 'b']})).to.be.true; 12 | expect(fn(undefined, undefined, {value: 2}, {value: ['a']})).to.be.false; 13 | }); 14 | 15 | it('should return true if the value is greater than the constraint', () => { 16 | expect(fn(10, undefined, {value: 5})).to.be.true; 17 | }); 18 | 19 | it('should true if the value is the same as than the constraint', () => { 20 | expect(fn(5, undefined, {value: 5})).to.be.true; 21 | }); 22 | 23 | it('should return false by default when field is over the max', () => { 24 | expect(fn(1, undefined, {value: 5})).to.be.false; 25 | }); 26 | 27 | it('should return custom error message if provided when field is over the max', () => { 28 | expect(fn(1, undefined, {value: 5, errorMessage: 'Too much!'})).to.equal('Too much!'); 29 | }); 30 | 31 | it('should accept string input', () => { 32 | expect(fn('12', undefined, {value: '2'})).to.be.true; 33 | expect(fn('12', undefined, {value: 2})).to.be.true; 34 | expect(fn('12', undefined, {value: '20'})).to.be.false; 35 | expect(fn('12', undefined, {value: 20})).to.be.false; 36 | }); 37 | 38 | it('should accept string constraint input', () => { 39 | expect(fn('10', undefined, {value: '2'})).to.be.true; 40 | expect(fn(10, undefined, {value: '2'})).to.be.true; 41 | expect(fn('3', undefined, {value: '20'})).to.be.false; 42 | expect(fn(3, undefined, {value: '20'})).to.be.false; 43 | }); 44 | 45 | it('should accept numeric input', () => { 46 | expect(fn(10, undefined, {value: '2'})).to.be.true; 47 | expect(fn(10, undefined, {value: 2})).to.be.true; 48 | expect(fn(2, undefined, {value: '10'})).to.be.false; 49 | expect(fn(2, undefined, {value: 10})).to.be.false; 50 | }); 51 | 52 | it('should accept numeric constraint input', () => { 53 | expect(fn('10', undefined, {value: 2})).to.be.true; 54 | expect(fn(10, undefined, {value: 2})).to.be.true; 55 | expect(fn('3', undefined, {value: 20})).to.be.false; 56 | expect(fn(3, undefined, {value: 20})).to.be.false; 57 | }); 58 | 59 | it('should not accept non numeric input', () => { 60 | expect(fn('1a', undefined, {value: 2})).to.be.false; 61 | expect(fn('a1', undefined, {value: 2})).to.be.false; 62 | expect(fn('1.1.1', undefined, {value: 2})).to.be.false; 63 | }); 64 | 65 | it('should accept decimal input', () => { 66 | expect(fn('10.5', undefined, {value: 2})).to.be.true; 67 | expect(fn(10.5, undefined, {value: 2})).to.be.true; 68 | expect(fn('1.5', undefined, {value: 10})).to.be.false; 69 | expect(fn(1.5, undefined, {value: 10})).to.be.false; 70 | }); 71 | 72 | it('should accept decimal constraint input', () => { 73 | expect(fn(10.5, undefined, {value: 2.2})).to.be.true; 74 | expect(fn(10.5, undefined, {value: '2.2'})).to.be.true; 75 | expect(fn(3.5, undefined, {value: 20.2})).to.be.false; 76 | expect(fn(3.5, undefined, {value: '20.2'})).to.be.false; 77 | }); 78 | 79 | 80 | it('should compare dates when date validation is on', () => { 81 | expect(fn('2016-10-08', undefined, {value: '2016-10-10'}, {validations: {date: {value: true}}})).to.be.false; 82 | expect(fn('2016-10-09', undefined, {value: '2016-10-10'}, {validations: {date: {value: true}}})).to.be.false; 83 | expect(fn('2016-10-10', undefined, {value: '2016-10-10'}, {validations: {date: {value: true}}})).to.be.true; 84 | expect(fn('2016-10-11', undefined, {value: '2016-10-10'}, {validations: {date: {value: true}}})).to.be.true; 85 | }); 86 | 87 | it('should compare dates when the field is of type date', () => { 88 | expect(fn('2016-10-08', undefined, {value: '2016-10-10'}, {props: {type: 'date'}})).to.be.false; 89 | expect(fn('2016-10-09', undefined, {value: '2016-10-10'}, {props: {type: 'date'}})).to.be.false; 90 | expect(fn('2016-10-10', undefined, {value: '2016-10-10'}, {props: {type: 'date'}})).to.be.true; 91 | expect(fn('2016-10-11', undefined, {value: '2016-10-10'}, {props: {type: 'date'}})).to.be.true; 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /__test__/AvValidator.minchecked.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.minChecked; 4 | 5 | describe('Min Checked Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('have an alias of minChecked', () => { 11 | expect(fn).to.equal(AvValidator.minChecked); 12 | }); 13 | 14 | it('should return true if the value is greater than the constraint', () => { 15 | expect(fn(undefined, undefined, {value: 1}, {value: ['a', 'b']})).to.be.true; 16 | }); 17 | 18 | it('should return true if the value is the same as than the constraint', () => { 19 | expect(fn(undefined, undefined, {value: 1}, {value: ['a']})).to.be.true; 20 | }); 21 | 22 | it('should return false when field is under the min', () => { 23 | expect(fn(undefined, undefined, {value: 2}, {value: ['a']})).to.be.false; 24 | }); 25 | 26 | it('should return custom error message if provided when field is under the min', () => { 27 | expect(fn(undefined, undefined, {value: 5, errorMessage: 'Too much!'}, {value: ['a']})).to.equal('Too much!'); 28 | }); 29 | 30 | it('should accept string constraint input', () => { 31 | expect(fn(undefined, undefined, {value: '1'}, {value: ['a']})).to.be.true; 32 | expect(fn(undefined, undefined, {value: '20'}, {value: ['a']})).to.be.false; 33 | }); 34 | 35 | it('should accept numeric constraint input', () => { 36 | expect(fn(undefined, undefined, {value: 1}, {value: ['a']})).to.be.true; 37 | expect(fn(undefined, undefined, {value: 20}, {value: ['a']})).to.be.false; 38 | }); 39 | 40 | it('should not accept non-numeric constraint input', () => { 41 | expect(fn(undefined, undefined, {value: '1a'}, {value: ['a']})).to.be.false; 42 | expect(fn(undefined, undefined, {value: 'a1'}, {value: ['a']})).to.be.false; 43 | expect(fn(undefined, undefined, {value: '1.1.1'}, {value: ['a']})).to.be.false; 44 | }); 45 | 46 | it('should not accept decimal constraint input', () => { 47 | expect(fn(undefined, undefined, {value: 0.2}, {value: ['a']})).to.be.false; 48 | expect(fn(undefined, undefined, {value: '2.2'}, {value: ['a']})).to.be.false; 49 | expect(fn(undefined, undefined, {value: 20.2}, {value: ['a', 'b', 'c']})).to.be.false; 50 | expect(fn(undefined, undefined, {value: '20.2'}, {value: ['a', 'b', 'c']})).to.be.false; 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /__test__/AvValidator.minlength.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.minlength; 4 | 5 | describe('Min Length Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('have an alias of minLength', () => { 11 | expect(fn).to.equal(AvValidator.minLength); 12 | }); 13 | 14 | it('should return true if the value length is greater than the constraint', () => { 15 | expect(fn('123456', undefined, {value: 5})).to.be.true; 16 | }); 17 | 18 | it('should true if the value is the same as than the constraint', () => { 19 | expect(fn('12345', undefined, {value: 5})).to.be.true; 20 | }); 21 | 22 | it('should return false by default when field is over the max', () => { 23 | expect(fn('1234', undefined, {value: 5})).to.be.false; 24 | }); 25 | 26 | it('should return custom error message if provided when field is over the max', () => { 27 | expect(fn('1234', undefined, {value: 5, errorMessage: 'Too much!'})).to.equal('Too much!'); 28 | }); 29 | 30 | it('should accept string input', () => { 31 | expect(fn('123', undefined, {value: '5'})).to.be.false; 32 | expect(fn('123', undefined, {value: 5})).to.be.false; 33 | expect(fn('123', undefined, {value: '2'})).to.be.true; 34 | expect(fn('123', undefined, {value: 2})).to.be.true; 35 | }); 36 | 37 | it('should accept string constraint input', () => { 38 | expect(fn('1', undefined, {value: '2'})).to.be.false; 39 | expect(fn('12345', undefined, {value: '2'})).to.be.true; 40 | }); 41 | 42 | it('should not accept numeric input', () => { 43 | expect(fn(10, undefined, {value: '1'})).to.be.false; 44 | expect(fn(2, undefined, {value: 1})).to.be.false; 45 | }); 46 | 47 | it('should accept numeric constraint input', () => { 48 | expect(fn('12345', undefined, {value: 20})).to.be.false; 49 | expect(fn('12345', undefined, {value: 3})).to.be.true; 50 | }); 51 | 52 | it('should accept non numeric input', () => { 53 | expect(fn('1a0', undefined, {value: 2})).to.be.true; 54 | expect(fn('001', undefined, {value: 2})).to.be.true; 55 | expect(fn('1.1.1', undefined, {value: 3})).to.be.true; 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /__test__/AvValidator.npi.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.npi; 4 | 5 | describe('NPI Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('should return custom error message if provided when field is not valid', () => { 11 | expect(fn('1234', undefined, {errorMessage: 'Not an NPI!'})).to.equal('Not an NPI!'); 12 | }); 13 | 14 | it('should return false if NPI contains non-digits', () => { 15 | expect(fn('i2eh56789o')).to.be.false; 16 | }); 17 | 18 | it('should return false if NPI is not 10 digits in length', () => { 19 | expect(fn('123456789')).to.be.false; 20 | expect(fn('12345678901')).to.be.false; 21 | }); 22 | 23 | it('should return false if NPI does not start with a 1, 2, 3, or 4', () => { 24 | expect(fn('5678901234')).to.be.false; 25 | }); 26 | 27 | it('should return false if NPI checksum does not match check digit', () => { 28 | expect(fn('1234567890')).to.be.false; 29 | }); 30 | 31 | it('should return true if NPI is valid', () => { 32 | expect(fn('1234567893')).to.be.true; 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /__test__/AvValidator.number.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.number; 4 | 5 | describe('Number Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('should return custom error message if provided when field is not valid', () => { 11 | expect(fn('a4', undefined, {errorMessage: 'NaN!'})).to.equal('NaN!'); 12 | }); 13 | 14 | it('should accept numbers', () => { 15 | expect(fn(0)).to.be.true; 16 | expect(fn(-1)).to.be.true; 17 | expect(fn(1)).to.be.true; 18 | expect(fn(10)).to.be.true; 19 | }); 20 | 21 | it('should accept decimals', () => { 22 | expect(fn(0.1)).to.be.true; 23 | expect(fn(-1.1)).to.be.true; 24 | expect(fn(1.1)).to.be.true; 25 | expect(fn(10.1)).to.be.true; 26 | }); 27 | 28 | it('should accept number like strings', () => { 29 | expect(fn('0')).to.be.true; 30 | expect(fn('-1')).to.be.true; 31 | expect(fn('1')).to.be.true; 32 | expect(fn('10')).to.be.true; 33 | }); 34 | 35 | it('should accept decimal like strings', () => { 36 | expect(fn('0.1')).to.be.true; 37 | expect(fn('-1.1')).to.be.true; 38 | expect(fn('1.1')).to.be.true; 39 | expect(fn('10.1')).to.be.true; 40 | }); 41 | 42 | it('should not accept strings that are not like numbers', () => { 43 | expect(fn('a0')).to.be.false; 44 | expect(fn('-1b')).to.be.false; 45 | expect(fn('1c')).to.be.false; 46 | expect(fn('1d0')).to.be.false; 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /__test__/AvValidator.pattern.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.pattern; 4 | 5 | describe('Pattern Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('should return custom error message if provided when field is not valid', () => { 11 | expect(fn('at3', undefined, {value: /^\d$/, errorMessage: 'Invalid!'})).to.equal('Invalid!'); 12 | }); 13 | 14 | it('should accept regex objects', () => { 15 | expect(fn('3', undefined, {value: /^\d$/})).to.be.true; 16 | expect(fn('a', undefined, {value: /^\d$/})).to.be.false; 17 | }); 18 | 19 | it('should accept regex like strings', () => { 20 | expect(fn('3', undefined, {value: '/^\\d$/'})).to.be.true; 21 | expect(fn('a', undefined, {value: '/^\\d$/'})).to.be.false; 22 | }); 23 | 24 | it('should accept somewhat regex like strings', () => { 25 | expect(fn('3', undefined, {value: '^\\d$'})).to.be.true; 26 | expect(fn('a', undefined, {value: '^\\d$'})).to.be.false; 27 | }); 28 | 29 | it('should accept and array of regex to match at least one of', () => { 30 | expect(fn('3.4', undefined, {value: ['^\\d$', /^\d\.\d$/, '/^\\d\.\\d\.\\d$/']})).to.be.true; 31 | expect(fn('3.4', undefined, {value: ['^\\d$', /^\d\.\d$/, '/^\\d\.\\d\.\\d$/']})).to.be.true; 32 | expect(fn('3.4.5', undefined, {value: ['^\\d$', /^\d\.\d$/, '/^\\d\.\\d\.\\d$/']})).to.be.true; 33 | expect(fn('3.a.b', undefined, {value: ['^\\d$', /^\d\.\d$/, '/^\\d\.\\d\.\\d$/']})).to.be.false; 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /__test__/AvValidator.phone.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.phone; 4 | 5 | describe('Phone Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | it('should have an alias of "tel"', () => { 11 | expect(fn).to.equal(AvValidator.tel); 12 | }); 13 | 14 | it('should return custom error message if provided when field is not valid', () => { 15 | expect(fn('at3', undefined, {errorMessage: 'Invalid!'})).to.equal('Invalid!'); 16 | }); 17 | 18 | it('should accept a regex to validate with', () => { 19 | expect(fn('3', undefined, {pattern: /^\d$/})).to.be.true; 20 | expect(fn('3', undefined, {pattern: '/^\\d$/'})).to.be.true; 21 | }); 22 | 23 | it('should not accept less than 10 digits', () => { 24 | expect(fn('123456789')).to.be.false; 25 | }); 26 | 27 | it('country code of "+1" is allowed', () => { 28 | expect(fn('+14444444444')).to.be.true; 29 | expect(fn('14444444444')).to.be.true; 30 | expect(fn('+1 4444444444')).to.be.true; 31 | expect(fn('1 4444444444')).to.be.true; 32 | }); 33 | 34 | it('must be 10 digits (minus country code)', () => { 35 | expect(fn('4444444444')).to.be.true; 36 | expect(fn('44444444445')).to.be.false; 37 | expect(fn('444 444 4444')).to.be.true; 38 | }); 39 | 40 | it('can be formatted', () => { 41 | expect(fn('(444) 444-4444')).to.be.true; 42 | expect(fn('+1 (444) 444-4444')).to.be.true; 43 | expect(fn('444-444-4444')).to.be.true; 44 | expect(fn('+1 444-444-4444')).to.be.true; 45 | expect(fn('444.444.4444')).to.be.true; 46 | expect(fn('(444) 444 4444')).to.be.true; 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /__test__/AvValidator.required.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.required; 4 | 5 | describe('Required Validation', () => { 6 | it('should be invalid with ""', () => { 7 | expect(fn('')).to.be.false; 8 | }); 9 | 10 | it('should be invalid with false', () => { 11 | expect(fn(false)).to.be.false; 12 | }); 13 | 14 | it('should return custom error message if provided when field is not valid', () => { 15 | expect(fn('', undefined, {errorMessage: 'Invalid!'})).to.equal('Invalid!'); 16 | }); 17 | 18 | it('should be valid with 0', () => { 19 | expect(fn(0)).to.be.true; 20 | }); 21 | 22 | it('should be valid with -1', () => { 23 | expect(fn(-1)).to.be.true; 24 | }); 25 | 26 | it('should be valid with true', () => { 27 | expect(fn(true)).to.be.true; 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /__test__/AvValidator.step.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.step; 4 | 5 | describe('Step Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | 11 | it('should return custom error message if provided when field is not valid', () => { 12 | expect(fn(12, undefined, {value: 7, errorMessage: 'Get to steppin!'})).to.equal('Get to steppin!'); 13 | }); 14 | 15 | it('should accept numbers', () => { 16 | expect(fn(10, undefined, {value: 5})).to.be.true; 17 | expect(fn(11, undefined, {value: 5})).to.be.false; 18 | expect(fn(10, undefined, {value: 6})).to.be.false; 19 | expect(fn(10, undefined, {value: 2})).to.be.true; 20 | 21 | expect(fn('10', undefined, {value: 5})).to.be.true; 22 | expect(fn('11', undefined, {value: 5})).to.be.false; 23 | expect(fn('10', undefined, {value: 6})).to.be.false; 24 | expect(fn('10', undefined, {value: 2})).to.be.true; 25 | 26 | expect(fn(10, undefined, {value: '5'})).to.be.true; 27 | expect(fn(11, undefined, {value: '5'})).to.be.false; 28 | expect(fn(10, undefined, {value: '6'})).to.be.false; 29 | expect(fn(10, undefined, {value: '2'})).to.be.true; 30 | }); 31 | 32 | it('should accept decimals', () => { 33 | expect(fn(10.2, undefined, {value: 5.1})).to.be.true; 34 | expect(fn(11.5, undefined, {value: 5.3})).to.be.false; 35 | expect(fn(10.5, undefined, {value: 6.7})).to.be.false; 36 | expect(fn(10.5, undefined, {value: 2.1})).to.be.true; 37 | expect(fn(0.00000002, undefined, {value: 0.00000001})).to.be.true; 38 | expect(fn(0.000000011, undefined, {value: 0.00000001})).to.be.false; 39 | 40 | expect(fn('10.2', undefined, {value: 5.1})).to.be.true; 41 | expect(fn('11.5', undefined, {value: 5.55})).to.be.false; 42 | expect(fn('10.55', undefined, {value: 6.2})).to.be.false; 43 | expect(fn('10.5', undefined, {value: 2.1})).to.be.true; 44 | expect(fn('0.00000002', undefined, {value: 0.00000001})).to.be.true; 45 | expect(fn('0.000000011', undefined, {value: 0.00000001})).to.be.false; 46 | 47 | expect(fn(10.2, undefined, {value: '5.1'})).to.be.true; 48 | expect(fn(11.5, undefined, {value: '5.4'})).to.be.false; 49 | expect(fn(10.5, undefined, {value: '6.7'})).to.be.false; 50 | expect(fn(10.5, undefined, {value: '2.1'})).to.be.true; 51 | expect(fn(0.00000002, undefined, {value: '0.00000001'})).to.be.true; 52 | expect(fn(0.000000011, undefined, {value: '0.00000001'})).to.be.false; 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /__test__/AvValidator.url.spec.js: -------------------------------------------------------------------------------- 1 | import {AvValidator} from 'availity-reactstrap-validation'; 2 | 3 | const fn = AvValidator.url; 4 | 5 | describe('URL Validation', () => { 6 | it('should not require a value', () => { 7 | expect(fn('')).to.be.true; 8 | }); 9 | 10 | describe('protocols', () => { 11 | it('should allow http://', () => { 12 | expect(fn('http://foo.com')).to.be.true; 13 | }); 14 | 15 | it('should allow https://', () => { 16 | expect(fn('https://foo.com')).to.be.true; 17 | }); 18 | 19 | it('should allow ftp://', () => { 20 | expect(fn('ftp://foo.com')).to.be.true; 21 | }); 22 | 23 | it('should allow sftp://', () => { 24 | expect(fn('sftp://foo.com')).to.be.true; 25 | }); 26 | 27 | it('should allow ftps://', () => { 28 | expect(fn('ftps://foo.com')).to.be.true; 29 | }); 30 | 31 | it('should not allow sftps://', () => { 32 | expect(fn('sftps://foo.com')).to.be.false; 33 | }); 34 | 35 | it('should not allow //', () => { 36 | expect(fn('//foo.com')).to.be.false; 37 | }); 38 | 39 | it('should not allow no protocol', () => { 40 | expect(fn('foo.com')).to.be.false; 41 | }); 42 | }); 43 | 44 | describe('domain', () => { 45 | it('should allow a domain', () => { 46 | expect(fn('http://foo.com')).to.be.true; 47 | }); 48 | 49 | it('should allow a subdomain', () => { 50 | expect(fn('http://www.foo.com')).to.be.true; 51 | expect(fn('http://bar.foo.com')).to.be.true; 52 | }); 53 | 54 | it('should allow a multiple subdomains', () => { 55 | expect(fn('http://app.bar.foo.com')).to.be.true; 56 | expect(fn('http://deep.app.bar.foo.com')).to.be.true; 57 | }); 58 | 59 | it('should now allow domains starting with a "."', () => { 60 | expect(fn('http://.foo.com')).to.be.false; 61 | expect(fn('http://.bar.foo.com')).to.be.false; 62 | }); 63 | 64 | it('should now allow domain names starting with a "-"', () => { 65 | expect(fn('http://-foo.com')).to.be.false; 66 | expect(fn('http://-bar.foo.com')).to.be.false; 67 | }); 68 | 69 | it('should now allow domains ending with a "-"', () => { 70 | expect(fn('http://foo-.com')).to.be.false; 71 | expect(fn('http://bar-.foo.com')).to.be.false; 72 | }); 73 | }); 74 | 75 | it('should allow port', () => { 76 | expect(fn('http://foo.com:8080')).to.be.true; 77 | expect(fn('http://bar.foo.com:1337/')).to.be.true; 78 | }); 79 | 80 | it('should allow userid', () => { 81 | expect(fn('http://userid@foo.com')).to.be.true; 82 | expect(fn('http://userid@bar.foo.com:1337/')).to.be.true; 83 | }); 84 | 85 | it('should allow userid with password', () => { 86 | expect(fn('http://userid:password@foo.com')).to.be.true; 87 | expect(fn('http://userid:password@bar.foo.com:1337/')).to.be.true; 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /docs/lib/Components/CheckboxPage.js: -------------------------------------------------------------------------------- 1 | /* eslint react/no-multi-comp: 0, react/prop-types: 0 */ 2 | import React from 'react'; 3 | import { PrismCode } from 'react-prism'; 4 | import Helmet from 'react-helmet'; 5 | 6 | import CheckboxExample from '../examples/Checkbox'; 7 | const CheckboxExampleSource = require('!!raw!../examples/Checkbox.js'); 8 | import CheckboxTrueValueExample from '../examples/CheckboxTrueValue'; 9 | const CheckboxTrueValueExampleSource = require('!!raw!../examples/CheckboxTrueValue.js'); 10 | import CheckboxFalseValueExample from '../examples/CheckboxFalseValue'; 11 | const CheckboxFalseValueExampleSource = require('!!raw!../examples/CheckboxFalseValue.js'); 12 | import CheckboxDefaultExample from '../examples/CheckboxDefault'; 13 | const CheckboxDefaultExampleSource = require('!!raw!../examples/CheckboxDefault.js'); 14 | 15 | export default class CheckboxPage extends React.Component { 16 | render() { 17 | return ( 18 |
19 | 20 |

Checkboxes

21 |

22 | Checkboxes are slightly special as the user cannot define a value, but only check and uncheck the box. 23 | There are special props, trueValue and falseValue which allow you to determine what 24 | the value returned will be when the box is check or not checked respectfully. trueValue will 25 | default to true and falseValue will default to false. 26 |

27 |
28 | 29 |
30 |
31 |           
32 |             {CheckboxExampleSource}
33 |           
34 |         
35 | 36 |

True Value

37 |

38 | Checking the boxes and submitting the form, you will see the value passed is the trueValue for 39 | the checkbox; true by default. 40 |

41 |
42 | 43 |
44 |
45 |           
46 |             {CheckboxTrueValueExampleSource}
47 |           
48 |         
49 | 50 |

False Value

51 |

52 | Leaving the boxes unchecked and submitting the form, you will see the value passed is the 53 | falseValue for the checkbox; false by default. 54 |

55 |
56 | 57 |
58 |
59 |           
60 |             {CheckboxFalseValueExampleSource}
61 |           
62 |         
63 | 64 |

Model Default Values

65 |

66 | Using the model prop on the form, you can indicate if the checkboxes should be checked or unchecked when 67 | initialized by providing the trueValue or falseValue in the model prop on the form. 68 |

69 |
70 | 71 |
72 |
73 |           
74 |             {CheckboxDefaultExampleSource}
75 |           
76 |         
77 |
78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /docs/lib/Components/FormPage.js: -------------------------------------------------------------------------------- 1 | /* eslint react/no-multi-comp: 0, react/prop-types: 0 */ 2 | import React from 'react'; 3 | import { PrismCode } from 'react-prism'; 4 | import Helmet from 'react-helmet'; 5 | 6 | import FormExample from '../examples/Form'; 7 | const FormExampleSource = require('!!raw!../examples/Form.js'); 8 | import FormOnSubmitExample from '../examples/FormOnSubmit'; 9 | const FormOnSubmitExampleSource = require('!!raw!../examples/FormOnSubmit.js'); 10 | import FormOnValidSubmitExample from '../examples/FormOnValidSubmit'; 11 | const FormOnValidSubmitExampleSource = require('!!raw!../examples/FormOnValidSubmit.js'); 12 | import FormOnInvalidSubmitExample from '../examples/FormOnInvalidSubmit'; 13 | const FormOnInvalidSubmitExampleSource = require('!!raw!../examples/FormOnInvalidSubmit.js'); 14 | import FormModelExample from '../examples/FormModel'; 15 | const FormModelExampleSource = require('!!raw!../examples/FormModel.js'); 16 | 17 | export default class FormPage extends React.Component { 18 | render() { 19 | return ( 20 |
21 | 22 |

AvForm

23 |

The AvForm component wraps reactstrap's form to add context that the other Av components know about to help share validation state

24 |
25 | 26 |
27 |
28 |           
29 |             {FormExampleSource}
30 |           
31 |         
32 | 33 |

OnSubmit

34 |

This callback is called with every submission of the form

35 |
36 | 37 |
38 |
39 |           
40 |             {FormOnSubmitExampleSource}
41 |           
42 |         
43 | 44 |

OnValidSubmit

45 |

This callback is called only when every field is valid when submitted

46 |
47 | 48 |
49 |
50 |           
51 |             {FormOnValidSubmitExampleSource}
52 |           
53 |         
54 | 55 |

OnInvalidSubmit

56 |

This callback is called only when any field is invalid when submitted

57 |
58 | 59 |
60 |
61 |           
62 |             {FormOnInvalidSubmitExampleSource}
63 |           
64 |         
65 | 66 |

Model (Easy default values)

67 |

68 | Pass an object in which the keys correspond to the name props of the form's input to set their initial value. 69 | Nested objects can be accessed via dot notation. Individual array indexes can be accessed via bracket notation. 70 | The values object returned to the various submissions handlers will reflex the object shape. 71 | Behind the scenes, lodash's get and set are being used, 72 | look at lodash's documentation to learn more about how to access complex data in the model. 73 |

74 |
75 | 76 |
77 |
78 |           
79 |             {FormModelExampleSource}
80 |           
81 |         
82 |
83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /docs/lib/Components/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router'; 3 | import { Container, Row, Col, Nav, NavItem, NavLink } from 'reactstrap'; 4 | 5 | const ComponentLink = (props) => { 6 | return ( 7 | 8 | 9 | {props.item.name} 10 | 11 | 12 | ); 13 | }; 14 | 15 | 16 | class Components extends React.Component { 17 | constructor(props) { 18 | super(props); 19 | 20 | this.state = { 21 | navItems: [ 22 | { 23 | name: 'AvForm', 24 | to: '/components/avform/', 25 | }, 26 | { 27 | name: 'Validators', 28 | to: '/components/validators/', 29 | }, 30 | { 31 | name: 'Checkboxes', 32 | to: '/components/checkboxes/', 33 | }, 34 | ], 35 | }; 36 | } 37 | render() { 38 | return ( 39 | 40 | 41 | 42 |
43 |
Components
44 | 49 |
50 | 51 | 52 | {this.props.children} 53 | 54 |
55 |
56 | ); 57 | } 58 | } 59 | 60 | export default Components; 61 | -------------------------------------------------------------------------------- /docs/lib/Home/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { PrismCode } from 'react-prism'; 3 | import { Jumbotron, Button, Container, Row, Col } from 'reactstrap'; 4 | import { Link } from 'react-router'; 5 | import Example from '../examples/import-basic'; 6 | 7 | const importBasic = require('!!raw!../examples/import-basic.js'); 8 | 9 | export default () => { 10 | return ( 11 |
12 | 13 | 14 | 15 | 16 |

17 | 18 |

19 |

Availity reactstrap Validation

20 |

21 | Easy to use form validation for reactstrap 22 |

23 |

24 | 25 | 26 |

27 | 28 |
29 |
30 |
31 | 32 | 33 | 34 |

Installation

35 |
36 |

NPM

37 |

Install reactstrap and peer dependencies via NPM

38 |
39 |               npm install --save availity-reactstrap-validation react react-dom
40 |             
41 |

ES6 - import the components you need

42 |
43 | 44 |
45 |
46 |               
47 |                 {importBasic}
48 |               
49 |             
50 |

About the Project

51 |
52 |

This library contains helper components that extend the form capabilities provided by reactstrap. The library does not depend on jQuery or Bootstrap javascript, only reactstrap.

53 |

Use the form and input components provided by this library directly instead of the ones provided by reactstrap. You can use the components provided by reactstrap in conjunction with the components this library provides without an problem, but validation will not work for those particular components.

54 | 55 |
56 |
57 |
58 | ); 59 | }; 60 | -------------------------------------------------------------------------------- /docs/lib/NotFound/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Container, Row, Col } from 'reactstrap'; 3 | import { Link } from 'react-router'; 4 | import Helmet from 'react-helmet'; 5 | 6 | export default () => { 7 | return ( 8 |
9 | 10 |
11 | 12 | 13 | 14 |

15 | 16 |

17 |

404 - Not Found

18 |

19 | Can't find what you're looking for? Open up an issue. 20 |

21 |

22 | 23 | 24 |

25 | 26 |
27 |
28 |
29 |
30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /docs/lib/UI/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Container, Row, Col } from 'reactstrap'; 3 | 4 | export default () => { 5 | return ( 6 |
7 | 8 | 9 | 10 |

11 | © 2016 - present Availity 12 | {' '} 13 |