From ad1c1100bee2eb52f3ad794bbdc1aced48b795a9 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 25 Apr 2016 18:21:57 +1000 Subject: [PATCH 1/2] Added isEmpty Added orConditions. Added validation tests. --- .gitignore | 1 + __tests__/RenderTests.js | 39 +++++++- __tests__/ValidatedInputTests.js | 150 +++++++++++++++++++++++++++++++ package.json | 1 + src/Form.js | 29 +++++- src/Validator.js | 1 + 6 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 __tests__/ValidatedInputTests.js diff --git a/.gitignore b/.gitignore index f06884f..c2ca283 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ node_modules .coverage/ dist/ lib/ +coverage/ diff --git a/__tests__/RenderTests.js b/__tests__/RenderTests.js index a5e4c53..aa789be 100644 --- a/__tests__/RenderTests.js +++ b/__tests__/RenderTests.js @@ -1,5 +1,5 @@ 'use strict'; -import Form from '../src/Form'; +import {ValidatedInput,Form, Radio, RadioGroup} from '../src'; // Note: THere is an issue with react-bootstrap and mocking. For now the whole node_modules directory has been unmocked. describe('React bootstrap validation compilation test', () => { @@ -7,7 +7,7 @@ describe('React bootstrap validation compilation test', () => { var TestUtils = require('react-addons-test-utils'); beforeEach(function() { - + }); it('Renders Form component correctly.', () => { @@ -19,5 +19,40 @@ describe('React bootstrap validation compilation test', () => { // Do some work with the validation outcomes } } />); + }); + it('Renders ValidatedInput component correctly.', () => { + // Render into document + let validSubmit = function(event){}; + TestUtils.renderIntoDocument( +
+ + ); + }); + it('Renders RadioGroup component correctly.', () => { + // Render into document + let validSubmit = function(event){}; + TestUtils.renderIntoDocument( +
+ v === 'cola'} + errorHelp='Pepsi? Seriously?' + labelClassName='col-xs-2' + wrapperClassName='col-xs-10'> + + + +
); }); + }); diff --git a/__tests__/ValidatedInputTests.js b/__tests__/ValidatedInputTests.js new file mode 100644 index 0000000..8d6c96d --- /dev/null +++ b/__tests__/ValidatedInputTests.js @@ -0,0 +1,150 @@ +'use strict'; +import {ValidatedInput,Form} from '../src'; + +// Note: THere is an issue with react-bootstrap and mocking. For now the whole node_modules directory has been unmocked. +describe('React bootstrap ValidatedInput test', () => { + var React = require('react'); + var TestUtils = require('react-addons-test-utils'); + beforeEach(function() { + }); + it('Validates or conditons.', () => { + // Render into document + var submittedObject = null; + var validSubmit = function(event){ + submittedObject = event; + }; + + let item = TestUtils.renderIntoDocument( +
+ + ); + + let input = TestUtils.scryRenderedDOMComponentsWithClass(item, 'testInput')[1]; + input.value=''; + TestUtils.Simulate.change(input); + TestUtils.Simulate.submit(item.refs.form); + // test for error messages next to the item + expect(submittedObject.email).toBe(''); + + input.value='someone@test.com'; + TestUtils.Simulate.change(input); + TestUtils.Simulate.submit(item.refs.form); + // test for error messages next to the item + expect(submittedObject.email).toBe('someone@test.com'); + + }); + it('Validates an empty field.', () => { + // Render into document + var submittedObject = null; + var validSubmit = function(event){ + submittedObject = event; + }; + + let item = TestUtils.renderIntoDocument( +
+ + ); + + let input = TestUtils.scryRenderedDOMComponentsWithClass(item, 'testInput')[1]; + input.value='aaaa'; + TestUtils.Simulate.change(input); + TestUtils.Simulate.submit(item.refs.form); + // test for error messages next to the item + expect(submittedObject).toBe(null); + input.value=''; + TestUtils.Simulate.change(input); + TestUtils.Simulate.submit(item.refs.form); + // test for error messages next to the item + expect(submittedObject.email).toBe(''); + }); + + it('Validates a number.', () => { + // Render into document + var submittedObject = null; + var validSubmit = function(event){ + submittedObject = event; + }; + + let item = TestUtils.renderIntoDocument( +
+ + ); + + let input = TestUtils.scryRenderedDOMComponentsWithClass(item, 'testInput')[1]; + input.value='not a number'; + TestUtils.Simulate.change(input); + TestUtils.Simulate.submit(item.refs.form); + // test for error messages next to the item + expect(submittedObject).toBe(null); + + input.value='23'; + TestUtils.Simulate.change(input); + TestUtils.Simulate.submit(item.refs.form); + // test for error messages next to the item + expect(submittedObject.number).toBe('23'); + }); + + it('Validates an email.', () => { + // Render into document + var submittedObject = null; + var validSubmit = function(event){ + submittedObject = event; + }; + + let item = TestUtils.renderIntoDocument( +
+ + ); + + let input = TestUtils.scryRenderedDOMComponentsWithClass(item, 'testInput')[1]; + input.value='notavlidaemailaddress'; + TestUtils.Simulate.change(input); + TestUtils.Simulate.submit(item.refs.form); + // test for error messages next to the item + expect(submittedObject).toBe(null); + + input.value='test@nowhere.com'; + TestUtils.Simulate.change(input); + TestUtils.Simulate.submit(item.refs.form); + console.log(submittedObject); + expect(submittedObject.email).toBe('test@nowhere.com'); + }); +}); diff --git a/package.json b/package.json index e31f51d..c19654b 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ }, "jest": { "scriptPreprocessor": "node_modules/babel-jest", + "collectCoverage": true, "unmockedModulePathPatterns": [ "node_modules", "src" diff --git a/src/Form.js b/src/Form.js index d8b82dc..335695e 100644 --- a/src/Form.js +++ b/src/Form.js @@ -200,7 +200,7 @@ export default class Form extends InputContainer { if (typeof this.props.validateOne === 'function') { result = this.props.validateOne(iptName, value, context, result); - } + } // if result is !== true, it is considered an error // it can be either bool or string error if (result !== true) { @@ -248,6 +248,8 @@ export default class Form extends InputContainer { } _compileValidationRules(input, ruleProp) { + + // Split and groups let rules = ruleProp.split(',').map(rule => { let params = rule.split(':'); let name = params.shift(); @@ -257,14 +259,31 @@ export default class Form extends InputContainer { name = name.substr(1); } - return { name, inverse, params }; + return { name, inverse, params,andCondition:true }; }); + + let orRules = ruleProp.split('|').map(rule => { + let params = rule.split(':'); + let name = params.shift(); + let inverse = name[0] === '!'; + + if (inverse) { + name = name.substr(1); + } + + return { name, inverse, params,andCondition:false }; + }); + if(ruleProp.indexOf('|')>0){ + rules = orRules; + } + + let validator = (input.props && input.props.type) === 'file' ? FileValidator : Validator; return val => { let result = true; - + let previousResult = true; rules.forEach(rule => { if (typeof validator[rule.name] !== 'function') { throw new Error('Invalid input validation rule "' + rule.name + '"'); @@ -275,6 +294,10 @@ export default class Form extends InputContainer { if (rule.inverse) { ruleResult = !ruleResult; } + if(!rule.andCondition){ + ruleResult = ruleResult || previousResult; + } + previousResult = ruleResult; if (result === true && ruleResult !== true) { result = getInputErrorMessage(input, rule.name) || diff --git a/src/Validator.js b/src/Validator.js index 0e267e9..be2969f 100644 --- a/src/Validator.js +++ b/src/Validator.js @@ -8,6 +8,7 @@ import validator from 'validator'; */ validator.extend('required', val => !validator.isNull(val)); +validator.extend('isEmpty', val => validator.isNull(val)); /** * Returns true if the value is boolean true * From 8ef7535793ef02ef58e2116707a2e6b9a9992c4d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 25 Apr 2016 20:59:11 +1000 Subject: [PATCH 2/2] cleanup variant --- src/Form.js | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/Form.js b/src/Form.js index 335695e..ad9875b 100644 --- a/src/Form.js +++ b/src/Form.js @@ -248,22 +248,16 @@ export default class Form extends InputContainer { } _compileValidationRules(input, ruleProp) { + let deliminator =','; + let andCondition =true; + // set the deliminator + if(ruleProp.indexOf('|')>0){ + deliminator='|'; + andCondition=false; + } // Split and groups - let rules = ruleProp.split(',').map(rule => { - let params = rule.split(':'); - let name = params.shift(); - let inverse = name[0] === '!'; - - if (inverse) { - name = name.substr(1); - } - - return { name, inverse, params,andCondition:true }; - }); - - - let orRules = ruleProp.split('|').map(rule => { + let rules = ruleProp.split(deliminator).map(rule => { let params = rule.split(':'); let name = params.shift(); let inverse = name[0] === '!'; @@ -272,12 +266,8 @@ export default class Form extends InputContainer { name = name.substr(1); } - return { name, inverse, params,andCondition:false }; + return { name, inverse, params,andCondition:andCondition }; }); - if(ruleProp.indexOf('|')>0){ - rules = orRules; - } - let validator = (input.props && input.props.type) === 'file' ? FileValidator : Validator;