Compare commits
82 Commits
react-0.14
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
ebd84bb026 | |
|
|
7dc68fc633 | |
|
|
a20da5b7cd | |
|
|
c5dfa4b31a | |
|
|
f1ba9d417e | |
|
|
57f97cb045 | |
|
|
ac301f8950 | |
|
|
d68586180a | |
|
|
f395839e2c | |
|
|
73dd46b5e3 | |
|
|
84cdcb117c | |
|
|
c56e8c3328 | |
|
|
2b249113d8 | |
|
|
15493dce67 | |
|
|
89dbed0468 | |
|
|
168521e578 | |
|
|
42ba9616d2 | |
|
|
6b167cbfe1 | |
|
|
24a6b6217d | |
|
|
d6950885a1 | |
|
|
3cdcdf57ce | |
|
|
1800442ea1 | |
|
|
da8f041eca | |
|
|
9e923dd0dc | |
|
|
89a2d4287b | |
|
|
6767a6b9eb | |
|
|
d84397906b | |
|
|
112819f699 | |
|
|
4931256105 | |
|
|
7658d06cc8 | |
|
|
1df3e3520f | |
|
|
fec4576d1b | |
|
|
b39fd2ed74 | |
|
|
18467a94a1 | |
|
|
d5268a4eef | |
|
|
5b5bd0fb67 | |
|
|
46c1f2c250 | |
|
|
dcac495d79 | |
|
|
c4fa202ebf | |
|
|
7481b6da64 | |
|
|
fbd09119d3 | |
|
|
f67f8317c9 | |
|
|
59bde8324c | |
|
|
8636cdabc3 | |
|
|
cfebf17aea | |
|
|
6bcdb61b27 | |
|
|
300a53f172 | |
|
|
36b5dd1dab | |
|
|
8cf8409e3a | |
|
|
e4d35f999b | |
|
|
78b2ada909 | |
|
|
2a384f40a6 | |
|
|
b797979873 | |
|
|
13615e82e4 | |
|
|
2639319f9b | |
|
|
2be44f1b32 | |
|
|
97923876d9 | |
|
|
9fb4b93fec | |
|
|
dd15a840a0 | |
|
|
6f2a21e3ef | |
|
|
5bfa7e53f1 | |
|
|
4ca7a57af7 | |
|
|
3bd3ad699e | |
|
|
19e28c6437 | |
|
|
2846f0fadd | |
|
|
4670a9cc1f | |
|
|
2c6f7fe8f0 | |
|
|
404f696bfb | |
|
|
e72f34a3d1 | |
|
|
43a8f66150 | |
|
|
f559c8f9d4 | |
|
|
bf77058a87 | |
|
|
32aac21a4e | |
|
|
349d5c7922 | |
|
|
523ab69a4e | |
|
|
a8dd273148 | |
|
|
3791b1976f | |
|
|
7f6ab4f52c | |
|
|
6b521d35e7 | |
|
|
c311e144fb | |
|
|
c04623ae05 | |
|
|
dcac01159a |
|
|
@ -1,4 +1,2 @@
|
|||
.DS_Store
|
||||
build
|
||||
node_modules
|
||||
lib
|
||||
|
|
|
|||
11
.npmignore
11
.npmignore
|
|
@ -1,3 +1,8 @@
|
|||
build/
|
||||
bower.json
|
||||
Gulpfile.js
|
||||
.babelrc
|
||||
.editorconfig
|
||||
.travis.yml
|
||||
testrunner.js
|
||||
webpack.production.config.js
|
||||
examples/
|
||||
release/
|
||||
tests/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '0.12'
|
||||
- '0.10'
|
||||
- '4.1'
|
||||
|
|
|
|||
227
API.md
227
API.md
|
|
@ -1,6 +1,5 @@
|
|||
# API
|
||||
|
||||
- [Formsy.defaults - DEPRECATED](#formsydefaults)
|
||||
- [Formsy.Form](#formsyform)
|
||||
- [className](#classname)
|
||||
- [mapping](#mapping)
|
||||
|
|
@ -12,19 +11,21 @@
|
|||
- [onInvalidSubmit()](#oninvalidsubmit)
|
||||
- [onChange()](#onchange)
|
||||
- [reset()](#resetform)
|
||||
- [getModel()](#getmodel)
|
||||
- [updateInputsWithError()](#updateinputswitherrorerrors)
|
||||
- [preventExternalInvalidation](#preventexternalinvalidation)
|
||||
- [Formsy.Mixin](#formsymixin)
|
||||
- [name](#name)
|
||||
- [value](#value)
|
||||
- [validations](#validations)
|
||||
- [validationError](#validationerror)
|
||||
- [validationErrors](#validationerrors)
|
||||
- [validationErrors](#validationerrors-1)
|
||||
- [required](#required)
|
||||
- [getValue()](#getvalue)
|
||||
- [setValue()](#setvalue)
|
||||
- [hasValue() - DEPRECATED](#hasvalue)
|
||||
- [resetValue()](#resetvalue)
|
||||
- [getErrorMessage()](#geterrormessage)
|
||||
- [getErrorMessages()](#geterrormessages)
|
||||
- [isValid()](#isvalid)
|
||||
- [isValidValue()](#isvalidvalue)
|
||||
- [isRequired()](#isrequired)
|
||||
|
|
@ -36,22 +37,21 @@
|
|||
- [validate](#validate)
|
||||
- [formNoValidate](#formnovalidate)
|
||||
- [Formsy.HOC](#formsyhoc)
|
||||
- [innerRef](#innerRef)
|
||||
- [Formsy.Decorator](#formsydecorator)
|
||||
- [Formsy.addValidationRule](#formsyaddvalidationrule)
|
||||
- [Validators](#validators)
|
||||
|
||||
### <a name="formsydefaults">Formsy.defaults(options) - DEPRECATED</a>
|
||||
|
||||
### <a name="formsyform">Formsy.Form</a>
|
||||
|
||||
#### <a name="classname">className</a>
|
||||
```html
|
||||
```jsx
|
||||
<Formsy.Form className="my-class"></Formsy.Form>
|
||||
```
|
||||
Sets a class name on the form itself.
|
||||
|
||||
#### <a name="mapping">mapping</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyForm = React.createClass({
|
||||
mapInputs: function (inputs) {
|
||||
return {
|
||||
|
|
@ -77,7 +77,7 @@ Use mapping to change the data structure of your input elements. This structure
|
|||
#### <a name="validationerrors">validationErrors</a>
|
||||
You can manually pass down errors to your form. In combination with `onChange` you are able to validate using an external validator.
|
||||
|
||||
```js
|
||||
```jsx
|
||||
var Form = React.createClass({
|
||||
getInitialState: function () {
|
||||
return {
|
||||
|
|
@ -108,45 +108,45 @@ var Form = React.createClass({
|
|||
```
|
||||
|
||||
#### <a name="onsubmit">onSubmit(data, resetForm, invalidateForm)</a>
|
||||
```html
|
||||
```jsx
|
||||
<Formsy.Form onSubmit={this.showFormLoader}></Formsy.Form>
|
||||
```
|
||||
Takes a function to run when the submit button has been clicked.
|
||||
|
||||
The first argument is the data of the form. The second argument will reset the form. The third argument will invalidate the form by taking an object that maps to inputs. E.g. `{email: "This email is taken"}`. Resetting or invalidating the form will cause **setState** to run on the form element component.
|
||||
The first argument is the data of the form. The second argument will reset the form. The third argument will invalidate the form by taking an object that maps to inputs. This is useful for server side validation. E.g. `{email: "This email is taken"}`. Resetting or invalidating the form will cause **setState** to run on the form element component.
|
||||
|
||||
#### <a name="onvalid">onValid()</a>
|
||||
```html
|
||||
```jsx
|
||||
<Formsy.Form onValid={this.enableSubmitButton}></Formsy.Form>
|
||||
```
|
||||
Whenever the form becomes valid the "onValid" handler is called. Use it to change state of buttons or whatever your heart desires.
|
||||
|
||||
#### <a name="oninvalid">onInvalid()</a>
|
||||
```html
|
||||
```jsx
|
||||
<Formsy.Form onInvalid={this.disableSubmitButton}></Formsy.Form>
|
||||
```
|
||||
Whenever the form becomes invalid the "onInvalid" handler is called. Use it to for example revert "onValid" state.
|
||||
|
||||
#### <a name="onvalidsubmit">onValidSubmit(model, resetForm, invalidateForm)</a>
|
||||
```html
|
||||
```jsx
|
||||
<Formsy.Form onValidSubmit={this.sendToServer}></Formsy.Form>
|
||||
```
|
||||
Triggers when form is submitted with a valid state. The arguments are the same as on `onSubmit`.
|
||||
|
||||
#### <a name="oninvalidsubmit">onInvalidSubmit(model, resetForm, invalidateForm)</a>
|
||||
```html
|
||||
```jsx
|
||||
<Formsy.Form onInvalidSubmit={this.notifyFormError}></Formsy.Form>
|
||||
```
|
||||
Triggers when form is submitted with an invalid state. The arguments are the same as on `onSubmit`.
|
||||
|
||||
#### <a name="onchange">onChange(currentValues, isChanged)</a>
|
||||
```html
|
||||
```jsx
|
||||
<Formsy.Form onChange={this.saveCurrentValuesToLocalStorage}></Formsy.Form>
|
||||
```
|
||||
"onChange" triggers when setValue is called on your form elements. It is also triggered when dynamic form elements have been added to the form. The "currentValues" is an object where the key is the name of the input and the value is the current value. The second argument states if the forms initial values actually has changed.
|
||||
|
||||
#### <a name="resetform">reset(values)</a>
|
||||
```html
|
||||
```jsx
|
||||
var MyForm = React.createClass({
|
||||
resetForm: function () {
|
||||
this.refs.form.reset();
|
||||
|
|
@ -162,8 +162,45 @@ var MyForm = React.createClass({
|
|||
```
|
||||
Manually reset the form to its pristine state. You can also pass an object that inserts new values into the inputs. Keys are name of input and value is of course the value.
|
||||
|
||||
#### <a name="getmodel">getModel()</a>
|
||||
```jsx
|
||||
var MyForm = React.createClass({
|
||||
getMyData: function () {
|
||||
alert(this.refs.form.getModel());
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<Formsy.Form ref="form">
|
||||
...
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
Manually get values from all registered components. Keys are name of input and value is of course the value.
|
||||
|
||||
#### <a name="updateInputsWithError">updateInputsWithError(errors)</a>
|
||||
```jsx
|
||||
var MyForm = React.createClass({
|
||||
someFunction: function () {
|
||||
this.refs.form.updateInputsWithError({
|
||||
email: 'This email is taken',
|
||||
'field[10]': 'Some error!'
|
||||
});
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<Formsy.Form ref="form">
|
||||
...
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
Manually invalidate the form by taking an object that maps to inputs. This is useful for server side validation. You can also use a third parameter to the [`onSubmit`](#onsubmitdata-resetform-invalidateform), [`onValidSubmit`](#onvalidsubmitmodel-resetform-invalidateform) or [`onInvalidSubmit`](#oninvalidsubmitmodel-resetform-invalidateform).
|
||||
|
||||
#### <a name="preventExternalInvalidation">preventExternalInvalidation</a>
|
||||
```html
|
||||
```jsx
|
||||
var MyForm = React.createClass({
|
||||
onSubmit: function (model, reset, invalidate) {
|
||||
invalidate({
|
||||
|
|
@ -184,20 +221,20 @@ With the `preventExternalInvalidation` the input will not be invalidated though
|
|||
### <a name="formsymixin">Formsy.Mixin</a>
|
||||
|
||||
#### <a name="name">name</a>
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="email"/>
|
||||
<MyInputComponent name="address.street"/>
|
||||
```
|
||||
The name is required to register the form input component in the form. You can also use dot notation. This will result in the "form model" being a nested object. `{email: 'value', address: {street: 'value'}}`.
|
||||
|
||||
#### <a name="value">value</a>
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="email" value="My initial value"/>
|
||||
```
|
||||
You should always use the [**getValue()**](#getvalue) method inside your formsy form element. To pass an initial value, use the value attribute. This value will become the "pristine" value and any reset of the form will bring back this value.
|
||||
|
||||
#### <a name="validations">validations</a>
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="email" validations="isEmail"/>
|
||||
<MyInputComponent name="number" validations="isNumeric,isLength:5"/>
|
||||
<MyInputComponent name="number" validations={{
|
||||
|
|
@ -212,22 +249,22 @@ You should always use the [**getValue()**](#getvalue) method inside your formsy
|
|||
}
|
||||
}}/>
|
||||
```
|
||||
An comma separated list with validation rules. Take a look at [**Validators**](#validators) to see default rules. Use ":" to separate argument passed to the validator. The argument will go through a **JSON.parse** converting them into correct JavaScript types. Meaning:
|
||||
A comma separated list with validation rules. Take a look at [**Validators**](#validators) to see default rules. Use ":" to separate argument passed to the validator. The argument will go through a **JSON.parse** converting them into correct JavaScript types. Meaning:
|
||||
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="fruit" validations="isIn:['apple', 'orange']"/>
|
||||
<MyInputComponent name="car" validations="mapsTo:{'bmw': true, 'vw': true}"/>
|
||||
```
|
||||
Works just fine.
|
||||
|
||||
#### <a name="validationerror">validationError</a>
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="email" validations="isEmail" validationError="This is not an email"/>
|
||||
```
|
||||
The message that will show when the form input component is invalid. It will be used as a default error.
|
||||
|
||||
#### <a name="validationerrors">validationErrors</a>
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent
|
||||
name="email"
|
||||
validations={{
|
||||
|
|
@ -243,19 +280,19 @@ The message that will show when the form input component is invalid. It will be
|
|||
The message that will show when the form input component is invalid. You can combine this with `validationError`. Keys not found in `validationErrors` defaults to the general error message.
|
||||
|
||||
#### <a name="required">required</a>
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="email" validations="isEmail" validationError="This is not an email" required/>
|
||||
```
|
||||
|
||||
A property that tells the form that the form input component value is required. By default it uses `isDefaultRequiredValue`, but you can define your own definition of what defined a required state.
|
||||
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="email" required="isFalse"/>
|
||||
```
|
||||
Would be typical for a checkbox type of form element.
|
||||
Would be typical for a checkbox type of form element that must be checked, e.g. agreeing to Terms of Service.
|
||||
|
||||
#### <a name="getvalue">getValue()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
render: function () {
|
||||
|
|
@ -268,7 +305,7 @@ var MyInput = React.createClass({
|
|||
Gets the current value of the form input component.
|
||||
|
||||
#### <a name="setvalue">setValue(value)</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -283,27 +320,8 @@ var MyInput = React.createClass({
|
|||
```
|
||||
Sets the value of your form input component. Notice that it does not have to be a text input. Anything can set a value on the component. Think calendars, checkboxes, autocomplete stuff etc. Running this method will trigger a **setState()** on the component and do a render.
|
||||
|
||||
#### <a name="hasvalue">hasValue() - DEPRECATED</a>
|
||||
```javascript
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
this.setValue(event.currentTarget.value);
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<div>
|
||||
<input type="text" onChange={this.changeValue} value={this.getValue()}/>
|
||||
{this.hasValue() ? 'There is a value here' : 'No value entered yet'}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
The hasValue() method helps you identify if there actually is a value or not. The only invalid value in Formsy is an empty string, "". All other values are valid as they could be something you want to send to the server. F.ex. the number zero (0), or false.
|
||||
|
||||
#### <a name="resetvalue">resetValue()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -322,7 +340,7 @@ var MyInput = React.createClass({
|
|||
Resets to empty value. This will run a **setState()** on the component and do a render.
|
||||
|
||||
#### <a name="geterrormessage">getErrorMessage()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -340,8 +358,11 @@ var MyInput = React.createClass({
|
|||
```
|
||||
Will return the validation message set if the form input component is invalid. If form input component is valid it returns **null**.
|
||||
|
||||
#### <a name="geterrormessages">getErrorMessages()</a>
|
||||
Will return the validation messages set if the form input component is invalid. If form input component is valid it returns empty array.
|
||||
|
||||
#### <a name="isvalid">isValid()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -364,7 +385,7 @@ Returns the valid state of the form input component.
|
|||
#### <a name="isvalidvalue">isValidValue()</a>
|
||||
You can pre-verify a value against the passed validators to the form element.
|
||||
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -389,7 +410,7 @@ var MyForm = React.createClass({
|
|||
```
|
||||
|
||||
#### <a name="isrequired">isRequired()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -409,7 +430,7 @@ var MyInput = React.createClass({
|
|||
Returns true if the required property has been passed.
|
||||
|
||||
#### <a name="showrequired">showRequired()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -429,7 +450,7 @@ var MyInput = React.createClass({
|
|||
Lets you check if the form input component should indicate if it is a required field. This happens when the form input component value is empty and the required prop has been passed.
|
||||
|
||||
#### <a name="showerror">showError()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -449,7 +470,7 @@ var MyInput = React.createClass({
|
|||
Lets you check if the form input component should indicate if there is an error. This happens if there is a form input component value and it is invalid or if a server error is received.
|
||||
|
||||
#### <a name="ispristine">isPristine()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -470,7 +491,7 @@ By default all formsy input elements are pristine, which means they are not "tou
|
|||
**note!** When the form is reset, using the resetForm callback function on for example [**onSubmit**](#onsubmitdata-resetform-invalidateform) the inputs are reset to their pristine state.
|
||||
|
||||
#### <a name="isformdisabled">isFormDisabled()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
render: function () {
|
||||
|
|
@ -487,7 +508,7 @@ React.render(<Formy.Form disabled={true}/>);
|
|||
You can now disable the form itself with a prop and use **isFormDisabled()** inside form elements to verify this prop.
|
||||
|
||||
#### <a name="isformsubmitted">isFormSubmitted()</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
render: function () {
|
||||
|
|
@ -504,7 +525,7 @@ var MyInput = React.createClass({
|
|||
You can check if the form has been submitted.
|
||||
|
||||
#### <a name="validate">validate</a>
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
changeValue: function (event) {
|
||||
|
|
@ -528,7 +549,7 @@ You can create custom validation inside a form element. The validate method defi
|
|||
|
||||
#### <a name="formnovalidate">formNoValidate</a>
|
||||
To avoid native validation behavior on inputs, use the React `formNoValidate` property.
|
||||
```javascript
|
||||
```jsx
|
||||
var MyInput = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
render: function () {
|
||||
|
|
@ -543,10 +564,10 @@ var MyInput = React.createClass({
|
|||
|
||||
### <a name="formsyhoc">Formsy.HOC</a>
|
||||
The same methods as the mixin are exposed to the HOC version of the element component, though through the `props`, not on the instance.
|
||||
```js
|
||||
```jsx
|
||||
import {HOC} from 'formsy-react';
|
||||
|
||||
class MyInput extends React.Component {
|
||||
class MyInputHoc extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -555,12 +576,31 @@ class MyInput extends React.Component {
|
|||
);
|
||||
}
|
||||
};
|
||||
export default HOC(MyInput);
|
||||
export default HOC(MyInputHoc);
|
||||
```
|
||||
|
||||
#### <a name="innerRef">innerRef</a>
|
||||
|
||||
Use an `innerRef` prop to get a reference to your DOM node.
|
||||
|
||||
```jsx
|
||||
var MyForm = React.createClass({
|
||||
componentDidMount() {
|
||||
this.searchInput.focus()
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<MyInputHoc name="search" innerRef={(c) => { this.searchInput = c; }} />
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### <a name="formsydecorator">Formsy.Decorator</a>
|
||||
The same methods as the mixin are exposed to the decorator version of the element component, though through the `props`, not on the instance.
|
||||
```js
|
||||
```jsx
|
||||
import {Decorator as FormsyElement} from 'formsy-react';
|
||||
|
||||
@FormsyElement()
|
||||
|
|
@ -578,25 +618,25 @@ export default MyInput
|
|||
|
||||
### <a name="formsyaddvalidationrule">Formsy.addValidationRule(name, ruleFunc)</a>
|
||||
An example:
|
||||
```javascript
|
||||
```jsx
|
||||
Formsy.addValidationRule('isFruit', function (values, value) {
|
||||
return ['apple', 'orange', 'pear'].indexOf(value) >= 0;
|
||||
});
|
||||
```
|
||||
```html
|
||||
<MyInputComponent name="fruit" validations="'isFruit"/>
|
||||
```jsx
|
||||
<MyInputComponent name="fruit" validations="isFruit"/>
|
||||
```
|
||||
Another example:
|
||||
```javascript
|
||||
```jsx
|
||||
Formsy.addValidationRule('isIn', function (values, value, array) {
|
||||
return array.indexOf(value) >= 0;
|
||||
});
|
||||
```
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="fruit" validations="isIn:['apple', 'orange', 'pear']"/>
|
||||
```
|
||||
Cross input validation:
|
||||
```javascript
|
||||
```jsx
|
||||
Formsy.addValidationRule('isMoreThan', function (values, value, otherField) {
|
||||
// The this context points to an object containing the values
|
||||
// {childAge: "", parentAge: "5"}
|
||||
|
|
@ -604,130 +644,133 @@ Formsy.addValidationRule('isMoreThan', function (values, value, otherField) {
|
|||
return Number(value) > Number(values[otherField]);
|
||||
});
|
||||
```
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="childAge"/>
|
||||
<MyInputComponent name="parentAge" validations="isMoreThan:childAge"/>
|
||||
```
|
||||
## <a name="validators">Validators</a>
|
||||
**matchRegexp**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations={{
|
||||
matchRegexp: /foo/
|
||||
}}/>
|
||||
```
|
||||
Returns true if the value is thruthful
|
||||
|
||||
_For more complicated regular expressions (emoji, international characters) you can use [xregexp](https://github.com/slevithan/xregexp). See [this comment](https://github.com/christianalfoni/formsy-react/issues/407#issuecomment-266306783) for an example._
|
||||
|
||||
**isEmail**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isEmail"/>
|
||||
```
|
||||
Return true if it is an email
|
||||
|
||||
**isUrl**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isUrl"/>
|
||||
```
|
||||
Return true if it is an url
|
||||
|
||||
**isExisty**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isExisty"/>
|
||||
```
|
||||
Returns true if the value is not undefined or null
|
||||
|
||||
**isUndefined**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isUndefined"/>
|
||||
```
|
||||
Returns true if the value is the undefined
|
||||
|
||||
**isEmptyString**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isEmptyString"/>
|
||||
```
|
||||
Returns true if the value is an empty string
|
||||
|
||||
**isTrue**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isTrue"/>
|
||||
```
|
||||
Returns true if the value is the boolean true
|
||||
|
||||
**isFalse**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isFalse"/>
|
||||
```
|
||||
Returns true if the value is the boolean false
|
||||
|
||||
**isAlpha**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isAlpha"/>
|
||||
```
|
||||
Returns true if string is only letters
|
||||
|
||||
**isNumeric**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isNumeric"/>
|
||||
```
|
||||
Returns true if string only contains numbers. Examples: 42; -3.14
|
||||
|
||||
**isAlphanumeric**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isAlphanumeric"/>
|
||||
```
|
||||
Returns true if string only contains letters or numbers
|
||||
|
||||
**isInt**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isInt"/>
|
||||
```
|
||||
Returns true if string represents integer value. Examples: 42; -12; 0
|
||||
|
||||
**isFloat**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isFloat"/>
|
||||
```
|
||||
Returns true if string represents float value. Examples: 42; -3.14; 1e3
|
||||
|
||||
**isWords**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isWords"/>
|
||||
```
|
||||
Returns true if string is only letters, including spaces and tabs
|
||||
|
||||
**isSpecialWords**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isSpecialWords"/>
|
||||
```
|
||||
Returns true if string is only letters, including special letters (a-z,ú,ø,æ,å)
|
||||
|
||||
**equals:value**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="equals:4"/>
|
||||
```
|
||||
Return true if the value from input component matches value passed (==).
|
||||
|
||||
**equalsField:fieldName**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="password"/>
|
||||
<MyInputComponent name="repeated_password" validations="equalsField:password"/>
|
||||
```
|
||||
Return true if the value from input component matches value passed (==).
|
||||
|
||||
**isLength:length**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="foo" validations="isLength:8"/>
|
||||
```
|
||||
Returns true if the value length is the equal.
|
||||
|
||||
**minLength:length**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="number" validations="minLength:1"/>
|
||||
```
|
||||
Return true if the value is more or equal to argument
|
||||
Return true if the value is more or equal to argument.
|
||||
**Also returns true for an empty value.** If you want to get false, then you should use [`required`](#required) additionally.
|
||||
|
||||
**maxLength:length**
|
||||
```html
|
||||
```jsx
|
||||
<MyInputComponent name="number" validations="maxLength:5"/>
|
||||
```
|
||||
Return true if the value is less or equal to argument
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Christian Alfoni
|
||||
Copyright (c) 2014-2016 PatientSky A/S
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
77
README.md
77
README.md
|
|
@ -6,10 +6,6 @@ A form input builder and validator for React JS
|
|||
| [How to use](#how-to-use) | [API](/API.md) | [Examples](/examples) |
|
||||
|---|---|---|
|
||||
|
||||
### Currently, the development is in 'react-0.14' branch. For more information see [#158](https://github.com/christianalfoni/formsy-react/issues/158)
|
||||
|
||||
### From version 0.12.0 Formsy only supports React 0.13.1 and up
|
||||
|
||||
## <a name="background">Background</a>
|
||||
I wrote an article on forms and validation with React JS, [Nailing that validation with React JS](http://christianalfoni.github.io/javascript/2014/10/22/nailing-that-validation-with-reactjs.html), the result of that was this extension.
|
||||
|
||||
|
|
@ -28,7 +24,7 @@ The main concept is that forms, inputs and validation is done very differently a
|
|||
5. You can dynamically add form elements to your form and they will register/unregister to the form
|
||||
|
||||
## Default elements
|
||||
You can look at examples in this repo or use the [formsy-react-components](https://github.com/twisty/formsy-react-components) project to use bootstrap with formsy-react.
|
||||
You can look at examples in this repo or use the [formsy-react-components](https://github.com/twisty/formsy-react-components) project to use bootstrap with formsy-react, or use [formsy-material-ui](https://github.com/mbrookes/formsy-material-ui) to use [Material-UI](http://material-ui.com/) with formsy-react.
|
||||
|
||||
## Install
|
||||
|
||||
|
|
@ -44,30 +40,35 @@ You can look at examples in this repo or use the [formsy-react-components](https
|
|||
|
||||
## How to use
|
||||
|
||||
See [`examples` folder](/examples) for examples.
|
||||
See [`examples` folder](/examples) for examples. [Codepen demo](http://codepen.io/semigradsky/pen/dYYpwv?editors=001).
|
||||
|
||||
Complete API reference is available [here](/API.md).
|
||||
|
||||
#### Formsy gives you a form straight out of the box
|
||||
|
||||
```javascript
|
||||
/** @jsx React.DOM */
|
||||
var Formsy = require('formsy-react');
|
||||
var MyAppForm = React.createClass({
|
||||
enableButton: function () {
|
||||
```jsx
|
||||
import Formsy from 'formsy-react';
|
||||
|
||||
const MyAppForm = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
canSubmit: false
|
||||
}
|
||||
},
|
||||
enableButton() {
|
||||
this.setState({
|
||||
canSubmit: true
|
||||
});
|
||||
},
|
||||
disableButton: function () {
|
||||
disableButton() {
|
||||
this.setState({
|
||||
canSubmit: false
|
||||
});
|
||||
},
|
||||
submit: function (model) {
|
||||
submit(model) {
|
||||
someDep.saveEmail(model.email);
|
||||
},
|
||||
render: function () {
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onValidSubmit={this.submit} onValid={this.enableButton} onInvalid={this.disableButton}>
|
||||
<MyOwnInput name="email" validations="isEmail" validationError="This is not a valid email" required/>
|
||||
|
|
@ -81,31 +82,31 @@ Complete API reference is available [here](/API.md).
|
|||
This code results in a form with a submit button that will run the `submit` method when the submit button is clicked with a valid email. The submit button is disabled as long as the input is empty ([required](/API.md#required)) or the value is not an email ([isEmail](/API.md#validators)). On validation error it will show the message: "This is not a valid email".
|
||||
|
||||
#### Building a form element (required)
|
||||
```javascript
|
||||
/** @jsx React.DOM */
|
||||
var Formsy = require('formsy-react');
|
||||
var MyOwnInput = React.createClass({
|
||||
```jsx
|
||||
import Formsy from 'formsy-react';
|
||||
|
||||
const MyOwnInput = React.createClass({
|
||||
|
||||
// Add the Formsy Mixin
|
||||
mixins: [Formsy.Mixin],
|
||||
|
||||
// setValue() will set the value of the component, which in
|
||||
// turn will validate it and the rest of the form
|
||||
changeValue: function (event) {
|
||||
changeValue(event) {
|
||||
this.setValue(event.currentTarget.value);
|
||||
},
|
||||
render: function () {
|
||||
|
||||
render() {
|
||||
// Set a specific className based on the validation
|
||||
// state of this component. showRequired() is true
|
||||
// when the value is empty and the required prop is
|
||||
// passed to the input. showError() is true when the
|
||||
// value typed is invalid
|
||||
var className = this.showRequired() ? 'required' : this.showError() ? 'error' : null;
|
||||
const className = this.showRequired() ? 'required' : this.showError() ? 'error' : null;
|
||||
|
||||
// An error message is returned ONLY if the component is invalid
|
||||
// or the server has returned an error message
|
||||
var errorMessage = this.getErrorMessage();
|
||||
const errorMessage = this.getErrorMessage();
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
|
|
@ -119,39 +120,19 @@ This code results in a form with a submit button that will run the `submit` meth
|
|||
The form element component is what gives the form validation functionality to whatever you want to put inside this wrapper. You do not have to use traditional inputs, it can be anything you want and the value of the form element can also be anything you want. As you can see it is very flexible, you just have a small API to help you identify the state of the component and set its value.
|
||||
|
||||
## Related projects
|
||||
- [formsy-react-components](https://github.com/twisty/formsy-react-components) - A set of React JS components for use in a formsy-react form
|
||||
- [formsy-material-ui](https://github.com/mbrookes/formsy-material-ui) - A formsy-react compatibility wrapper for [Material-UI](http://material-ui.com/) form components.
|
||||
- [formsy-react-components](https://github.com/twisty/formsy-react-components) - A set of React JS components for use in a formsy-react form.
|
||||
- ...
|
||||
- Send PR for adding your project to this list!
|
||||
|
||||
## Contribute
|
||||
- Fork repo
|
||||
- `npm install`
|
||||
- `npm start` runs the development server on `localhost:8080`
|
||||
- `npm run examples` runs the development server on `localhost:8080`
|
||||
- `npm test` runs the tests
|
||||
|
||||
License
|
||||
-------
|
||||
## License
|
||||
|
||||
formsy-react is licensed under the [MIT license](LICENSE).
|
||||
[The MIT License (MIT)](/LICENSE)
|
||||
|
||||
> The MIT License (MIT)
|
||||
>
|
||||
> Copyright (c) 2015 Gloppens EDB Lag
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
||||
Copyright (c) 2014-2016 PatientSky A/S
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "formsy-react",
|
||||
"version": "0.14.1",
|
||||
"version": "0.18.0",
|
||||
"description": "A form input builder and validator for React JS",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
"Gulpfile.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"react": "^0.13.1"
|
||||
"react": "^0.14.7 || ^15.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"react",
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Formsy Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="build.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
var React = require('react');
|
||||
var ReactDOM = require('react-dom');
|
||||
var Formsy = require('./../src/main.js');
|
||||
|
||||
var Input = React.createClass({
|
||||
onChange: function (event) {
|
||||
this.props.setValue(event.currentTarget.value);
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<div>
|
||||
{this.props.showRequired() ? 'required' : ''}
|
||||
<input disabled={this.props.isFormDisabled()} value={this.props.getValue()} onChange={this.onChange}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Input = Formsy.HOC(Input);
|
||||
|
||||
var SomeComp = React.createClass({
|
||||
getInitialState: function () {
|
||||
return {
|
||||
isRequired: false
|
||||
};
|
||||
},
|
||||
toggleRequired: function () {
|
||||
this.setState({
|
||||
isRequired: !this.state.isRequired
|
||||
});
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<div>
|
||||
<Input name="foo[0]" value={''} validations="isEmail" validationError="No email" required={this.state.isRequired}/>
|
||||
<button onClick={this.toggleRequired}>Test</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
var FormApp = React.createClass({
|
||||
onSubmit: function (model) {
|
||||
console.log('model', model);
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<Formsy.Form ref="form" onSubmit={this.onSubmit}>
|
||||
<SomeComp/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ReactDOM.render(<FormApp />, document.getElementById('app'));
|
||||
|
|
@ -34,3 +34,7 @@ If it is not helped try update your node.js and npm.
|
|||
3. [**Reset Values**](reset-values)
|
||||
|
||||
Reset text input, checkbox and select to their pristine values.
|
||||
|
||||
4. [**Dynamic Form Fields**](dynamic-form-fields)
|
||||
|
||||
Dynamically adding and removing fields to form.
|
||||
|
|
|
|||
|
|
@ -18,14 +18,15 @@ const MyInput = React.createClass({
|
|||
// when the value is empty and the required prop is
|
||||
// passed to the input. showError() is true when the
|
||||
// value typed is invalid
|
||||
const className = this.props.className + ' ' + (this.showRequired() ? 'required' : this.showError() ? 'error' : null);
|
||||
const className = 'form-group' + (this.props.className || ' ') +
|
||||
(this.showRequired() ? 'required' : this.showError() ? 'error' : '');
|
||||
|
||||
// An error message is returned ONLY if the component is invalid
|
||||
// or the server has returned an error message
|
||||
const errorMessage = this.getErrorMessage();
|
||||
|
||||
return (
|
||||
<div className='form-group'>
|
||||
<div className={className}>
|
||||
<label htmlFor={this.props.name}>{this.props.title}</label>
|
||||
<input
|
||||
type={this.props.type || 'text'}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import Formsy from 'formsy-react';
|
||||
|
||||
function contains(container, item, cmp) {
|
||||
for (const it of container) {
|
||||
if (cmp(it, item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const MyRadioGroup = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
getInitialState() {
|
||||
return { value: [], cmp: (a, b) => a === b };
|
||||
},
|
||||
componentDidMount() {
|
||||
const value = this.props.value || [];
|
||||
this.setValue(value);
|
||||
this.setState({ value: value, cmp: this.props.cmp || this.state.cmp });
|
||||
},
|
||||
|
||||
changeValue(value, event) {
|
||||
const checked = event.currentTarget.checked;
|
||||
|
||||
let newValue = [];
|
||||
if (checked) {
|
||||
newValue = this.state.value.concat(value);
|
||||
} else {
|
||||
newValue = this.state.value.filter(it => !this.state.cmp(it, value));
|
||||
}
|
||||
|
||||
this.setValue(newValue);
|
||||
this.setState({ value: newValue });
|
||||
},
|
||||
|
||||
render() {
|
||||
const className = 'form-group' + (this.props.className || ' ') +
|
||||
(this.showRequired() ? 'required' : this.showError() ? 'error' : '');
|
||||
const errorMessage = this.getErrorMessage();
|
||||
|
||||
const { name, title, items } = this.props;
|
||||
return (
|
||||
<div className={className}>
|
||||
<label htmlFor={name}>{title}</label>
|
||||
{items.map((item, i) => (
|
||||
<div key={i}>
|
||||
<input
|
||||
type="checkbox"
|
||||
name={name}
|
||||
onChange={this.changeValue.bind(this, item)}
|
||||
checked={contains(this.state.value, item, this.state.cmp)}
|
||||
/>
|
||||
<span>{JSON.stringify(item)}</span>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<span className='validation-error'>{errorMessage}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
export default MyRadioGroup;
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import React from 'react';
|
||||
import Formsy from 'formsy-react';
|
||||
|
||||
const MyRadioGroup = React.createClass({
|
||||
mixins: [Formsy.Mixin],
|
||||
|
||||
componentDidMount() {
|
||||
const value = this.props.value;
|
||||
this.setValue(value);
|
||||
this.setState({ value });
|
||||
},
|
||||
|
||||
changeValue(value) {
|
||||
this.setValue(value);
|
||||
this.setState({ value });
|
||||
},
|
||||
|
||||
render() {
|
||||
const className = 'form-group' + (this.props.className || ' ') +
|
||||
(this.showRequired() ? 'required' : this.showError() ? 'error' : '');
|
||||
const errorMessage = this.getErrorMessage();
|
||||
|
||||
const { name, title, items } = this.props;
|
||||
return (
|
||||
<div className={className}>
|
||||
<label htmlFor={name}>{title}</label>
|
||||
{items.map((item, i) => (
|
||||
<div key={i}>
|
||||
<input
|
||||
type="radio"
|
||||
name={name}
|
||||
onChange={this.changeValue.bind(this, item)}
|
||||
checked={this.state.value === item}
|
||||
/>
|
||||
<span>{item.toString()}</span>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<span className='validation-error'>{errorMessage}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
export default MyRadioGroup;
|
||||
|
|
@ -9,7 +9,8 @@ const MySelect = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
const className = this.props.className + ' ' + (this.showRequired() ? 'required' : this.showError() ? 'error' : null);
|
||||
const className = 'form-group' + (this.props.className || ' ') +
|
||||
(this.showRequired() ? 'required' : this.showError() ? 'error' : '');
|
||||
const errorMessage = this.getErrorMessage();
|
||||
|
||||
const options = this.props.options.map((option, i) => (
|
||||
|
|
@ -19,7 +20,7 @@ const MySelect = React.createClass({
|
|||
));
|
||||
|
||||
return (
|
||||
<div className='form-group'>
|
||||
<div className={className}>
|
||||
<label htmlFor={this.props.name}>{this.props.title}</label>
|
||||
<select name={this.props.name} onChange={this.changeValue} value={this.getValue()}>
|
||||
{options}
|
||||
|
|
|
|||
|
|
@ -58,19 +58,20 @@ const DynamicInput = React.createClass({
|
|||
},
|
||||
validate() {
|
||||
const value = this.getValue();
|
||||
return value !== '' ? validators[this.state.validationType].regexp.test(value) : true;
|
||||
console.log(value, this.state.validationType);
|
||||
return value ? validators[this.state.validationType].regexp.test(value) : true;
|
||||
},
|
||||
getCustomErrorMessage() {
|
||||
return this.showError() ? validators[this.state.validationType].message : '';
|
||||
},
|
||||
render() {
|
||||
const className = this.props.className + ' ' + (this.showError() ? 'error' : null);
|
||||
const className = 'form-group' + (this.props.className || ' ') + (this.showRequired() ? 'required' : this.showError() ? 'error' : null);
|
||||
const errorMessage = this.getCustomErrorMessage();
|
||||
|
||||
return (
|
||||
<div className='form-group'>
|
||||
<div className={className}>
|
||||
<label htmlFor={this.props.name}>{this.props.title}</label>
|
||||
<input type='text' name={this.props.name} onChange={this.changeValue} value={this.getValue()}/>
|
||||
<input type='text' name={this.props.name} onChange={this.changeValue} value={this.getValue() || ''}/>
|
||||
<span className='validation-error'>{errorMessage}</span>
|
||||
<Validations validationType={this.state.validationType} changeValidation={this.changeValidation}/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
.many-fields-conf {
|
||||
width: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.many-fields {
|
||||
width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.field {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.many-fields .form-group {
|
||||
width: calc(100% - 20px);
|
||||
float: left;
|
||||
}
|
||||
.many-fields .remove-field {
|
||||
margin-top: 30px;
|
||||
margin-left: 8px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Form } from 'formsy-react';
|
||||
|
||||
import MyInput from './../components/Input';
|
||||
import MySelect from './../components/Select';
|
||||
import MyRadioGroup from './../components/RadioGroup';
|
||||
import MyMultiCheckboxSet from './../components/MultiCheckboxSet';
|
||||
|
||||
const Fields = props => {
|
||||
function onRemove(pos) {
|
||||
return event => {
|
||||
event.preventDefault();
|
||||
props.onRemove(pos);
|
||||
};
|
||||
}
|
||||
const foo = 'required';
|
||||
return (
|
||||
<div className="fields">
|
||||
{props.data.map((field, i) => (
|
||||
<div className="field" key={field.id}>
|
||||
{
|
||||
field.type === 'input' ?
|
||||
(
|
||||
<MyInput
|
||||
value=""
|
||||
name={`fields[${i}]`}
|
||||
title={field.validations ? JSON.stringify(field.validations) : 'No validations'}
|
||||
required={field.required}
|
||||
validations={field.validations}
|
||||
/>
|
||||
) :
|
||||
(
|
||||
<MySelect
|
||||
name={`fields[${i}]`}
|
||||
title={field.validations ? JSON.stringify(field.validations) : 'No validations'}
|
||||
required={field.required}
|
||||
validations={field.validations}
|
||||
options={[
|
||||
{title: '123', value: '123'},
|
||||
{title: 'some long text', value: 'some long text'},
|
||||
{title: '`empty string`', value: ''},
|
||||
{title: 'alpha42', value: 'alpha42'},
|
||||
{title: 'test@mail.com', value: 'test@mail.com'}
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<a href="#" className="remove-field" onClick={onRemove(i)}>X</a>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const App = React.createClass({
|
||||
getInitialState() {
|
||||
return { fields: [], canSubmit: false };
|
||||
},
|
||||
submit(data) {
|
||||
alert(JSON.stringify(data, null, 4));
|
||||
},
|
||||
addField(fieldData) {
|
||||
fieldData.validations = fieldData.validations.length ?
|
||||
fieldData.validations.reduce((a, b) => Object.assign({}, a, b)) :
|
||||
null;
|
||||
fieldData.id = Date.now();
|
||||
this.setState({ fields: this.state.fields.concat(fieldData) });
|
||||
},
|
||||
removeField(pos) {
|
||||
const fields = this.state.fields;
|
||||
this.setState({ fields: fields.slice(0, pos).concat(fields.slice(pos+1)) })
|
||||
},
|
||||
enableButton() {
|
||||
this.setState({ canSubmit: true });
|
||||
},
|
||||
disableButton() {
|
||||
this.setState({ canSubmit: false });
|
||||
},
|
||||
render() {
|
||||
const { fields, canSubmit } = this.state;
|
||||
return (
|
||||
<div>
|
||||
<Form onSubmit={this.addField} className="many-fields-conf">
|
||||
<MyMultiCheckboxSet name="validations" title="Validations"
|
||||
cmp={(a, b) => JSON.stringify(a) === JSON.stringify(b)}
|
||||
items={[
|
||||
{isEmail: true},
|
||||
{isEmptyString: true},
|
||||
{isNumeric: true},
|
||||
{isAlphanumeric: true},
|
||||
{equals: 5},
|
||||
{minLength: 3},
|
||||
{maxLength: 7}
|
||||
]}
|
||||
/>
|
||||
<MyRadioGroup name="required" value={false} title="Required"
|
||||
items={[true, false]} />
|
||||
<MyRadioGroup name="type" value="input" title="Type"
|
||||
items={['input', 'select']} />
|
||||
<button type="submit">Add</button>
|
||||
</Form>
|
||||
<Form onSubmit={this.submit} onValid={this.enableButton} onInvalid={this.disableButton} className="many-fields">
|
||||
<Fields data={fields} onRemove={this.removeField} />
|
||||
<button type="submit" disabled={!canSubmit}>Submit</button>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ReactDOM.render(<App/>, document.getElementById('example'));
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dynamic Form Fields</title>
|
||||
<link href="../global.css" rel="stylesheet"/>
|
||||
<link href="app.css" rel="stylesheet"/>
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="breadcrumbs"><a href="../index.html">Formsy React Examples</a> / Dynamic Form Fields</h1>
|
||||
<div id="example"/>
|
||||
<script src="/__build__/shared.js"></script>
|
||||
<script src="/__build__/dynamic-form-fields.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -49,11 +49,28 @@ form {
|
|||
color: #555;
|
||||
background-color: #FFF;
|
||||
background-image: none;
|
||||
border: 1px solid #CCC;
|
||||
border: 2px solid #CCC;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-group.error input[type='text'],
|
||||
.form-group.error input[type='email'],
|
||||
.form-group.error input[type='number'],
|
||||
.form-group.error input[type='password'],
|
||||
.form-group.error select {
|
||||
border-color: red;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.form-group.required input[type='text'],
|
||||
.form-group.required input[type='email'],
|
||||
.form-group.required input[type='number'],
|
||||
.form-group.required input[type='password'],
|
||||
.form-group.required select {
|
||||
border-color: #FF9696;
|
||||
}
|
||||
|
||||
.validation-error {
|
||||
color: red;
|
||||
margin: 5px 0;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<li><a href="login/index.html">Login Page</a></li>
|
||||
<li><a href="custom-validation/index.html">Custom Validation</a></li>
|
||||
<li><a href="reset-values/index.html">Reset Values</a></li>
|
||||
<li><a href="dynamic-form-fields/index.html">Dynamic Form Fields</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ const App = React.createClass({
|
|||
render() {
|
||||
return (
|
||||
<Form onSubmit={this.submit} onValid={this.enableButton} onInvalid={this.disableButton} className="login">
|
||||
<MyInput name="email" title="Email" validations="isEmail" validationError="This is not a valid email" required />
|
||||
<MyInput name="password" title="Password" type="password" required />
|
||||
<MyInput value="" name="email" title="Email" validations="isEmail" validationError="This is not a valid email" required />
|
||||
<MyInput value="" name="password" title="Password" type="password" required />
|
||||
<button type="submit" disabled={!this.state.canSubmit}>Submit</button>
|
||||
</Form>
|
||||
);
|
||||
|
|
|
|||
37
package.json
37
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "formsy-react",
|
||||
"version": "0.15.1",
|
||||
"version": "0.19.5",
|
||||
"description": "A form input builder and validator for React JS",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
@ -8,9 +8,8 @@
|
|||
},
|
||||
"main": "lib/main.js",
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server --content-base build",
|
||||
"deploy": "NODE_ENV=production webpack -p --config webpack.production.config.js",
|
||||
"test": "node testrunner",
|
||||
"build": "NODE_ENV=production webpack -p --config webpack.production.config.js",
|
||||
"test": "babel-node testrunner",
|
||||
"examples": "webpack-dev-server --config examples/webpack.config.js --content-base examples",
|
||||
"prepublish": "babel ./src/ -d ./lib/"
|
||||
},
|
||||
|
|
@ -24,21 +23,27 @@
|
|||
"react-component"
|
||||
],
|
||||
"dependencies": {
|
||||
"form-data-to-object": "^0.1.0"
|
||||
"form-data-to-object": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^5.6.4",
|
||||
"babel-core": "^5.1.11",
|
||||
"babel-loader": "^5.0.0",
|
||||
"jasmine-node": "^1.14.5",
|
||||
"jsdom": "^3.1.2",
|
||||
"react": "^0.14.0-beta3",
|
||||
"react-addons-test-utils": "^0.14.0-beta3",
|
||||
"react-dom": "^0.14.0-beta3",
|
||||
"webpack": "^1.7.3",
|
||||
"webpack-dev-server": "^1.7.0"
|
||||
"babel-cli": "^6.6.5",
|
||||
"babel-loader": "^6.2.4",
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"babel-preset-react": "^6.5.0",
|
||||
"babel-preset-stage-2": "^6.5.0",
|
||||
"create-react-class": "^15.6.0",
|
||||
"jsdom": "^6.5.1",
|
||||
"nodeunit": "^0.9.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^15.0.0",
|
||||
"react-addons-pure-render-mixin": "^15.0.0",
|
||||
"react-addons-test-utils": "^15.0.0",
|
||||
"react-dom": "^15.0.0",
|
||||
"sinon": "^1.17.3",
|
||||
"webpack": "^1.12.14",
|
||||
"webpack-dev-server": "^1.14.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^0.14.0-beta3"
|
||||
"react": "^0.14.0 || ^15.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,519 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import TestInput from './utils/TestInput';
|
||||
import immediate from './utils/immediate';
|
||||
|
||||
describe('Formsy', function () {
|
||||
|
||||
describe('Setting up a form', function () {
|
||||
|
||||
it('should render a form into the document', function () {
|
||||
const form = TestUtils.renderIntoDocument(<Formsy.Form></Formsy.Form>);
|
||||
expect(React.findDOMNode(form).tagName).toEqual('FORM');
|
||||
});
|
||||
|
||||
it('should set a class name if passed', function () {
|
||||
const form = TestUtils.renderIntoDocument( <Formsy.Form className="foo"></Formsy.Form>);
|
||||
expect(React.findDOMNode(form).className).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should allow for null/undefined children', function (done) {
|
||||
|
||||
let model = null;
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={(formModel) => (model = formModel)}>
|
||||
<h1>Test</h1>
|
||||
{ null }
|
||||
{ undefined }
|
||||
<TestInput name="name" value={ 'foo' } />
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
immediate(() => {
|
||||
TestUtils.Simulate.submit(React.findDOMNode(form));
|
||||
expect(model).toEqual({name: 'foo'});
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should allow for inputs being added dynamically', function (done) {
|
||||
|
||||
const inputs = [];
|
||||
let forceUpdate = null;
|
||||
let model = null;
|
||||
const TestForm = React.createClass({
|
||||
componentWillMount() {
|
||||
forceUpdate = this.forceUpdate.bind(this);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={(formModel) => (model = formModel)}>
|
||||
{inputs}
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
// Wait before adding the input
|
||||
setTimeout(() => {
|
||||
inputs.push(<TestInput name="test" value="" key={inputs.length}/>);
|
||||
|
||||
forceUpdate(() => {
|
||||
// Wait for next event loop, as that does the form
|
||||
immediate(() => {
|
||||
TestUtils.Simulate.submit(React.findDOMNode(form));
|
||||
expect(model.test).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}, 10);
|
||||
|
||||
});
|
||||
|
||||
it('should allow dynamically added inputs to update the form-model', function (done) {
|
||||
|
||||
const inputs = [];
|
||||
let forceUpdate = null;
|
||||
let model = null;
|
||||
const TestForm = React.createClass({
|
||||
componentWillMount() {
|
||||
forceUpdate = this.forceUpdate.bind(this);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={(formModel) => (model = formModel)}>
|
||||
{inputs}
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
// Wait before adding the input
|
||||
immediate(() => {
|
||||
inputs.push(<TestInput name="test" key={inputs.length}/>);
|
||||
|
||||
forceUpdate(() => {
|
||||
|
||||
// Wait for next event loop, as that does the form
|
||||
immediate(() => {
|
||||
TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'foo'}});
|
||||
TestUtils.Simulate.submit(React.findDOMNode(form));
|
||||
expect(model.test).toBe('foo');
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should allow a dynamically updated input to update the form-model', function (done) {
|
||||
|
||||
let forceUpdate = null;
|
||||
let model = null;
|
||||
|
||||
const TestForm = React.createClass({
|
||||
componentWillMount() {
|
||||
forceUpdate = this.forceUpdate.bind(this);
|
||||
},
|
||||
render() {
|
||||
const input = <TestInput name="test" value={this.props.value} />;
|
||||
|
||||
return (
|
||||
<Formsy.Form onSubmit={(formModel) => (model = formModel)}>
|
||||
{input}
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
let form = TestUtils.renderIntoDocument(<TestForm value="foo"/>);
|
||||
|
||||
// Wait before changing the input
|
||||
immediate(() => {
|
||||
form = TestUtils.renderIntoDocument(<TestForm value="bar"/>);
|
||||
|
||||
forceUpdate(() => {
|
||||
// Wait for next event loop, as that does the form
|
||||
immediate(() => {
|
||||
TestUtils.Simulate.submit(React.findDOMNode(form));
|
||||
expect(model.test).toBe('bar');
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('validations', function () {
|
||||
let CheckValid, onSubmit, OtherCheckValid;
|
||||
let isValid;
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getDefaultProps() {
|
||||
return { inputs: [] };
|
||||
},
|
||||
render() {
|
||||
const builtInputs = this.props.inputs.map((input) => <TestInput { ...input } key={ input.name } />);
|
||||
return (
|
||||
<Formsy.Form
|
||||
onSubmit={(arg1) => onSubmit(arg1)}
|
||||
onValid={() => (isValid = true)}
|
||||
onInvalid={() => (isValid = false)}>
|
||||
{ builtInputs }
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
isValid = true;
|
||||
CheckValid = jasmine.createSpy('CheckValid');
|
||||
Formsy.addValidationRule('CheckValid', CheckValid);
|
||||
OtherCheckValid = jasmine.createSpy('CheckValid');
|
||||
Formsy.addValidationRule('OtherCheckValid', OtherCheckValid);
|
||||
onSubmit = jasmine.createSpy('onSubmit');
|
||||
});
|
||||
|
||||
it('should run when the input changes', function () {
|
||||
const inputs = [{name: 'one', validations: 'CheckValid', value: 'foo'}];
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputs={inputs}/>);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}});
|
||||
expect(CheckValid).toHaveBeenCalledWith({one: 'bar'}, 'bar', true);
|
||||
expect(OtherCheckValid).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should allow the validation to be changed', function () {
|
||||
const inputs = [{name: 'one', validations: 'CheckValid', value: 'foo'}];
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputs={inputs}/>);
|
||||
form.setProps({inputs: [{name: 'one', validations: 'OtherCheckValid', value: 'foo'}] });
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}});
|
||||
expect(OtherCheckValid).toHaveBeenCalledWith({one: 'bar'}, 'bar', true);
|
||||
});
|
||||
|
||||
it('should invalidate a form if dynamically inserted input is invalid', function (done) {
|
||||
const inputs = [{name: 'one', validations: 'isEmail', value: 'foo@bar.com'}];
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputs={inputs}/>);
|
||||
expect(isValid).toEqual(true);
|
||||
form.setProps({inputs: [
|
||||
{name: 'one', validations: 'isEmail', value: 'foo@bar.com'},
|
||||
{name: 'two', validations: 'isEmail', value: 'foo@bar'}
|
||||
]}, () => {
|
||||
immediate(() => {
|
||||
expect(isValid).toEqual(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should validate a form when removing an invalid input', function (done) {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputs={ [
|
||||
{name: 'one', validations: 'isEmail', value: 'foo@bar.com'},
|
||||
{name: 'two', validations: 'isEmail', value: 'foo@bar'}
|
||||
] } />);
|
||||
expect(isValid).toEqual(false);
|
||||
form.setProps({inputs: [{name: 'one', validations: 'isEmail', value: 'foo@bar.com'}]}, () => {
|
||||
immediate(() => {
|
||||
expect(isValid).toEqual(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('runs multiple validations', function () {
|
||||
const inputs = [{name: 'one', validations: 'CheckValid,OtherCheckValid', value: 'foo'}];
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputs={inputs}/>);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}});
|
||||
expect(CheckValid).toHaveBeenCalledWith({one: 'bar'}, 'bar', true);
|
||||
expect(OtherCheckValid).toHaveBeenCalledWith({one: 'bar'}, 'bar', true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not trigger onChange when form is mounted', function () {
|
||||
const hasChanged = jasmine.createSpy('onChange');
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return <Formsy.Form onChange={hasChanged}></Formsy.Form>;
|
||||
}
|
||||
});
|
||||
TestUtils.renderIntoDocument(<TestForm/>);
|
||||
expect(hasChanged).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should trigger onChange when form element is changed', function () {
|
||||
const hasChanged = jasmine.createSpy('onChange');
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onChange={hasChanged}>
|
||||
<TestInput name="foo"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'bar'}});
|
||||
expect(hasChanged).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should trigger onChange when new input is added to form', function (done) {
|
||||
const hasChanged = jasmine.createSpy('onChange');
|
||||
const inputs = [];
|
||||
let forceUpdate = null;
|
||||
const TestForm = React.createClass({
|
||||
componentWillMount() {
|
||||
forceUpdate = this.forceUpdate.bind(this);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onChange={hasChanged}>
|
||||
{inputs}
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
// Wait before adding the input
|
||||
inputs.push(<TestInput name="test" key={inputs.length}/>);
|
||||
|
||||
forceUpdate(() => {
|
||||
|
||||
// Wait for next event loop, as that does the form
|
||||
immediate(() => {
|
||||
expect(hasChanged).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Update a form', function () {
|
||||
|
||||
it('should allow elements to check if the form is disabled', function (done) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() { return { disabled: true }; },
|
||||
enableForm() { this.setState({ disabled: false }); },
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onChange={this.onChange} disabled={this.state.disabled}>
|
||||
<TestInput name="foo"/>
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(input.isFormDisabled()).toBe(true);
|
||||
|
||||
form.enableForm();
|
||||
immediate(() => {
|
||||
expect(input.isFormDisabled()).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should be possible to pass error state of elements by changing an errors attribute', function (done) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() { return { validationErrors: { foo: 'bar' } }; },
|
||||
onChange(values) {
|
||||
this.setState(values.foo ? { validationErrors: {} } : { validationErrors: {foo: 'bar'} });
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onChange={this.onChange} validationErrors={this.state.validationErrors}>
|
||||
<TestInput name="foo"/>
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
// Wait for update
|
||||
immediate(() => {
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(input.getErrorMessage()).toBe('bar');
|
||||
input.setValue('gotValue');
|
||||
|
||||
// Wait for update
|
||||
immediate(() => {
|
||||
expect(input.getErrorMessage()).toBe(null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
it('should trigger an onValidSubmit when submitting a valid form', function () {
|
||||
|
||||
let isCalled = false;
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onValidSubmit={() => (isCalled = true)}>
|
||||
<TestInput name="foo" validations="isEmail" value="foo@bar.com"/>
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const FoundForm = TestUtils.findRenderedComponentWithType(form, TestForm);
|
||||
TestUtils.Simulate.submit(React.findDOMNode(FoundForm));
|
||||
expect(isCalled).toBe(true);
|
||||
|
||||
});
|
||||
|
||||
it('should trigger an onInvalidSubmit when submitting an invalid form', function () {
|
||||
|
||||
let isCalled = false;
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onInvalidSubmit={() => (isCalled = true)}>
|
||||
<TestInput name="foo" validations="isEmail" value="foo@bar"/>
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<TestForm/>
|
||||
);
|
||||
|
||||
const FoundForm = TestUtils.findRenderedComponentWithType(form, TestForm);
|
||||
TestUtils.Simulate.submit(React.findDOMNode(FoundForm));
|
||||
expect(isCalled).toBe(true);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("value === false", function () {
|
||||
let onSubmit;
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={(x) => onSubmit(x)}>
|
||||
<TestInput name="foo" value={ this.props.value } type="checkbox" />
|
||||
<button type="submit">Save</button>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
onSubmit = jasmine.createSpy('onSubmit');
|
||||
});
|
||||
|
||||
it("should call onSubmit correctly", function () {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm value={ false }/>);
|
||||
TestUtils.Simulate.submit(React.findDOMNode(form));
|
||||
expect(onSubmit).toHaveBeenCalledWith({foo: false});
|
||||
});
|
||||
|
||||
it("should allow dynamic changes to false", function () {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm value={ true }/>);
|
||||
form.setProps({value: false});
|
||||
TestUtils.Simulate.submit(React.findDOMNode(form));
|
||||
expect(onSubmit).toHaveBeenCalledWith({foo: false});
|
||||
});
|
||||
|
||||
it("should say the form is submitted", function () {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm value={ true }/>);
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(input.isFormSubmitted()).toBe(false);
|
||||
TestUtils.Simulate.submit(React.findDOMNode(form));
|
||||
expect(input.isFormSubmitted()).toBe(true);
|
||||
});
|
||||
|
||||
it("should be able to reset the form to its pristine state", function () {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm value={ true }/>);
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
const formsyForm = TestUtils.findRenderedComponentWithType(form, Formsy.Form);
|
||||
expect(input.getValue()).toBe(true);
|
||||
form.setProps({value: false});
|
||||
expect(input.getValue()).toBe(false);
|
||||
formsyForm.reset();
|
||||
expect(input.getValue()).toBe(true);
|
||||
});
|
||||
|
||||
it("should be able to reset the form using custom data", function () {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm value={ true }/>);
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
const formsyForm = TestUtils.findRenderedComponentWithType(form, Formsy.Form);
|
||||
expect(input.getValue()).toBe(true);
|
||||
form.setProps({value: false});
|
||||
expect(input.getValue()).toBe(false);
|
||||
formsyForm.reset({
|
||||
foo: 'bar'
|
||||
});
|
||||
expect(input.getValue()).toBe('bar');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('.isChanged()', function () {
|
||||
let onChange;
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getDefaultProps() {
|
||||
return { inputs: [] };
|
||||
},
|
||||
render() {
|
||||
const builtInputs = this.props.inputs.map((input) => <TestInput {...input} key={input.name}/>);
|
||||
return (
|
||||
<Formsy.Form ref="formsy" onChange={ onChange }>
|
||||
{ builtInputs }
|
||||
{ this.props.children }
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
onChange = jasmine.createSpy('onChange');
|
||||
});
|
||||
|
||||
it('initially returns false', function () {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputs={ [{name: 'one', value: 'foo'}] }/>);
|
||||
expect(form.refs.formsy.isChanged()).toEqual(false);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns true when changed', function () {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputs={ [{name: 'one', value: 'foo'}] }/>);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}});
|
||||
expect(form.refs.formsy.isChanged()).toEqual(true);
|
||||
expect(onChange).toHaveBeenCalledWith({one: 'bar'}, true);
|
||||
});
|
||||
|
||||
it('returns false if changes are undone', function () {
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputs={ [{name: 'one', value: 'foo'}] }/>);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'bar'}});
|
||||
expect(onChange).toHaveBeenCalledWith({one: 'bar'}, true);
|
||||
TestUtils.Simulate.change(React.findDOMNode(input), {target: {value: 'foo'}});
|
||||
expect(form.refs.formsy.isChanged()).toEqual(false);
|
||||
expect(onChange).toHaveBeenCalledWith({one: 'foo'}, false);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: equals', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="equals:myValue"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should fail when the value is not equal', fail('foo'));
|
||||
|
||||
it('should pass when the value is equal', pass('myValue'));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should fail with a number', fail(42));
|
||||
|
||||
});
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isAlpha', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isAlpha"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should pass with a string is only latin letters', pass('myValue'));
|
||||
|
||||
it('should fail with a string with numbers', fail('myValue42'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with a number', fail(42));
|
||||
|
||||
});
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isAlphanumeric', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isAlphanumeric"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should pass with a string is only latin letters', pass('myValue'));
|
||||
|
||||
it('should pass with a string with numbers', pass('myValue42'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should pass with a number', pass(42));
|
||||
|
||||
it('should fail with a non alpha and number symbols', fail('!@#$%^&*()'));
|
||||
|
||||
});
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isEmail', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" value="foo" validations="isEmail"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should fail with "foo"', fail('foo'));
|
||||
|
||||
it('should pass with "foo@foo.com"', pass('foo@foo.com'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with a number', fail(42));
|
||||
|
||||
});
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isEmptyString', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isEmptyString"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with a default value', fail());
|
||||
|
||||
it('should fail with non-empty string', fail('asd'));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with a undefined', fail(undefined));
|
||||
|
||||
it('should fail with a null', fail(null));
|
||||
|
||||
it('should fail with a number', fail(123));
|
||||
|
||||
it('should fail with a zero', fail(0));
|
||||
|
||||
});
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isExisty', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isExisty"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should fail with a default value', fail());
|
||||
|
||||
it('should pass with a string', pass('myValue'));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with an undefined', fail(undefined));
|
||||
|
||||
it('should fail with a null', fail(null));
|
||||
|
||||
it('should pass with a number', pass(42));
|
||||
|
||||
it('should pass with a zero', pass(0));
|
||||
|
||||
});
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isFloat', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isFloat"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with an unempty string', fail('myValue'));
|
||||
|
||||
it('should pass with a number as string', pass('+42'));
|
||||
|
||||
it('should fail with a number as string with not digits', fail('42 as an answer'));
|
||||
|
||||
it('should pass with an int', pass(42));
|
||||
|
||||
it('should pass with a float', pass(Math.PI));
|
||||
|
||||
it('should pass with a float in science notation', pass('-1e3'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should pass with a zero', pass(0));
|
||||
|
||||
});
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isInt', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isInt"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with an unempty string', fail('myValue'));
|
||||
|
||||
it('should pass with a number as string', pass('+42'));
|
||||
|
||||
it('should fail with a number as string with not digits', fail('42 as an answer'));
|
||||
|
||||
it('should pass with an int', pass(42));
|
||||
|
||||
it('should fail with a float', fail(Math.PI));
|
||||
|
||||
it('should fail with a float in science notation', fail('-1e3'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should pass with a zero', pass(0));
|
||||
|
||||
});
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isLength', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
describe('isLength:3', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isLength:3"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should fail with a string too small', fail('hi'));
|
||||
|
||||
it('should fail with a string too long', fail('foo bar'));
|
||||
|
||||
it('should pass with the right length', pass('sup'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with a number', fail(123));
|
||||
|
||||
});
|
||||
|
||||
describe('isLength:0', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isLength:0"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should fail with a string too long', fail('foo bar'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with a number', fail(123));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isNumeric', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isNumeric"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should fail with an unempty string', fail('myValue'));
|
||||
|
||||
it('should pass with a number as string', pass('+42'));
|
||||
|
||||
it('should fail with a number as string with not digits', fail('42 as an answer'));
|
||||
|
||||
it('should pass with an int', pass(42));
|
||||
|
||||
it('should pass with a float', pass(Math.PI));
|
||||
|
||||
it('should fail with a float in science notation', fail('-1e3'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should pass with a zero', pass(0));
|
||||
|
||||
});
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isUrl', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" value="foo" validations="isUrl"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should fail with "foo"', fail('foo'));
|
||||
|
||||
it('should pass with "https://www.google.com/"', pass('https://www.google.com/'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should fail with a number', fail(42));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
});
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: isWords', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="isWords"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should pass with a 1 word', pass('sup'));
|
||||
|
||||
it('should pass with 2 words', pass('sup dude'));
|
||||
|
||||
it('should fail with a string with numbers', fail('myValue 42'));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should fail with a number', fail(42));
|
||||
|
||||
});
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: maxLength', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="maxLength:3"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should pass when a string\'s length is smaller', pass('hi'));
|
||||
|
||||
it('should pass when a string\'s length is equal', pass('bar'));
|
||||
|
||||
it('should fail when a string\'s length is bigger', fail('myValue'));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should fail with a number', fail(123));
|
||||
|
||||
});
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { customizeInput } from './utils/TestInput';
|
||||
|
||||
describe('Rules: minLength', function () {
|
||||
let Input, isValid, form, input;
|
||||
|
||||
function pass(value) {
|
||||
return pass.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(true);
|
||||
} : () => expect(isValid).toBe(true);
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
return fail.length ? () => {
|
||||
TestUtils.Simulate.change(input, {target: {value}});
|
||||
expect(isValid).toBe(false);
|
||||
} : () => expect(isValid).toBe(false);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
Input = customizeInput({
|
||||
render() {
|
||||
isValid = this.isValid();
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Input = isValid = form = null;
|
||||
});
|
||||
|
||||
describe('minLength:3', function () {
|
||||
|
||||
beforeEach(() => {
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="minLength:3"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should fail when a string\'s length is smaller', fail('hi'));
|
||||
|
||||
it('should pass when a string\'s length is equal', pass('bar'));
|
||||
|
||||
it('should pass when a string\'s length is bigger', pass('myValue'));
|
||||
|
||||
it('should pass with an empty string', pass(''));
|
||||
|
||||
it('should pass with an undefined', pass(undefined));
|
||||
|
||||
it('should pass with a null', pass(null));
|
||||
|
||||
it('should fail with a number', fail(123));
|
||||
|
||||
});
|
||||
|
||||
describe('minLength:0', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" validations="minLength:0"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
});
|
||||
|
||||
it('should pass with a default value', pass());
|
||||
|
||||
it('should pass when a string\'s length is bigger', pass('myValue'));
|
||||
|
||||
it('should pass with empty string', pass(''));
|
||||
|
||||
it('should pass with undefined', pass(undefined));
|
||||
|
||||
it('should pass with null', pass(null));
|
||||
|
||||
it('should fail with a number', fail(123));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import utils from './../src/utils.js';
|
||||
|
||||
describe('Utils', function () {
|
||||
|
||||
it('should check equality of objects and arrays', () => {
|
||||
const objA = { foo: 'bar' };
|
||||
const objB = { foo: 'bar' };
|
||||
const objC = [{ foo: ['bar'] }];
|
||||
const objD = [{ foo: ['bar'] }];
|
||||
const objE = undefined;
|
||||
const objF = undefined;
|
||||
const objG = null;
|
||||
const objH = null;
|
||||
|
||||
expect(utils.isSame(objA, objB)).toBe(true);
|
||||
expect(utils.isSame(objC, objD)).toBe(true);
|
||||
expect(utils.isSame(objA, objD)).toBe(false);
|
||||
|
||||
expect(utils.isSame(objE, objF)).toBe(true);
|
||||
expect(utils.isSame(objA, objF)).toBe(false);
|
||||
expect(utils.isSame(objE, objA)).toBe(false);
|
||||
|
||||
expect(utils.isSame(objG, objH)).toBe(true);
|
||||
expect(utils.isSame(objA, objH)).toBe(false);
|
||||
expect(utils.isSame(objG, objA)).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
var React = global.React || require('react');
|
||||
var createReactClass = require('create-react-class');
|
||||
var Mixin = require('./Mixin.js');
|
||||
module.exports = function () {
|
||||
return function (Component) {
|
||||
return React.createClass({
|
||||
return createReactClass({
|
||||
mixins: [Mixin],
|
||||
render: function () {
|
||||
return React.createElement(Component, {
|
||||
|
|
|
|||
26
src/HOC.js
26
src/HOC.js
|
|
@ -1,10 +1,14 @@
|
|||
var React = global.React || require('react');
|
||||
var createReactClass = require('create-react-class');
|
||||
var Mixin = require('./Mixin.js');
|
||||
module.exports = function (Component) {
|
||||
return React.createClass({
|
||||
return createReactClass({
|
||||
displayName: 'Formsy(' + getDisplayName(Component) + ')',
|
||||
mixins: [Mixin],
|
||||
|
||||
render: function () {
|
||||
return React.createElement(Component, {
|
||||
const { innerRef } = this.props;
|
||||
const propsForElement = {
|
||||
setValidations: this.setValidations,
|
||||
setValue: this.setValue,
|
||||
resetValue: this.resetValue,
|
||||
|
|
@ -19,8 +23,22 @@ module.exports = function (Component) {
|
|||
isRequired: this.isRequired,
|
||||
showRequired: this.showRequired,
|
||||
showError: this.showError,
|
||||
isValidValue: this.isValidValue
|
||||
});
|
||||
isValidValue: this.isValidValue,
|
||||
...this.props
|
||||
};
|
||||
|
||||
if (innerRef) {
|
||||
propsForElement.ref = innerRef;
|
||||
}
|
||||
return React.createElement(Component, propsForElement);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function getDisplayName(Component) {
|
||||
return (
|
||||
Component.displayName ||
|
||||
Component.name ||
|
||||
(typeof Component === 'string' ? Component : 'Component')
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
var PropTypes = require('prop-types');
|
||||
var utils = require('./utils.js');
|
||||
var React = global.React || require('react');
|
||||
|
||||
|
|
@ -44,7 +45,7 @@ module.exports = {
|
|||
};
|
||||
},
|
||||
contextTypes: {
|
||||
formsy: React.PropTypes.object // What about required?
|
||||
formsy: PropTypes.object // What about required?
|
||||
},
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
|
|
|
|||
190
src/main.js
190
src/main.js
|
|
@ -1,4 +1,6 @@
|
|||
var PropTypes = require('prop-types');
|
||||
var React = global.React || require('react');
|
||||
var createReactClass = require('create-react-class');
|
||||
var Formsy = {};
|
||||
var validationRules = require('./validationRules.js');
|
||||
var formDataToObject = require('form-data-to-object');
|
||||
|
|
@ -7,6 +9,7 @@ var Mixin = require('./Mixin.js');
|
|||
var HOC = require('./HOC.js');
|
||||
var Decorator = require('./Decorator.js');
|
||||
var options = {};
|
||||
var emptyArray = [];
|
||||
|
||||
Formsy.Mixin = Mixin;
|
||||
Formsy.HOC = HOC;
|
||||
|
|
@ -20,7 +23,8 @@ Formsy.addValidationRule = function (name, func) {
|
|||
validationRules[name] = func;
|
||||
};
|
||||
|
||||
Formsy.Form = React.createClass({
|
||||
Formsy.Form = createReactClass({
|
||||
displayName: 'Formsy',
|
||||
getInitialState: function () {
|
||||
return {
|
||||
isValid: true,
|
||||
|
|
@ -35,7 +39,6 @@ Formsy.Form = React.createClass({
|
|||
onSubmit: function () {},
|
||||
onValidSubmit: function () {},
|
||||
onInvalidSubmit: function () {},
|
||||
onSubmitted: function () {},
|
||||
onValid: function () {},
|
||||
onInvalid: function () {},
|
||||
onChange: function () {},
|
||||
|
|
@ -45,7 +48,7 @@ Formsy.Form = React.createClass({
|
|||
},
|
||||
|
||||
childContextTypes: {
|
||||
formsy: React.PropTypes.object
|
||||
formsy: PropTypes.object
|
||||
},
|
||||
getChildContext: function () {
|
||||
return {
|
||||
|
|
@ -54,9 +57,9 @@ Formsy.Form = React.createClass({
|
|||
detachFromForm: this.detachFromForm,
|
||||
validate: this.validate,
|
||||
isFormDisabled: this.isFormDisabled,
|
||||
isValidValue: function (component, value) {
|
||||
isValidValue: (component, value) => {
|
||||
return this.runValidation(component, value).isValid;
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -64,8 +67,7 @@ Formsy.Form = React.createClass({
|
|||
// Add a map to store the inputs of the form, a model to store
|
||||
// the values of the form and register child inputs
|
||||
componentWillMount: function () {
|
||||
this.inputs = {};
|
||||
this.model = {};
|
||||
this.inputs = [];
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
|
|
@ -73,21 +75,19 @@ Formsy.Form = React.createClass({
|
|||
},
|
||||
|
||||
componentWillUpdate: function () {
|
||||
|
||||
// Keep a reference to input keys before form updates,
|
||||
// Keep a reference to input names before form updates,
|
||||
// to check if inputs has changed after render
|
||||
this.prevInputKeys = Object.keys(this.inputs);
|
||||
|
||||
this.prevInputNames = this.inputs.map(component => component.props.name);
|
||||
},
|
||||
|
||||
componentDidUpdate: function () {
|
||||
|
||||
if (this.props.validationErrors) {
|
||||
if (this.props.validationErrors && typeof this.props.validationErrors === 'object' && Object.keys(this.props.validationErrors).length > 0) {
|
||||
this.setInputValidationErrors(this.props.validationErrors);
|
||||
}
|
||||
|
||||
var newInputKeys = Object.keys(this.inputs);
|
||||
if (utils.arraysDiffer(this.prevInputKeys, newInputKeys)) {
|
||||
var newInputNames = this.inputs.map(component => component.props.name);
|
||||
if (utils.arraysDiffer(this.prevInputNames, newInputNames)) {
|
||||
this.validateForm();
|
||||
}
|
||||
|
||||
|
|
@ -108,62 +108,59 @@ Formsy.Form = React.createClass({
|
|||
// If any inputs have not been touched yet this will make them dirty
|
||||
// so validation becomes visible (if based on isPristine)
|
||||
this.setFormPristine(false);
|
||||
this.updateModel();
|
||||
var model = this.mapModel();
|
||||
var model = this.getModel();
|
||||
this.props.onSubmit(model, this.resetModel, this.updateInputsWithError);
|
||||
this.state.isValid ? this.props.onValidSubmit(model, this.resetModel, this.updateInputsWithError) : this.props.onInvalidSubmit(model, this.resetModel, this.updateInputsWithError);
|
||||
|
||||
},
|
||||
|
||||
mapModel: function () {
|
||||
mapModel: function (model) {
|
||||
|
||||
if (this.props.mapping) {
|
||||
return this.props.mapping(this.model)
|
||||
return this.props.mapping(model)
|
||||
} else {
|
||||
return formDataToObject(Object.keys(this.model).reduce(function (mappedModel, key) {
|
||||
return formDataToObject.toObj(Object.keys(model).reduce((mappedModel, key) => {
|
||||
|
||||
var keyArray = key.split('.');
|
||||
var base = mappedModel;
|
||||
while (keyArray.length) {
|
||||
var currentKey = keyArray.shift();
|
||||
base = (base[currentKey] = keyArray.length ? base[currentKey] || {} : this.model[key]);
|
||||
base = (base[currentKey] = keyArray.length ? base[currentKey] || {} : model[key]);
|
||||
}
|
||||
|
||||
return mappedModel;
|
||||
|
||||
}.bind(this), {}));
|
||||
}, {}));
|
||||
}
|
||||
},
|
||||
|
||||
// Goes through all registered components and
|
||||
// updates the model values
|
||||
updateModel: function () {
|
||||
Object.keys(this.inputs).forEach(function (name) {
|
||||
var component = this.inputs[name];
|
||||
this.model[name] = component.state._value;
|
||||
}.bind(this));
|
||||
getModel: function () {
|
||||
var currentValues = this.getCurrentValues();
|
||||
return this.mapModel(currentValues);
|
||||
},
|
||||
|
||||
// Reset each key in the model to the original / initial / specified value
|
||||
resetModel: function (data) {
|
||||
Object.keys(this.inputs).forEach(function (name) {
|
||||
if (data && data[name]) {
|
||||
this.inputs[name].setValue(data[name]);
|
||||
this.inputs.forEach(component => {
|
||||
var name = component.props.name;
|
||||
if (data && data.hasOwnProperty(name)) {
|
||||
component.setValue(data[name]);
|
||||
} else {
|
||||
this.inputs[name].resetValue();
|
||||
component.resetValue();
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
this.validateForm();
|
||||
},
|
||||
|
||||
setInputValidationErrors: function (errors) {
|
||||
Object.keys(this.inputs).forEach(function (name, index) {
|
||||
var component = this.inputs[name];
|
||||
this.inputs.forEach(component => {
|
||||
var name = component.props.name;
|
||||
var args = [{
|
||||
_isValid: !(name in errors),
|
||||
_validationError: typeof errors[name] === 'string' ? [errors[name]] : errors[name]
|
||||
}];
|
||||
component.setState.apply(component, args);
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
|
||||
// Checks if the values have changed from their initial value
|
||||
|
|
@ -172,9 +169,8 @@ Formsy.Form = React.createClass({
|
|||
},
|
||||
|
||||
getPristineValues: function() {
|
||||
var inputs = this.inputs;
|
||||
return Object.keys(inputs).reduce(function (data, name) {
|
||||
var component = inputs[name];
|
||||
return this.inputs.reduce((data, component) => {
|
||||
var name = component.props.name;
|
||||
data[name] = component.props.value;
|
||||
return data;
|
||||
}, {});
|
||||
|
|
@ -184,51 +180,18 @@ Formsy.Form = React.createClass({
|
|||
// stored in the inputs map. Change their state to invalid
|
||||
// and set the serverError message
|
||||
updateInputsWithError: function (errors) {
|
||||
Object.keys(errors).forEach(function (name, index) {
|
||||
var component = this.inputs[name];
|
||||
|
||||
Object.keys(errors).forEach((name, index) => {
|
||||
var component = utils.find(this.inputs, component => component.props.name === name);
|
||||
if (!component) {
|
||||
throw new Error('You are trying to update an input that does not exist. Verify errors object with input names. ' + JSON.stringify(errors));
|
||||
throw new Error('You are trying to update an input that does not exist. ' +
|
||||
'Verify errors object with input names. ' + JSON.stringify(errors));
|
||||
}
|
||||
var args = [{
|
||||
_isValid: this.props.preventExternalInvalidation || false,
|
||||
_externalError: typeof errors[name] === 'string' ? [errors[name]] : errors[name]
|
||||
}];
|
||||
component.setState.apply(component, args);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
// Traverse the children and children of children to find
|
||||
// all inputs by checking the name prop. Maybe do a better
|
||||
// check here
|
||||
traverseChildrenAndRegisterInputs: function (children) {
|
||||
|
||||
if (typeof children !== 'object' || children === null) {
|
||||
return children;
|
||||
}
|
||||
return React.Children.map(children, function (child) {
|
||||
|
||||
if (typeof child !== 'object' || child === null) {
|
||||
return child;
|
||||
}
|
||||
|
||||
if (child.props && child.props.name) {
|
||||
|
||||
return React.cloneElement(child, {
|
||||
_attachToForm: this.attachToForm,
|
||||
_detachFromForm: this.detachFromForm,
|
||||
_validate: this.validate,
|
||||
_isFormDisabled: this.isFormDisabled,
|
||||
_isValidValue: function (component, value) {
|
||||
return this.runValidation(component, value).isValid;
|
||||
}.bind(this)
|
||||
}, child.props && child.props.children);
|
||||
} else {
|
||||
return React.cloneElement(child, {}, this.traverseChildrenAndRegisterInputs(child.props && child.props.children));
|
||||
}
|
||||
|
||||
}, this);
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
isFormDisabled: function () {
|
||||
|
|
@ -236,30 +199,26 @@ Formsy.Form = React.createClass({
|
|||
},
|
||||
|
||||
getCurrentValues: function () {
|
||||
return Object.keys(this.inputs).reduce(function (data, name) {
|
||||
var component = this.inputs[name];
|
||||
return this.inputs.reduce((data, component) => {
|
||||
var name = component.props.name;
|
||||
data[name] = component.state._value;
|
||||
return data;
|
||||
}.bind(this), {});
|
||||
}, {});
|
||||
},
|
||||
|
||||
setFormPristine: function (isPristine) {
|
||||
var inputs = this.inputs;
|
||||
var inputKeys = Object.keys(inputs);
|
||||
|
||||
this.setState({
|
||||
_formSubmitted: !isPristine
|
||||
})
|
||||
_formSubmitted: !isPristine
|
||||
});
|
||||
|
||||
// Iterate through each component and set it as pristine
|
||||
// or "dirty".
|
||||
inputKeys.forEach(function (name, index) {
|
||||
var component = inputs[name];
|
||||
this.inputs.forEach((component, index) => {
|
||||
component.setState({
|
||||
_formSubmitted: !isPristine,
|
||||
_isPristine: isPristine
|
||||
});
|
||||
}.bind(this));
|
||||
});
|
||||
},
|
||||
|
||||
// Use the binded values and the actual input value to
|
||||
|
|
@ -309,7 +268,7 @@ Formsy.Form = React.createClass({
|
|||
error: (function () {
|
||||
|
||||
if (isValid && !isRequired) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
if (validationResults.errors.length) {
|
||||
|
|
@ -393,16 +352,13 @@ Formsy.Form = React.createClass({
|
|||
// Validate the form by going through all child input components
|
||||
// and check their state
|
||||
validateForm: function () {
|
||||
var allIsValid;
|
||||
var inputs = this.inputs;
|
||||
var inputKeys = Object.keys(inputs);
|
||||
|
||||
// We need a callback as we are validating all inputs again. This will
|
||||
// run when the last component has set its state
|
||||
var onValidationComplete = function () {
|
||||
allIsValid = inputKeys.every(function (name) {
|
||||
return inputs[name].state._isValid;
|
||||
}.bind(this));
|
||||
var allIsValid = this.inputs.every(component => {
|
||||
return component.state._isValid;
|
||||
});
|
||||
|
||||
this.setState({
|
||||
isValid: allIsValid
|
||||
|
|
@ -423,8 +379,7 @@ Formsy.Form = React.createClass({
|
|||
|
||||
// Run validation again in case affected by other inputs. The
|
||||
// last component validated will run the onValidationComplete callback
|
||||
inputKeys.forEach(function (name, index) {
|
||||
var component = inputs[name];
|
||||
this.inputs.forEach((component, index) => {
|
||||
var validation = this.runValidation(component);
|
||||
if (validation.isValid && component.state._externalError) {
|
||||
validation.isValid = false;
|
||||
|
|
@ -434,12 +389,12 @@ Formsy.Form = React.createClass({
|
|||
_isRequired: validation.isRequired,
|
||||
_validationError: validation.error,
|
||||
_externalError: !validation.isValid && component.state._externalError ? component.state._externalError : null
|
||||
}, index === inputKeys.length - 1 ? onValidationComplete : null);
|
||||
}.bind(this));
|
||||
}, index === this.inputs.length - 1 ? onValidationComplete : null);
|
||||
});
|
||||
|
||||
// If there are no inputs, set state where form is ready to trigger
|
||||
// change event. New inputs might be added later
|
||||
if (!inputKeys.length && this.isMounted()) {
|
||||
if (!this.inputs.length) {
|
||||
this.setState({
|
||||
canChange: true
|
||||
});
|
||||
|
|
@ -449,23 +404,46 @@ Formsy.Form = React.createClass({
|
|||
// Method put on each input component to register
|
||||
// itself to the form
|
||||
attachToForm: function (component) {
|
||||
this.inputs[component.props.name] = component;
|
||||
this.model[component.props.name] = component.state._value;
|
||||
|
||||
if (this.inputs.indexOf(component) === -1) {
|
||||
this.inputs.push(component);
|
||||
}
|
||||
|
||||
this.validate(component);
|
||||
},
|
||||
|
||||
// Method put on each input component to unregister
|
||||
// itself from the form
|
||||
detachFromForm: function (component) {
|
||||
delete this.inputs[component.props.name];
|
||||
delete this.model[component.props.name];
|
||||
var componentPos = this.inputs.indexOf(component);
|
||||
|
||||
if (componentPos !== -1) {
|
||||
this.inputs = this.inputs.slice(0, componentPos)
|
||||
.concat(this.inputs.slice(componentPos + 1));
|
||||
}
|
||||
|
||||
this.validateForm();
|
||||
},
|
||||
render: function () {
|
||||
var {
|
||||
mapping,
|
||||
validationErrors,
|
||||
onSubmit,
|
||||
onValid,
|
||||
onValidSubmit,
|
||||
onInvalid,
|
||||
onInvalidSubmit,
|
||||
onChange,
|
||||
reset,
|
||||
preventExternalInvalidation,
|
||||
onSuccess,
|
||||
onError,
|
||||
...nonFormsyProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<form {...this.props} onSubmit={this.submit}>
|
||||
<form {...nonFormsyProps} onSubmit={this.submit}>
|
||||
{this.props.children}
|
||||
{/*this.traverseChildrenAndRegisterInputs(this.props.children)*/}
|
||||
</form>
|
||||
);
|
||||
|
||||
|
|
|
|||
14
src/utils.js
14
src/utils.js
|
|
@ -30,12 +30,24 @@ module.exports = {
|
|||
isSame: function (a, b) {
|
||||
if (typeof a !== typeof b) {
|
||||
return false;
|
||||
} else if (Array.isArray(a)) {
|
||||
} else if (Array.isArray(a) && Array.isArray(b)) {
|
||||
return !this.arraysDiffer(a, b);
|
||||
} else if (typeof a === 'function') {
|
||||
return a.toString() === b.toString();
|
||||
} else if (typeof a === 'object' && a !== null && b !== null) {
|
||||
return !this.objectsDiffer(a, b);
|
||||
}
|
||||
|
||||
return a === b;
|
||||
},
|
||||
|
||||
find: function (collection, fn) {
|
||||
for (var i = 0, l = collection.length; i < l; i++) {
|
||||
var item = collection[i];
|
||||
if (fn(item)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
require('babel/register');
|
||||
|
||||
var path = require('path');
|
||||
var jsdom = require('jsdom').jsdom;
|
||||
var jasmine = require('jasmine-node');
|
||||
import path from 'path';
|
||||
import testrunner from 'nodeunit/lib/reporters/default.js';
|
||||
import {jsdom} from 'jsdom';
|
||||
|
||||
global.document = jsdom();
|
||||
global.window = document.defaultView;
|
||||
global.navigator = global.window.navigator;
|
||||
|
||||
var jasmineOptions = {
|
||||
specFolders: [path.resolve(__dirname, 'specs')],
|
||||
isVerbose: true,
|
||||
showColors: true,
|
||||
teamcity: false,
|
||||
useRequireJs: false,
|
||||
regExpSpec: /spec\.js$/,
|
||||
junitreport: true,
|
||||
includeStackTrace: true
|
||||
};
|
||||
|
||||
jasmine.executeSpecsInFolder(jasmineOptions);
|
||||
testrunner.run(['tests'], {
|
||||
"error_prefix": "\u001B[31m",
|
||||
"error_suffix": "\u001B[39m",
|
||||
"ok_prefix": "\u001B[32m",
|
||||
"ok_suffix": "\u001B[39m",
|
||||
"bold_prefix": "\u001B[1m",
|
||||
"bold_suffix": "\u001B[22m",
|
||||
"assertion_prefix": "\u001B[35m",
|
||||
"assertion_suffix": "\u001B[39m"
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import Formsy from './..';
|
||||
import TestInput, { customizeInput } from './utils/TestInput';
|
||||
import TestInput, { InputFactory } from './utils/TestInput';
|
||||
import immediate from './utils/immediate';
|
||||
|
||||
describe('Element', function () {
|
||||
export default {
|
||||
|
||||
it('should return passed and setValue() value when using getValue()', function () {
|
||||
'should return passed and setValue() value when using getValue()': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
|
|
@ -16,16 +18,18 @@ describe('Element', function () {
|
|||
);
|
||||
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
expect(input.value).toBe('foo');
|
||||
test.equal(input.value, 'foo');
|
||||
TestUtils.Simulate.change(input, {target: {value: 'foobar'}});
|
||||
expect(input.value).toBe('foobar');
|
||||
test.equal(input.value, 'foobar');
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should set back to pristine value when running reset', function () {
|
||||
},
|
||||
|
||||
'should set back to pristine value when running reset': function (test) {
|
||||
|
||||
let reset = null;
|
||||
const Input = customizeInput({
|
||||
const Input = InputFactory({
|
||||
componentDidMount() {
|
||||
reset = this.resetValue;
|
||||
}
|
||||
|
|
@ -39,14 +43,16 @@ describe('Element', function () {
|
|||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
TestUtils.Simulate.change(input, {target: {value: 'foobar'}});
|
||||
reset();
|
||||
expect(input.value).toBe('foo');
|
||||
test.equal(input.value, 'foo');
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should return error message passed when calling getErrorMessage()', function () {
|
||||
},
|
||||
|
||||
'should return error message passed when calling getErrorMessage()': function (test) {
|
||||
|
||||
let getErrorMessage = null;
|
||||
const Input = customizeInput({
|
||||
const Input = InputFactory({
|
||||
componentDidMount() {
|
||||
getErrorMessage = this.getErrorMessage;
|
||||
}
|
||||
|
|
@ -57,14 +63,16 @@ describe('Element', function () {
|
|||
</Formsy.Form>
|
||||
);
|
||||
|
||||
expect(getErrorMessage()).toBe('Has to be email');
|
||||
test.equal(getErrorMessage(), 'Has to be email');
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should return true or false when calling isValid() depending on valid state', function () {
|
||||
},
|
||||
|
||||
'should return true or false when calling isValid() depending on valid state': function (test) {
|
||||
|
||||
let isValid = null;
|
||||
const Input = customizeInput({
|
||||
const Input = InputFactory({
|
||||
componentDidMount() {
|
||||
isValid = this.isValid;
|
||||
}
|
||||
|
|
@ -75,17 +83,19 @@ describe('Element', function () {
|
|||
</Formsy.Form>
|
||||
);
|
||||
|
||||
expect(isValid()).toBe(false);
|
||||
test.equal(isValid(), false);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
TestUtils.Simulate.change(input, {target: {value: 'foo@foo.com'}});
|
||||
expect(isValid()).toBe(true);
|
||||
test.equal(isValid(), true);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should return true or false when calling isRequired() depending on passed required attribute', function () {
|
||||
},
|
||||
|
||||
'should return true or false when calling isRequired() depending on passed required attribute': function (test) {
|
||||
|
||||
const isRequireds = [];
|
||||
const Input = customizeInput({
|
||||
const Input = InputFactory({
|
||||
componentDidMount() {
|
||||
isRequireds.push(this.isRequired);
|
||||
}
|
||||
|
|
@ -98,16 +108,18 @@ describe('Element', function () {
|
|||
</Formsy.Form>
|
||||
);
|
||||
|
||||
expect(isRequireds[0]()).toBe(false);
|
||||
expect(isRequireds[1]()).toBe(true);
|
||||
expect(isRequireds[2]()).toBe(true);
|
||||
test.equal(isRequireds[0](), false);
|
||||
test.equal(isRequireds[1](), true);
|
||||
test.equal(isRequireds[2](), true);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should return true or false when calling showRequired() depending on input being empty and required is passed, or not', function () {
|
||||
},
|
||||
|
||||
'should return true or false when calling showRequired() depending on input being empty and required is passed, or not': function (test) {
|
||||
|
||||
const showRequireds = [];
|
||||
const Input = customizeInput({
|
||||
const Input = InputFactory({
|
||||
componentDidMount() {
|
||||
showRequireds.push(this.showRequired);
|
||||
}
|
||||
|
|
@ -120,16 +132,18 @@ describe('Element', function () {
|
|||
</Formsy.Form>
|
||||
);
|
||||
|
||||
expect(showRequireds[0]()).toBe(false);
|
||||
expect(showRequireds[1]()).toBe(true);
|
||||
expect(showRequireds[2]()).toBe(false);
|
||||
test.equal(showRequireds[0](), false);
|
||||
test.equal(showRequireds[1](), true);
|
||||
test.equal(showRequireds[2](), false);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should return true or false when calling isPristine() depending on input has been "touched" or not', function () {
|
||||
},
|
||||
|
||||
'should return true or false when calling isPristine() depending on input has been "touched" or not': function (test) {
|
||||
|
||||
let isPristine = null;
|
||||
const Input = customizeInput({
|
||||
const Input = InputFactory({
|
||||
componentDidMount() {
|
||||
isPristine = this.isPristine;
|
||||
}
|
||||
|
|
@ -140,14 +154,16 @@ describe('Element', function () {
|
|||
</Formsy.Form>
|
||||
);
|
||||
|
||||
expect(isPristine()).toBe(true);
|
||||
test.equal(isPristine(), true);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
TestUtils.Simulate.change(input, {target: {value: 'foo'}});
|
||||
expect(isPristine()).toBe(false);
|
||||
test.equal(isPristine(), false);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should allow an undefined value to be updated to a value', function (done) {
|
||||
},
|
||||
|
||||
'should allow an undefined value to be updated to a value': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() {
|
||||
|
|
@ -171,13 +187,13 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
form.changeValue();
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
immediate(() => {
|
||||
expect(input.value).toBe('foo');
|
||||
done();
|
||||
test.equal(input.value, 'foo');
|
||||
test.done();
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should be able to test a values validity', function () {
|
||||
'should be able to test a values validity': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -191,12 +207,13 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(input.isValidValue('foo@bar.com')).toBe(true);
|
||||
expect(input.isValidValue('foo@bar')).toBe(false);
|
||||
test.equal(input.isValidValue('foo@bar.com'), true);
|
||||
test.equal(input.isValidValue('foo@bar'), false);
|
||||
test.done();
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should be able to use an object as validations property', function () {
|
||||
'should be able to use an object as validations property': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -212,12 +229,14 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(input.isValidValue('foo@bar.com')).toBe(true);
|
||||
expect(input.isValidValue('foo@bar')).toBe(false);
|
||||
test.equal(input.isValidValue('foo@bar.com'), true);
|
||||
test.equal(input.isValidValue('foo@bar'), false);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should be able to pass complex values to a validation rule', function () {
|
||||
},
|
||||
|
||||
'should be able to pass complex values to a validation rule': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -233,14 +252,16 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(inputComponent.isValid()).toBe(true);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
|
||||
expect(inputComponent.isValid()).toBe(false);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should be able to run a function to validate', function () {
|
||||
},
|
||||
|
||||
'should be able to run a function to validate': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
customValidationA(values, value) {
|
||||
|
|
@ -265,16 +286,41 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const inputComponent = TestUtils.scryRenderedComponentsWithType(form, TestInput);
|
||||
expect(inputComponent[0].isValid()).toBe(true);
|
||||
expect(inputComponent[1].isValid()).toBe(true);
|
||||
test.equal(inputComponent[0].isValid(), true);
|
||||
test.equal(inputComponent[1].isValid(), true);
|
||||
const input = TestUtils.scryRenderedDOMComponentsWithTag(form, 'INPUT');
|
||||
TestUtils.Simulate.change(input[0], {target: {value: 'bar'}});
|
||||
expect(inputComponent[0].isValid()).toBe(false);
|
||||
expect(inputComponent[1].isValid()).toBe(false);
|
||||
test.equal(inputComponent[0].isValid(), false);
|
||||
test.equal(inputComponent[1].isValid(), false);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should override all error messages with error messages passed by form', function () {
|
||||
},
|
||||
|
||||
'should not override error messages with error messages passed by form if passed eror messages is an empty object': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form validationErrors={{}}>
|
||||
<TestInput name="A" validations={{
|
||||
isEmail: true
|
||||
}} validationError="bar2" validationErrors={{isEmail: 'bar3'}} value="foo"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.getErrorMessage(), 'bar3');
|
||||
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
|
||||
'should override all error messages with error messages passed by form': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -290,11 +336,13 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(inputComponent.getErrorMessage()).toBe('bar');
|
||||
test.equal(inputComponent.getErrorMessage(), 'bar');
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should override validation rules with required rules', function () {
|
||||
},
|
||||
|
||||
'should override validation rules with required rules': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -318,11 +366,13 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(inputComponent.getErrorMessage()).toBe('bar3');
|
||||
test.equal(inputComponent.getErrorMessage(), 'bar3');
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should fall back to default error message when non exist in validationErrors map', function () {
|
||||
},
|
||||
|
||||
'should fall back to default error message when non exist in validationErrors map': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -343,11 +393,13 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(inputComponent.getErrorMessage()).toBe('bar');
|
||||
test.equal(inputComponent.getErrorMessage(), 'bar');
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should not be valid if it is required and required rule is true', function () {
|
||||
},
|
||||
|
||||
'should not be valid if it is required and required rule is true': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -363,11 +415,13 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(inputComponent.isValid()).toBe(false);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should handle objects and arrays as values', function () {
|
||||
},
|
||||
|
||||
'should handle objects and arrays as values': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() {
|
||||
|
|
@ -393,12 +447,14 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
});
|
||||
|
||||
const inputs = TestUtils.scryRenderedComponentsWithType(form, TestInput);
|
||||
expect(inputs[0].getValue()).toEqual({foo: 'foo'});
|
||||
expect(inputs[1].getValue()).toEqual(['bar']);
|
||||
test.deepEqual(inputs[0].getValue(), {foo: 'foo'});
|
||||
test.deepEqual(inputs[1].getValue(), ['bar']);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should handle isFormDisabled with dynamic inputs', function () {
|
||||
},
|
||||
|
||||
'should handle isFormDisabled with dynamic inputs': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() {
|
||||
|
|
@ -425,17 +481,19 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
expect(input.isFormDisabled()).toBe(true);
|
||||
test.equal(input.isFormDisabled(), true);
|
||||
form.flip();
|
||||
expect(input.isFormDisabled()).toBe(false);
|
||||
test.equal(input.isFormDisabled(), false);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should allow for dot notation in name which maps to a deep object', function () {
|
||||
},
|
||||
|
||||
'should allow for dot notation in name which maps to a deep object': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
onSubmit(model) {
|
||||
expect(model).toEqual({foo: {bar: 'foo', test: 'test'}});
|
||||
test.deepEqual(model, {foo: {bar: 'foo', test: 'test'}});
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
|
|
@ -448,16 +506,20 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
test.expect(1);
|
||||
|
||||
const formEl = TestUtils.findRenderedDOMComponentWithTag(form, 'form');
|
||||
TestUtils.Simulate.submit(formEl);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
it('should allow for application/x-www-form-urlencoded syntax and convert to object', function () {
|
||||
},
|
||||
|
||||
'should allow for application/x-www-form-urlencoded syntax and convert to object': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
onSubmit(model) {
|
||||
expect(model).toEqual({foo: ['foo', 'bar']});
|
||||
test.deepEqual(model, {foo: ['foo', 'bar']});
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
|
|
@ -470,9 +532,37 @@ it('should allow an undefined value to be updated to a value', function (done) {
|
|||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
test.expect(1);
|
||||
|
||||
const formEl = TestUtils.findRenderedDOMComponentWithTag(form, 'form');
|
||||
TestUtils.Simulate.submit(formEl);
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
'input should rendered once with PureRenderMixin': function (test) {
|
||||
|
||||
var renderSpy = sinon.spy();
|
||||
|
||||
const Input = InputFactory({
|
||||
mixins: [Formsy.Mixin, PureRenderMixin],
|
||||
render() {
|
||||
renderSpy();
|
||||
return <input type={this.props.type} value={this.getValue()} onChange={this.updateValue}/>;
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" value="foo"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
test.equal(renderSpy.calledOnce, true);
|
||||
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,748 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import TestInput from './utils/TestInput';
|
||||
import TestInputHoc from './utils/TestInputHoc';
|
||||
import immediate from './utils/immediate';
|
||||
import sinon from 'sinon';
|
||||
|
||||
export default {
|
||||
|
||||
'Setting up a form': {
|
||||
'should expose the users DOM node through an innerRef prop': function (test) {
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInputHoc name="name" innerRef={(c) => { this.name = c; }} />
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const input = form.name;
|
||||
test.equal(input.methodOnWrappedInstance('foo'), 'foo');
|
||||
|
||||
test.done();
|
||||
},
|
||||
|
||||
'should render a form into the document': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<Formsy.Form></Formsy.Form>);
|
||||
test.equal(ReactDOM.findDOMNode(form).tagName, 'FORM');
|
||||
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should set a class name if passed': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument( <Formsy.Form className="foo"></Formsy.Form>);
|
||||
test.equal(ReactDOM.findDOMNode(form).className, 'foo');
|
||||
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should allow for null/undefined children': function (test) {
|
||||
|
||||
let model = null;
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={(formModel) => (model = formModel)}>
|
||||
<h1>Test</h1>
|
||||
{ null }
|
||||
{ undefined }
|
||||
<TestInput name="name" value={ 'foo' } />
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
immediate(() => {
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
|
||||
test.deepEqual(model, {name: 'foo'});
|
||||
test.done();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
'should allow for inputs being added dynamically': function (test) {
|
||||
|
||||
const inputs = [];
|
||||
let forceUpdate = null;
|
||||
let model = null;
|
||||
const TestForm = React.createClass({
|
||||
componentWillMount() {
|
||||
forceUpdate = this.forceUpdate.bind(this);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={(formModel) => (model = formModel)}>
|
||||
{inputs}
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
// Wait before adding the input
|
||||
setTimeout(() => {
|
||||
inputs.push(<TestInput name="test" value="" key={inputs.length}/>);
|
||||
|
||||
forceUpdate(() => {
|
||||
// Wait for next event loop, as that does the form
|
||||
immediate(() => {
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
|
||||
test.ok('test' in model);
|
||||
test.done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}, 10);
|
||||
|
||||
},
|
||||
|
||||
'should allow dynamically added inputs to update the form-model': function (test) {
|
||||
|
||||
const inputs = [];
|
||||
let forceUpdate = null;
|
||||
let model = null;
|
||||
const TestForm = React.createClass({
|
||||
componentWillMount() {
|
||||
forceUpdate = this.forceUpdate.bind(this);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={(formModel) => (model = formModel)}>
|
||||
{inputs}
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
// Wait before adding the input
|
||||
immediate(() => {
|
||||
inputs.push(<TestInput name="test" key={inputs.length}/>);
|
||||
|
||||
forceUpdate(() => {
|
||||
|
||||
// Wait for next event loop, as that does the form
|
||||
immediate(() => {
|
||||
TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'foo'}});
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
|
||||
test.equal(model.test, 'foo');
|
||||
test.done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
'should allow a dynamically updated input to update the form-model': function (test) {
|
||||
|
||||
let forceUpdate = null;
|
||||
let model = null;
|
||||
|
||||
const TestForm = React.createClass({
|
||||
componentWillMount() {
|
||||
forceUpdate = this.forceUpdate.bind(this);
|
||||
},
|
||||
render() {
|
||||
const input = <TestInput name="test" value={this.props.value} />;
|
||||
|
||||
return (
|
||||
<Formsy.Form onSubmit={(formModel) => (model = formModel)}>
|
||||
{input}
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
let form = TestUtils.renderIntoDocument(<TestForm value="foo"/>);
|
||||
|
||||
// Wait before changing the input
|
||||
immediate(() => {
|
||||
form = TestUtils.renderIntoDocument(<TestForm value="bar"/>);
|
||||
|
||||
forceUpdate(() => {
|
||||
// Wait for next event loop, as that does the form
|
||||
immediate(() => {
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
|
||||
test.equal(model.test, 'bar');
|
||||
test.done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'validations': {
|
||||
|
||||
'should run when the input changes': function (test) {
|
||||
|
||||
const runRule = sinon.spy();
|
||||
const notRunRule = sinon.spy();
|
||||
|
||||
Formsy.addValidationRule('runRule', runRule);
|
||||
Formsy.addValidationRule('notRunRule', notRunRule);
|
||||
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="one" validations="runRule" value="foo"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(ReactDOM.findDOMNode(input), {target: {value: 'bar'}});
|
||||
test.equal(runRule.calledWith({one: 'bar'}, 'bar', true), true);
|
||||
test.equal(notRunRule.called, false);
|
||||
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should allow the validation to be changed': function (test) {
|
||||
|
||||
const ruleA = sinon.spy();
|
||||
const ruleB = sinon.spy();
|
||||
Formsy.addValidationRule('ruleA', ruleA);
|
||||
Formsy.addValidationRule('ruleB', ruleB);
|
||||
|
||||
class TestForm extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {rule: 'ruleA'};
|
||||
}
|
||||
changeRule() {
|
||||
this.setState({
|
||||
rule: 'ruleB'
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="one" validations={this.state.rule} value="foo"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
form.changeRule();
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(ReactDOM.findDOMNode(input), {target: {value: 'bar'}});
|
||||
test.equal(ruleB.calledWith({one: 'bar'}, 'bar', true), true);
|
||||
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should invalidate a form if dynamically inserted input is invalid': function (test) {
|
||||
|
||||
const isInValidSpy = sinon.spy();
|
||||
|
||||
class TestForm extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {showSecondInput: false};
|
||||
}
|
||||
addInput() {
|
||||
this.setState({
|
||||
showSecondInput: true
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form ref="formsy" onInvalid={isInValidSpy}>
|
||||
<TestInput name="one" validations="isEmail" value="foo@bar.com"/>
|
||||
{
|
||||
this.state.showSecondInput ?
|
||||
<TestInput name="two" validations="isEmail" value="foo@bar"/>
|
||||
:
|
||||
null
|
||||
}
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
test.equal(form.refs.formsy.state.isValid, true);
|
||||
form.addInput();
|
||||
|
||||
immediate(() => {
|
||||
test.equal(isInValidSpy.called, true);
|
||||
test.done();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
'should validate a form when removing an invalid input': function (test) {
|
||||
|
||||
const isValidSpy = sinon.spy();
|
||||
|
||||
class TestForm extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {showSecondInput: true};
|
||||
}
|
||||
removeInput() {
|
||||
this.setState({
|
||||
showSecondInput: false
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form ref="formsy" onValid={isValidSpy}>
|
||||
<TestInput name="one" validations="isEmail" value="foo@bar.com"/>
|
||||
{
|
||||
this.state.showSecondInput ?
|
||||
<TestInput name="two" validations="isEmail" value="foo@bar"/>
|
||||
:
|
||||
null
|
||||
}
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
test.equal(form.refs.formsy.state.isValid, false);
|
||||
form.removeInput();
|
||||
|
||||
immediate(() => {
|
||||
test.equal(isValidSpy.called, true);
|
||||
test.done();
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
'runs multiple validations': function (test) {
|
||||
|
||||
const ruleA = sinon.spy();
|
||||
const ruleB = sinon.spy();
|
||||
Formsy.addValidationRule('ruleA', ruleA);
|
||||
Formsy.addValidationRule('ruleB', ruleB);
|
||||
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<TestInput name="one" validations="ruleA,ruleB" value="foo" />
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(ReactDOM.findDOMNode(input), {target: {value: 'bar'}});
|
||||
test.equal(ruleA.calledWith({one: 'bar'}, 'bar', true), true);
|
||||
test.equal(ruleB.calledWith({one: 'bar'}, 'bar', true), true);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'should not trigger onChange when form is mounted': function (test) {
|
||||
|
||||
|
||||
const hasChanged = sinon.spy();
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return <Formsy.Form onChange={hasChanged}></Formsy.Form>;
|
||||
}
|
||||
});
|
||||
TestUtils.renderIntoDocument(<TestForm/>);
|
||||
test.equal(hasChanged.called, false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should trigger onChange once when form element is changed': function (test) {
|
||||
|
||||
const hasChanged = sinon.spy();
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onChange={hasChanged}>
|
||||
<TestInput name="foo"/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'bar'}});
|
||||
test.equal(hasChanged.calledOnce, true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should trigger onChange once when new input is added to form': function (test) {
|
||||
|
||||
const hasChanged = sinon.spy();
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
showInput: false
|
||||
};
|
||||
},
|
||||
addInput() {
|
||||
this.setState({
|
||||
showInput: true
|
||||
})
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onChange={hasChanged}>
|
||||
{
|
||||
this.state.showInput ?
|
||||
<TestInput name="test"/>
|
||||
:
|
||||
null
|
||||
}
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
form.addInput();
|
||||
immediate(() => {
|
||||
test.equal(hasChanged.calledOnce, true);
|
||||
test.done();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
'Update a form': {
|
||||
|
||||
'should allow elements to check if the form is disabled': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() { return { disabled: true }; },
|
||||
enableForm() { this.setState({ disabled: false }); },
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form disabled={this.state.disabled}>
|
||||
<TestInput name="foo"/>
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(input.isFormDisabled(), true);
|
||||
|
||||
form.enableForm();
|
||||
immediate(() => {
|
||||
test.equal(input.isFormDisabled(), false);
|
||||
test.done();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
'should be possible to pass error state of elements by changing an errors attribute': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() { return { validationErrors: { foo: 'bar' } }; },
|
||||
onChange(values) {
|
||||
this.setState(values.foo ? { validationErrors: {} } : { validationErrors: {foo: 'bar'} });
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onChange={this.onChange} validationErrors={this.state.validationErrors}>
|
||||
<TestInput name="foo"/>
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
// Wait for update
|
||||
immediate(() => {
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(input.getErrorMessage(), 'bar');
|
||||
input.setValue('gotValue');
|
||||
|
||||
// Wait for update
|
||||
immediate(() => {
|
||||
test.equal(input.getErrorMessage(), null);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
'should trigger an onValidSubmit when submitting a valid form': function (test) {
|
||||
|
||||
let isCalled = sinon.spy();
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onValidSubmit={isCalled}>
|
||||
<TestInput name="foo" validations="isEmail" value="foo@bar.com"/>
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const FoundForm = TestUtils.findRenderedComponentWithType(form, TestForm);
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(FoundForm));
|
||||
test.equal(isCalled.called,true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should trigger an onInvalidSubmit when submitting an invalid form': function (test) {
|
||||
|
||||
let isCalled = sinon.spy();
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onInvalidSubmit={isCalled}>
|
||||
<TestInput name="foo" validations="isEmail" value="foo@bar"/>
|
||||
</Formsy.Form>);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
|
||||
const FoundForm = TestUtils.findRenderedComponentWithType(form, TestForm);
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(FoundForm));
|
||||
test.equal(isCalled.called, true);
|
||||
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'value === false': {
|
||||
|
||||
'should call onSubmit correctly': function (test) {
|
||||
|
||||
const onSubmit = sinon.spy();
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={onSubmit}>
|
||||
<TestInput name="foo" value={false} type="checkbox" />
|
||||
<button type="submit">Save</button>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
|
||||
test.equal(onSubmit.calledWith({foo: false}), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should allow dynamic changes to false': function (test) {
|
||||
|
||||
const onSubmit = sinon.spy();
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
value: true
|
||||
};
|
||||
},
|
||||
changeValue() {
|
||||
this.setState({
|
||||
value: false
|
||||
});
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form onSubmit={onSubmit}>
|
||||
<TestInput name="foo" value={this.state.value} type="checkbox" />
|
||||
<button type="submit">Save</button>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
form.changeValue();
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
|
||||
test.equal(onSubmit.calledWith({foo: false}), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should say the form is submitted': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value={true} type="checkbox" />
|
||||
<button type="submit">Save</button>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(input.isFormSubmitted(), false);
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
|
||||
test.equal(input.isFormSubmitted(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should be able to reset the form to its pristine state': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
value: true
|
||||
};
|
||||
},
|
||||
changeValue() {
|
||||
this.setState({
|
||||
value: false
|
||||
});
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value={this.state.value} type="checkbox" />
|
||||
<button type="submit">Save</button>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
const formsyForm = TestUtils.findRenderedComponentWithType(form, Formsy.Form);
|
||||
test.equal(input.getValue(), true);
|
||||
form.changeValue();
|
||||
test.equal(input.getValue(), false);
|
||||
formsyForm.reset();
|
||||
test.equal(input.getValue(), true);
|
||||
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should be able to reset the form using custom data': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
value: true
|
||||
};
|
||||
},
|
||||
changeValue() {
|
||||
this.setState({
|
||||
value: false
|
||||
});
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value={this.state.value} type="checkbox" />
|
||||
<button type="submit">Save</button>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
const formsyForm = TestUtils.findRenderedComponentWithType(form, Formsy.Form);
|
||||
|
||||
test.equal(input.getValue(), true);
|
||||
form.changeValue();
|
||||
test.equal(input.getValue(), false);
|
||||
formsyForm.reset({
|
||||
foo: 'bar'
|
||||
});
|
||||
test.equal(input.getValue(), 'bar');
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'should be able to reset the form to empty values': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" value="42" type="checkbox" />
|
||||
<button type="submit">Save</button>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
const formsyForm = TestUtils.findRenderedComponentWithType(form, Formsy.Form);
|
||||
|
||||
formsyForm.reset({
|
||||
foo: ''
|
||||
});
|
||||
test.equal(input.getValue(), '');
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'.isChanged()': {
|
||||
|
||||
'initially returns false': function (test) {
|
||||
|
||||
const hasOnChanged = sinon.spy();
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onChange={hasOnChanged}>
|
||||
<TestInput name="one" value="foo" />
|
||||
</Formsy.Form>
|
||||
);
|
||||
test.equal(form.isChanged(), false);
|
||||
test.equal(hasOnChanged.called, false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'returns true when changed': function (test) {
|
||||
|
||||
const hasOnChanged = sinon.spy();
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onChange={hasOnChanged}>
|
||||
<TestInput name="one" value="foo" />
|
||||
</Formsy.Form>
|
||||
);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(ReactDOM.findDOMNode(input), {target: {value: 'bar'}});
|
||||
test.equal(form.isChanged(), true);
|
||||
test.equal(hasOnChanged.calledWith({one: 'bar'}), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'returns false if changes are undone': function (test) {
|
||||
|
||||
const hasOnChanged = sinon.spy();
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onChange={hasOnChanged}>
|
||||
<TestInput name="one" value="foo" />
|
||||
</Formsy.Form>
|
||||
);
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
|
||||
TestUtils.Simulate.change(ReactDOM.findDOMNode(input), {target: {value: 'bar'}});
|
||||
test.equal(hasOnChanged.calledWith({one: 'bar'}, true), true);
|
||||
|
||||
TestUtils.Simulate.change(ReactDOM.findDOMNode(input), {target: {value: 'foo'}});
|
||||
test.equal(form.isChanged(), false);
|
||||
test.equal(hasOnChanged.calledWith({one: 'foo'}, false), true);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
import immediate from './utils/immediate';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="equals:foo" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass when the value is equal': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="foo"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail when the value is not equal': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="fo"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={''}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isAlpha" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a string is only latin letters': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="myValue"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string with numbers': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="myValue42"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={''}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isAlphanumeric" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a string is only latin letters': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="myValue"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string with numbers': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="myValue42"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={''}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a non alpha and number symbols': function (test) {
|
||||
|
||||
const value = '!@#$%^&*()';
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={value}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isEmail" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with "foo"': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="foo"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with "foo@foo.com"': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="foo@foo.com"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={''}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isEmptyString" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with non-empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="abc"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a zero': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={0}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isExisty" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="abc"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a zero': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={0}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isFloat" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="abc"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a number as string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="+42"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail string with digits': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="42 is an answer"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an int': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a float': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={Math.PI}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a float in science notation': function (test) {
|
||||
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="-1e3"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a zero': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={0}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isInt" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="abc"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a number as string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="+42"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail string with digits': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="42 is an answer"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an int': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a float': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={Math.PI}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a float in science notation': function (test) {
|
||||
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="-1e3"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a zero': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={0}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations={this.props.rule} value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'isLength:3': {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:3"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string too small': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:3" inputValue="hi"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string too long': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:3" inputValue="hi ho happ"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with matching length': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:3" inputValue="foo"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:3" inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:3" inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:3" inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:3" inputValue={123}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'isLength:0': {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:0"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string too small': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:0" inputValue="hi"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string too long': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:0" inputValue="hi ho happ"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with matching length': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:0" inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:0" inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:0" inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:0" inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="isLength:0" inputValue={123}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isNumeric" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with an unempty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="foo"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a number as string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="+42"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number as string with not digits': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="42 is an answer"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an int': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a float': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={Math.PI}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a float in science notation': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="-1e3"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a zero': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={0}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isUrl" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with "foo"': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="foo"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with "https://www.google.com/"': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="https://www.google.com/"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="isWords" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a 1 word': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="sup"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with 2 words': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="sup dude"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a string with numbers': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="sup 42"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations="maxLength:3" value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass when a string\'s length is smaller': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="hi"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass when a string\'s length is equal': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="bar"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail when a string\'s length is bigger': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue="foobar"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
import React from 'react';
|
||||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import { InputFactory } from './utils/TestInput';
|
||||
|
||||
const TestInput = InputFactory({
|
||||
render() {
|
||||
return <input value={this.getValue()} readOnly/>;
|
||||
}
|
||||
});
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<Formsy.Form>
|
||||
<TestInput name="foo" validations={this.props.rule} value={this.props.inputValue}/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
|
||||
'minLength:3': {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:3"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass when a string\'s length is bigger': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:3" inputValue="myValue"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail when a string\'s length is smaller': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:3" inputValue="my"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:3" inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:3" inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:3" inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:3" inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'minLength:0': {
|
||||
|
||||
'should pass with a default value': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:0"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass when a string\'s length is bigger': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:0" inputValue="myValue"/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with empty string': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:0" inputValue=""/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with an undefined': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:0" inputValue={undefined}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should pass with a null': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:0" inputValue={null}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), true);
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
'should fail with a number': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(<TestForm rule="minLength:0" inputValue={42}/>);
|
||||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import utils from './../src/utils.js';
|
||||
|
||||
export default {
|
||||
|
||||
'should check equality of objects and arrays': function (test) {
|
||||
|
||||
const objA = { foo: 'bar' };
|
||||
const objB = { foo: 'bar' };
|
||||
const objC = [{ foo: ['bar'] }];
|
||||
const objD = [{ foo: ['bar'] }];
|
||||
const objE = undefined;
|
||||
const objF = undefined;
|
||||
const objG = null;
|
||||
const objH = null;
|
||||
|
||||
test.equal(utils.isSame(objA, objB), true);
|
||||
test.equal(utils.isSame(objC, objD), true);
|
||||
test.equal(utils.isSame(objA, objD), false);
|
||||
|
||||
test.equal(utils.isSame(objE, objF), true);
|
||||
test.equal(utils.isSame(objA, objF), false);
|
||||
test.equal(utils.isSame(objE, objA), false);
|
||||
|
||||
test.equal(utils.isSame(objG, objH), true);
|
||||
test.equal(utils.isSame(objA, objH), false);
|
||||
test.equal(utils.isSame(objC, objH), false);
|
||||
test.equal(utils.isSame(objG, objA), false);
|
||||
|
||||
test.equal(utils.isSame(() => {}, () => {}), true);
|
||||
test.equal(utils.isSame(objA, () => {}), false);
|
||||
test.equal(utils.isSame(() => {}, objA), false);
|
||||
|
||||
test.done();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -2,12 +2,13 @@ import React from 'react';
|
|||
import TestUtils from 'react-addons-test-utils';
|
||||
|
||||
import Formsy from './..';
|
||||
import TestInput, { customizeInput } from './utils/TestInput';
|
||||
import TestInput, {InputFactory} from './utils/TestInput';
|
||||
import immediate from './utils/immediate';
|
||||
import sinon from 'sinon';
|
||||
|
||||
describe('Validation', function () {
|
||||
export default {
|
||||
|
||||
it('should reset only changed form element when external error is passed', function (done) {
|
||||
'should reset only changed form element when external error is passed': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onSubmit={(model, reset, invalidate) => invalidate({ foo: 'bar', bar: 'foo' })}>
|
||||
|
|
@ -20,19 +21,19 @@ describe('Validation', function () {
|
|||
const inputComponents = TestUtils.scryRenderedComponentsWithType(form, TestInput);
|
||||
|
||||
form.submit();
|
||||
expect(inputComponents[0].isValid()).toBe(false);
|
||||
expect(inputComponents[1].isValid()).toBe(false);
|
||||
test.equal(inputComponents[0].isValid(), false);
|
||||
test.equal(inputComponents[1].isValid(), false);
|
||||
|
||||
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
|
||||
immediate(() => {
|
||||
expect(inputComponents[0].isValid()).toBe(true);
|
||||
expect(inputComponents[1].isValid()).toBe(false);
|
||||
done();
|
||||
test.equal(inputComponents[0].isValid(), true);
|
||||
test.equal(inputComponents[1].isValid(), false);
|
||||
test.done();
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should let normal validation take over when component with external error is changed', function (done) {
|
||||
'should let normal validation take over when component with external error is changed': function (test) {
|
||||
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onSubmit={(model, reset, invalidate) => invalidate({ foo: 'bar' })}>
|
||||
|
|
@ -44,21 +45,21 @@ describe('Validation', function () {
|
|||
const inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
|
||||
form.submit();
|
||||
expect(inputComponent.isValid()).toBe(false);
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
|
||||
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
|
||||
immediate(() => {
|
||||
expect(inputComponent.getValue()).toBe('bar');
|
||||
expect(inputComponent.isValid()).toBe(false);
|
||||
done();
|
||||
test.equal(inputComponent.getValue(), 'bar');
|
||||
test.equal(inputComponent.isValid(), false);
|
||||
test.done();
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should trigger an onValid handler, if passed, when form is valid', function () {
|
||||
'should trigger an onValid handler, if passed, when form is valid': function (test) {
|
||||
|
||||
const onValid = jasmine.createSpy('valid');
|
||||
const onInvalid = jasmine.createSpy('invalid');
|
||||
const onValid = sinon.spy();
|
||||
const onInvalid = sinon.spy();
|
||||
|
||||
TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onValid={onValid} onInvalid={onInvalid}>
|
||||
|
|
@ -66,15 +67,16 @@ describe('Validation', function () {
|
|||
</Formsy.Form>
|
||||
);
|
||||
|
||||
expect(onValid).toHaveBeenCalled();
|
||||
expect(onInvalid).not.toHaveBeenCalled();
|
||||
test.equal(onValid.called, true);
|
||||
test.equal(onInvalid.called, false);
|
||||
test.done();
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should trigger an onInvalid handler, if passed, when form is invalid', function () {
|
||||
'should trigger an onInvalid handler, if passed, when form is invalid': function (test) {
|
||||
|
||||
const onValid = jasmine.createSpy('valid');
|
||||
const onInvalid = jasmine.createSpy('invalid');
|
||||
const onValid = sinon.spy();
|
||||
const onInvalid = sinon.spy();
|
||||
|
||||
TestUtils.renderIntoDocument(
|
||||
<Formsy.Form onValid={onValid} onInvalid={onInvalid}>
|
||||
|
|
@ -82,40 +84,33 @@ describe('Validation', function () {
|
|||
</Formsy.Form>
|
||||
);
|
||||
|
||||
expect(onValid).not.toHaveBeenCalled();
|
||||
expect(onInvalid).toHaveBeenCalled();
|
||||
test.equal(onValid.called, false);
|
||||
test.equal(onInvalid.called, true);
|
||||
test.done();
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should use provided validate function', function () {
|
||||
'should be able to use provided validate function': function (test) {
|
||||
|
||||
const isValid = jasmine.createSpy('valid');
|
||||
|
||||
const Input = customizeInput({
|
||||
render() {
|
||||
if (this.isValid()) {
|
||||
isValid();
|
||||
}
|
||||
return <input value={this.getValue()} onChange={this.updateValue}/>;
|
||||
},
|
||||
validate() {
|
||||
return this.getValue() === 'checkValidity';
|
||||
let isValid = false;
|
||||
const CustomInput = InputFactory({
|
||||
componentDidMount() {
|
||||
isValid = this.isValid();
|
||||
}
|
||||
});
|
||||
|
||||
const form = TestUtils.renderIntoDocument(
|
||||
<Formsy.Form>
|
||||
<Input name="foo" value="checkInvalidity"/>
|
||||
<CustomInput name="foo" value="foo" required/>
|
||||
</Formsy.Form>
|
||||
);
|
||||
|
||||
const input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
|
||||
TestUtils.Simulate.change(input, {target: {value: 'checkValidity'}});
|
||||
expect(isValid).toHaveBeenCalled();
|
||||
test.equal(isValid, true);
|
||||
test.done();
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should provide invalidate callback on onValiSubmit', function () {
|
||||
'should provide invalidate callback on onValiSubmit': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -132,11 +127,12 @@ describe('Validation', function () {
|
|||
const formEl = TestUtils.findRenderedDOMComponentWithTag(form, 'form');
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
TestUtils.Simulate.submit(formEl);
|
||||
expect(input.isValid()).toBe(false);
|
||||
test.equal(input.isValid(), false);
|
||||
test.done();
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should provide invalidate callback on onInvalidSubmit', function () {
|
||||
'should provide invalidate callback on onInvalidSubmit': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -152,12 +148,13 @@ describe('Validation', function () {
|
|||
const formEl = TestUtils.findRenderedDOMComponentWithTag(form, 'form');
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
TestUtils.Simulate.submit(formEl);
|
||||
expect(input.getErrorMessage()).toBe('bar');
|
||||
test.equal(input.getErrorMessage(), 'bar');
|
||||
|
||||
});
|
||||
test.done();
|
||||
|
||||
},
|
||||
|
||||
it('should not invalidate inputs on external errors with preventExternalInvalidation prop', function () {
|
||||
'should not invalidate inputs on external errors with preventExternalInvalidation prop': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -175,11 +172,12 @@ describe('Validation', function () {
|
|||
const formEl = TestUtils.findRenderedDOMComponentWithTag(form, 'form');
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
TestUtils.Simulate.submit(formEl);
|
||||
expect(input.isValid()).toBe(true);
|
||||
test.equal(input.isValid(), true);
|
||||
test.done();
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
it('should invalidate inputs on external errors without preventExternalInvalidation prop', function () {
|
||||
'should invalidate inputs on external errors without preventExternalInvalidation prop': function (test) {
|
||||
|
||||
const TestForm = React.createClass({
|
||||
render() {
|
||||
|
|
@ -195,8 +193,9 @@ describe('Validation', function () {
|
|||
const formEl = TestUtils.findRenderedDOMComponentWithTag(form, 'form');
|
||||
const input = TestUtils.findRenderedComponentWithType(form, TestInput);
|
||||
TestUtils.Simulate.submit(formEl);
|
||||
expect(input.isValid()).toBe(false);
|
||||
test.equal(input.isValid(), false);
|
||||
test.done();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
import Formsy from './../..';
|
||||
import assign from 'react/lib/Object.assign';
|
||||
|
||||
const defaultProps = {
|
||||
mixins: [Formsy.Mixin],
|
||||
|
|
@ -15,8 +14,8 @@ const defaultProps = {
|
|||
}
|
||||
};
|
||||
|
||||
export function customizeInput(props) {
|
||||
return React.createClass(assign(defaultProps, props));
|
||||
export function InputFactory(props) {
|
||||
return React.createClass(Object.assign(defaultProps, props));
|
||||
}
|
||||
|
||||
export default React.createClass(defaultProps);
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import { HOC as formsyHoc } from './../..';
|
||||
|
||||
const defaultProps = {
|
||||
methodOnWrappedInstance(param) {
|
||||
return param;
|
||||
},
|
||||
render() {
|
||||
return (<input />);
|
||||
},
|
||||
};
|
||||
|
||||
export default formsyHoc(React.createClass(defaultProps));
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
|
||||
devtool: 'inline-source-map',
|
||||
|
||||
entry: path.resolve(__dirname, 'build', 'test.js'),
|
||||
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'build'),
|
||||
filename: 'build.js'
|
||||
},
|
||||
|
||||
module: {
|
||||
loaders: [
|
||||
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel' },
|
||||
{ test: /\.json$/, loader: 'json' }
|
||||
]
|
||||
}
|
||||
|
||||
};
|
||||
Loading…
Reference in New Issue