Merge branch 'master' of https://github.com/christianalfoni/formsy-react
This commit is contained in:
commit
33ae737868
21
bower.json
21
bower.json
|
|
@ -1,8 +1,25 @@
|
|||
{
|
||||
"name": "formsy-react",
|
||||
"version": "0.12.4",
|
||||
"version": "0.12.5",
|
||||
"description": "A form input builder and validator for React JS",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/christianalfoni/formsy-react.git"
|
||||
},
|
||||
"main": "src/main.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"build/",
|
||||
"Gulpfile.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"react": "^0.13.1"
|
||||
}
|
||||
},
|
||||
"keywords": [
|
||||
"react",
|
||||
"form",
|
||||
"forms",
|
||||
"validation",
|
||||
"react-component"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "formsy-react",
|
||||
"version": "0.12.4",
|
||||
"version": "0.12.5",
|
||||
"description": "A form input builder and validator for React JS",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
@ -13,6 +13,13 @@
|
|||
},
|
||||
"author": "Christian Alfoni",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"react",
|
||||
"form",
|
||||
"forms",
|
||||
"validation",
|
||||
"react-component"
|
||||
],
|
||||
"devDependencies": {
|
||||
"browserify": "^6.2.0",
|
||||
"glob": "^4.0.6",
|
||||
|
|
|
|||
|
|
@ -78,7 +78,8 @@ Formsy.Form = React.createClass({displayName: "Form",
|
|||
|
||||
// Update model, submit to url prop and send the model
|
||||
submit: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
event && event.preventDefault();
|
||||
|
||||
// Trigger form as not pristine.
|
||||
// If any inputs have not been touched yet this will make them dirty
|
||||
|
|
@ -117,7 +118,7 @@ Formsy.Form = React.createClass({displayName: "Form",
|
|||
var component = this.inputs[name];
|
||||
var args = [{
|
||||
_isValid: !(name in errors),
|
||||
_serverError: errors[name]
|
||||
_validationError: errors[name]
|
||||
}];
|
||||
component.setState.apply(component, args);
|
||||
}.bind(this));
|
||||
|
|
@ -136,7 +137,7 @@ Formsy.Form = React.createClass({displayName: "Form",
|
|||
|
||||
var args = [{
|
||||
_isValid: false,
|
||||
_validationError: errors[name]
|
||||
_externalError: errors[name]
|
||||
}];
|
||||
component.setState.apply(component, args);
|
||||
}.bind(this));
|
||||
|
|
@ -217,7 +218,8 @@ Formsy.Form = React.createClass({displayName: "Form",
|
|||
component.setState({
|
||||
_isValid: validation.isValid,
|
||||
_isRequired: validation.isRequired,
|
||||
_validationError: validation.error
|
||||
_validationError: validation.error,
|
||||
_externalError: null
|
||||
}, this.validateForm);
|
||||
|
||||
},
|
||||
|
|
@ -225,7 +227,6 @@ Formsy.Form = React.createClass({displayName: "Form",
|
|||
// Checks validation on current value or a passed value
|
||||
runValidation: function (component, value) {
|
||||
|
||||
|
||||
var currentValues = this.getCurrentValues();
|
||||
var validationErrors = component.props.validationErrors;
|
||||
var validationError = component.props.validationError;
|
||||
|
|
@ -241,6 +242,7 @@ Formsy.Form = React.createClass({displayName: "Form",
|
|||
|
||||
var isRequired = Object.keys(component._requiredValidations).length ? !!requiredResults.success.length : false;
|
||||
var isValid = !validationResults.failed.length && !(this.props.validationErrors && this.props.validationErrors[component.props.name]);
|
||||
|
||||
return {
|
||||
isRequired: isRequired,
|
||||
isValid: isRequired ? false : isValid,
|
||||
|
|
@ -360,10 +362,14 @@ Formsy.Form = React.createClass({displayName: "Form",
|
|||
inputKeys.forEach(function (name, index) {
|
||||
var component = inputs[name];
|
||||
var validation = this.runValidation(component);
|
||||
if (validation.isValid && component.state._externalError) {
|
||||
validation.isValid = false;
|
||||
}
|
||||
component.setState({
|
||||
_isValid: validation.isValid,
|
||||
_isRequired: validation.isRequired,
|
||||
_validationError: validation.error
|
||||
_validationError: validation.error,
|
||||
_externalError: !validation.isValid && component.state._externalError ? component.state._externalError : null
|
||||
}, index === inputKeys.length - 1 ? onValidationComplete : null);
|
||||
}.bind(this));
|
||||
|
||||
|
|
@ -447,7 +453,8 @@ module.exports = {
|
|||
_isValid: true,
|
||||
_isPristine: true,
|
||||
_pristineValue: this.props.value,
|
||||
_validationError: ''
|
||||
_validationError: '',
|
||||
_externalError: null
|
||||
};
|
||||
},
|
||||
getDefaultProps: function () {
|
||||
|
|
@ -538,7 +545,7 @@ module.exports = {
|
|||
return this.state._value !== '';
|
||||
},
|
||||
getErrorMessage: function () {
|
||||
return !this.isValid() || this.showRequired() ? this.state._validationError : null;
|
||||
return !this.isValid() || this.showRequired() ? (this.state._externalError || this.state._validationError) : null;
|
||||
},
|
||||
isFormDisabled: function () {
|
||||
return this.props._isFormDisabled();
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,60 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: equals', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="equals:myValue"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with undefined', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: undefined}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with null', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: null}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail when the value is not equal', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'foo'}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass when the value is equal', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'myValue'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: hasValue', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="hasValue"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with undefined', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: undefined}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with null', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: null}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with a string', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'myValue'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: isAlpha', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isAlpha"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with undefined', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: undefined}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with null', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: null}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with a number', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 123}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with a string', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'myValue'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: isEmail', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value="foo" validations="isEmail"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with "foo"', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'foo'}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with "foo@foo.com"', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'foo@foo.com'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: isLength', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isLength:3"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with undefined', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: undefined}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with null', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: null}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with a number', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 123}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with a string too small', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: "hi"}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with a string too long', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: "foo bar"}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with the right length', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'sup'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: isNumeric', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isNumeric"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with undefined', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: undefined}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with null', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: null}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with a string', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'myValue'}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with a number as string', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: '123'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with an int', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 123}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with a float', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 1.23}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: isWords', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isWords"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with undefined', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: undefined}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with null', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: null}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with a number', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 123}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with a 1 word', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'sup'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass with 2 words', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'sup dude'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: maxLength', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="maxLength:3"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with undefined', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: undefined}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with null', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: null}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with a number', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 123}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass when a string\'s length is smaller', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'hi'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass when a string\'s length is equal', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail when a string\'s length is bigger', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'myValue'}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
var Formsy = require('./../src/main.js');
|
||||
|
||||
describe('Rules: minLength', function() {
|
||||
var TestInput, isValid, form, input;
|
||||
|
||||
beforeEach(function() {
|
||||
isValid = jasmine.createSpy('valid');
|
||||
|
||||
TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="minLength:3"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
TestInput = isValid = isInvalid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with undefined', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: undefined}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with null', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: null}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail with a number', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 123}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail when a string\'s length is smaller', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'hi'}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass when a string\'s length is equal', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass when a string\'s length is bigger', function () {
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'myValue'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -2,6 +2,79 @@ var Formsy = require('./../src/main.js');
|
|||
|
||||
describe('Validation', function() {
|
||||
|
||||
it('should reset only changed form element when external error is passed', function (done) {
|
||||
|
||||
var onSubmit = function (model, reset, invalidate) {
|
||||
invalidate({
|
||||
foo: 'bar',
|
||||
bar: 'foo'
|
||||
});
|
||||
}
|
||||
var TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
var form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onSubmit={onSubmit}>
|
||||
<TestInput name="foo"/>
|
||||
<TestInput name="bar"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
var input = TestUtils.scryRenderedDOMComponentsWithTag(form, 'INPUT')[0];
|
||||
var inputComponents = TestUtils.scryRenderedComponentsWithType(form, TestInput);
|
||||
|
||||
form.submit();
|
||||
expect(inputComponents[0].isValid()).toBe(false);
|
||||
expect(inputComponents[1].isValid()).toBe(false);
|
||||
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
|
||||
setTimeout(function () {
|
||||
expect(inputComponents[0].isValid()).toBe(true);
|
||||
expect(inputComponents[1].isValid()).toBe(false);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('should let normal validation take over when component with external error is changed', function (done) {
|
||||
|
||||
var onSubmit = function (model, reset, invalidate) {
|
||||
invalidate({
|
||||
foo: 'bar'
|
||||
});
|
||||
}
|
||||
var TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
var form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onSubmit={onSubmit}>
|
||||
<TestInput name="foo" validations="isEmail"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
var inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
|
||||
form.submit();
|
||||
expect(inputComponent.isValid()).toBe(false);
|
||||
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
|
||||
setTimeout(function () {
|
||||
expect(inputComponent.getValue()).toBe('bar');
|
||||
expect(inputComponent.isValid()).toBe(false);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('should trigger an onValid handler, if passed, when form is valid', function () {
|
||||
|
||||
var onValid = jasmine.createSpy('valid');
|
||||
|
|
@ -142,166 +215,4 @@ describe('Validation', function() {
|
|||
|
||||
});
|
||||
|
||||
it('RULE: isEmail', function () {
|
||||
|
||||
var isValid = jasmine.createSpy('valid');
|
||||
var TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
var form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value="foo" validations="isEmail"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: 'foo@foo.com'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
it('RULE: isNumeric', function () {
|
||||
|
||||
var isValid = jasmine.createSpy('valid');
|
||||
var TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
var form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value="foo" validations="isNumeric"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: '123'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
it('RULE: isNumeric (actual number)', function () {
|
||||
|
||||
var isValid = jasmine.createSpy('valid');
|
||||
var TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(Number(event.target.value));
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
var form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value="foo" validations="isNumeric"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: '123'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
it('RULE: isNumeric (string representation of a float)', function () {
|
||||
|
||||
var isValid = jasmine.createSpy('valid');
|
||||
var TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
var form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value="foo" validations="isNumeric"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: '1.5'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
it('RULE: isNumeric is false (string representation of an invalid float)', function () {
|
||||
|
||||
var isValid = jasmine.createSpy('valid');
|
||||
var TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
updateValue: function (event) {
|
||||
this.setValue(event.target.value);
|
||||
},
|
||||
render: function () {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>
|
||||
}
|
||||
});
|
||||
var form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value="foo" validations="isNumeric"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
TestUtils.Simulate.change(input, {target: {value: '1.'}});
|
||||
expect(isValid).not.toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
it('RULE: equalsField', function () {
|
||||
|
||||
var TestInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
render: function () {
|
||||
return <input value={this.getValue()}/>
|
||||
}
|
||||
});
|
||||
var form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value="foo" validations="equalsField:bar"/>
|
||||
<TestInput name="bar" value="foo" validations="equalsField:foobar"/>
|
||||
<TestInput name="foobar" value="bar"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
var input = TestUtils.scryRenderedComponentsWithType(form, TestInput);
|
||||
expect(input[0].isValid()).toBe(true);
|
||||
expect(input[1].isValid()).toBe(false);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ module.exports = {
|
|||
_isValid: true,
|
||||
_isPristine: true,
|
||||
_pristineValue: this.props.value,
|
||||
_validationError: ''
|
||||
_validationError: '',
|
||||
_externalError: null
|
||||
};
|
||||
},
|
||||
getDefaultProps: function () {
|
||||
|
|
@ -124,7 +125,7 @@ module.exports = {
|
|||
return this.state._value !== '';
|
||||
},
|
||||
getErrorMessage: function () {
|
||||
return !this.isValid() || this.showRequired() ? this.state._validationError : null;
|
||||
return !this.isValid() || this.showRequired() ? (this.state._externalError || this.state._validationError) : null;
|
||||
},
|
||||
isFormDisabled: function () {
|
||||
return this.props._isFormDisabled();
|
||||
|
|
|
|||
16
src/main.js
16
src/main.js
|
|
@ -76,7 +76,8 @@ Formsy.Form = React.createClass({
|
|||
|
||||
// Update model, submit to url prop and send the model
|
||||
submit: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
event && event.preventDefault();
|
||||
|
||||
// Trigger form as not pristine.
|
||||
// If any inputs have not been touched yet this will make them dirty
|
||||
|
|
@ -134,7 +135,7 @@ Formsy.Form = React.createClass({
|
|||
|
||||
var args = [{
|
||||
_isValid: false,
|
||||
_validationError: errors[name]
|
||||
_externalError: errors[name]
|
||||
}];
|
||||
component.setState.apply(component, args);
|
||||
}.bind(this));
|
||||
|
|
@ -215,7 +216,8 @@ Formsy.Form = React.createClass({
|
|||
component.setState({
|
||||
_isValid: validation.isValid,
|
||||
_isRequired: validation.isRequired,
|
||||
_validationError: validation.error
|
||||
_validationError: validation.error,
|
||||
_externalError: null
|
||||
}, this.validateForm);
|
||||
|
||||
},
|
||||
|
|
@ -223,7 +225,6 @@ Formsy.Form = React.createClass({
|
|||
// Checks validation on current value or a passed value
|
||||
runValidation: function (component, value) {
|
||||
|
||||
|
||||
var currentValues = this.getCurrentValues();
|
||||
var validationErrors = component.props.validationErrors;
|
||||
var validationError = component.props.validationError;
|
||||
|
|
@ -239,6 +240,7 @@ Formsy.Form = React.createClass({
|
|||
|
||||
var isRequired = Object.keys(component._requiredValidations).length ? !!requiredResults.success.length : false;
|
||||
var isValid = !validationResults.failed.length && !(this.props.validationErrors && this.props.validationErrors[component.props.name]);
|
||||
|
||||
return {
|
||||
isRequired: isRequired,
|
||||
isValid: isRequired ? false : isValid,
|
||||
|
|
@ -358,10 +360,14 @@ Formsy.Form = React.createClass({
|
|||
inputKeys.forEach(function (name, index) {
|
||||
var component = inputs[name];
|
||||
var validation = this.runValidation(component);
|
||||
if (validation.isValid && component.state._externalError) {
|
||||
validation.isValid = false;
|
||||
}
|
||||
component.setState({
|
||||
_isValid: validation.isValid,
|
||||
_isRequired: validation.isRequired,
|
||||
_validationError: validation.error
|
||||
_validationError: validation.error,
|
||||
_externalError: !validation.isValid && component.state._externalError ? component.state._externalError : null
|
||||
}, index === inputKeys.length - 1 ? onValidationComplete : null);
|
||||
}.bind(this));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +1,36 @@
|
|||
module.exports = {
|
||||
'isDefaultRequiredValue': function (values, value) {
|
||||
isDefaultRequiredValue: function (values, value) {
|
||||
return value === undefined || value === '';
|
||||
},
|
||||
'hasValue': function (values, value) {
|
||||
return value !== undefined;
|
||||
hasValue: function (values, value) {
|
||||
return !!value;
|
||||
},
|
||||
'matchRegexp': function (values, value, regexp) {
|
||||
return value !== undefined && !!value.match(regexp);
|
||||
matchRegexp: function (values, value, regexp) {
|
||||
return !!value && !!value.match(regexp);
|
||||
},
|
||||
'isUndefined': function (values, value) {
|
||||
isUndefined: function (values, value) {
|
||||
return value === undefined;
|
||||
},
|
||||
'isEmptyString': function (values, value) {
|
||||
isEmptyString: function (values, value) {
|
||||
return value === '';
|
||||
},
|
||||
'isEmail': function (values, value) {
|
||||
isEmail: function (values, value) {
|
||||
return !value || value.match(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i);
|
||||
},
|
||||
'isTrue': function (values, value) {
|
||||
isTrue: function (values, value) {
|
||||
return value === true;
|
||||
},
|
||||
'isFalse': function (values, value) {
|
||||
isFalse: function (values, value) {
|
||||
return value === false;
|
||||
},
|
||||
'isNumeric': function (values, value) {
|
||||
isNumeric: function (values, value) {
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
return true;
|
||||
} else {
|
||||
var matchResults = value !== undefined && value.match(/[-+]?(\d*[.])?\d+/);
|
||||
var matchResults = value.match(/[-+]?(\d*[.])?\d+/);
|
||||
if (!!matchResults) {
|
||||
return matchResults[0] == value;
|
||||
} else {
|
||||
|
|
@ -35,17 +38,17 @@ module.exports = {
|
|||
}
|
||||
}
|
||||
},
|
||||
'isAlpha': function (values, value) {
|
||||
return !value || value.match(/^[a-zA-Z]+$/);
|
||||
isAlpha: function (values, value) {
|
||||
return value && /^[a-zA-Z]+$/.test(value);
|
||||
},
|
||||
'isWords': function (values, value) {
|
||||
return !value || value.match(/^[a-zA-Z\s]+$/);
|
||||
isWords: function (values, value) {
|
||||
return value && /^[a-zA-Z\s]+$/.test(value);
|
||||
},
|
||||
'isSpecialWords': function (values, value) {
|
||||
isSpecialWords: function (values, value) {
|
||||
return !value || value.match(/^[a-zA-Z\s\u00C0-\u017F]+$/);
|
||||
},
|
||||
isLength: function (values, value, length) {
|
||||
return value !== undefined && value.length === length;
|
||||
return value && value.length === length;
|
||||
},
|
||||
equals: function (values, value, eql) {
|
||||
return value == eql;
|
||||
|
|
@ -54,9 +57,9 @@ module.exports = {
|
|||
return value == values[field];
|
||||
},
|
||||
maxLength: function (values, value, length) {
|
||||
return value !== undefined && value.length <= length;
|
||||
return value && value.length && value.length <= length;
|
||||
},
|
||||
minLength: function (values, value, length) {
|
||||
return value !== undefined && value.length >= length;
|
||||
return value && value.length && value.length >= length;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue