UNPKG

redux-form

Version:

A higher order component decorator for forms using Redux and React

1,655 lines (1,480 loc) 77.6 kB
'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _expect = require('expect'); var _expect2 = _interopRequireDefault(_expect); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactRedux = require('react-redux'); var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _reactAddonsTestUtils = require('react-addons-test-utils'); var _reactAddonsTestUtils2 = _interopRequireDefault(_reactAddonsTestUtils); var _redux = require('redux'); var _reducer = require('../reducer'); var _reducer2 = _interopRequireDefault(_reducer); var _createReduxForm = require('../createReduxForm'); var _createReduxForm2 = _interopRequireDefault(_createReduxForm); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /* eslint react/no-multi-comp:0 */ var createRestorableSpy = function createRestorableSpy(fn) { return (0, _expect.createSpy)(fn, function restore() { this.calls = []; }); }; describe('createReduxForm', function () { var reduxForm = (0, _createReduxForm2.default)(false, _react2.default, _reactRedux.connect); var makeStore = function makeStore() { return (0, _redux.createStore)((0, _redux.combineReducers)({ form: _reducer2.default })); }; it('should return a decorator function', function () { (0, _expect2.default)(reduxForm).toBeA('function'); }); var Form = function (_Component) { _inherits(Form, _Component); function Form() { _classCallCheck(this, Form); return _possibleConstructorReturn(this, _Component.apply(this, arguments)); } Form.prototype.render = function render() { return _react2.default.createElement('div', null); }; return Form; }(_react.Component); var expectField = function expectField(_ref) { var field = _ref.field; var name = _ref.name; var value = _ref.value; var initial = _ref.initial; var valid = _ref.valid; var dirty = _ref.dirty; var error = _ref.error; var touched = _ref.touched; var visited = _ref.visited; var readonly = _ref.readonly; (0, _expect2.default)(field).toBeA('object'); (0, _expect2.default)(field.name).toBe(name); (0, _expect2.default)(field.value).toEqual(value); if (readonly) { (0, _expect2.default)(field.onBlur).toNotExist(); (0, _expect2.default)(field.onChange).toNotExist(); (0, _expect2.default)(field.onDragStart).toNotExist(); (0, _expect2.default)(field.onDrop).toNotExist(); (0, _expect2.default)(field.onFocus).toNotExist(); (0, _expect2.default)(field.onUpdate).toNotExist(); } else { (0, _expect2.default)(field.onBlur).toBeA('function'); (0, _expect2.default)(field.onChange).toBeA('function'); (0, _expect2.default)(field.onDragStart).toBeA('function'); (0, _expect2.default)(field.onDrop).toBeA('function'); (0, _expect2.default)(field.onFocus).toBeA('function'); (0, _expect2.default)(field.onUpdate).toBeA('function'); } (0, _expect2.default)(field.initialValue).toEqual(initial); (0, _expect2.default)(field.defaultValue).toEqual(initial); (0, _expect2.default)(field.defaultChecked).toBe(initial === true); (0, _expect2.default)(field.valid).toBe(valid); (0, _expect2.default)(field.invalid).toBe(!valid); (0, _expect2.default)(field.dirty).toBe(dirty); (0, _expect2.default)(field.pristine).toBe(!dirty); (0, _expect2.default)(field.error).toEqual(error); (0, _expect2.default)(field.touched).toBe(touched); (0, _expect2.default)(field.visited).toBe(visited); }; it('should render without error', function () { var store = makeStore(); (0, _expect2.default)(function () { var Decorated = reduxForm({ form: 'testForm', fields: ['foo', 'bar'] })(Form); _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); }).toNotThrow(); }); it('should pass fields as props', function () { var store = makeStore(); var Decorated = reduxForm({ form: 'testForm', fields: ['foo', 'bar'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.fields).toBeA('object'); expectField({ field: stub.props.fields.foo, name: 'foo', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); expectField({ field: stub.props.fields.bar, name: 'bar', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); }); it('should initialize field values', function () { var store = makeStore(); var Decorated = reduxForm({ form: 'testForm', fields: ['foo', 'bar'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { initialValues: { foo: 'fooValue', bar: 'barValue' } }) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.fields).toBeA('object'); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue', initial: 'fooValue', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); expectField({ field: stub.props.fields.bar, name: 'bar', value: 'barValue', initial: 'barValue', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); }); it('should set value and touch field on blur', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); stub.props.fields.foo.onBlur('fooValue'); (0, _expect2.default)(stub.props.fields).toBeA('object'); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue', initial: undefined, valid: true, dirty: true, error: undefined, touched: true, visited: false, readonly: false }); expectField({ field: stub.props.fields.bar, name: 'bar', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); }); it('should set value and NOT touch field on blur if touchOnBlur is disabled', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], touchOnBlur: false })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); stub.props.fields.foo.onBlur('fooValue'); (0, _expect2.default)(stub.props.fields).toBeA('object'); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue', initial: undefined, valid: true, dirty: true, error: undefined, touched: false, visited: false, readonly: false }); expectField({ field: stub.props.fields.bar, name: 'bar', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); }); it('should set value and NOT touch field on change', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); stub.props.fields.foo.onChange('fooValue'); (0, _expect2.default)(stub.props.fields).toBeA('object'); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue', initial: undefined, valid: true, dirty: true, error: undefined, touched: false, visited: false, readonly: false }); expectField({ field: stub.props.fields.bar, name: 'bar', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); }); it('should set value and touch field on change if touchOnChange is enabled', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], touchOnChange: true })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); stub.props.fields.foo.onChange('fooValue'); (0, _expect2.default)(stub.props.fields).toBeA('object'); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue', initial: undefined, valid: true, dirty: true, error: undefined, touched: true, visited: false, readonly: false }); expectField({ field: stub.props.fields.bar, name: 'bar', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); }); it('should set visited field on focus', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.active).toBe(undefined); stub.props.fields.foo.onFocus(); (0, _expect2.default)(stub.props.active).toBe('foo'); (0, _expect2.default)(stub.props.fields).toBeA('object'); expectField({ field: stub.props.fields.foo, name: 'foo', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: true, readonly: false }); expectField({ field: stub.props.fields.bar, name: 'bar', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); }); it('should set dirty when field changes', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { initialValues: { foo: 'fooValue', bar: 'barValue' } }) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue', initial: 'fooValue', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); stub.props.fields.foo.onChange('fooValue!'); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue!', initial: 'fooValue', valid: true, dirty: true, error: undefined, touched: false, visited: false, readonly: false }); }); it('should set dirty when and array field changes', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['children[].name'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { initialValues: { children: [{ name: 'Tom' }, { name: 'Jerry' }] } }) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.fields.children).toBeA('array'); (0, _expect2.default)(stub.props.fields.children.length).toBe(2); expectField({ field: stub.props.fields.children[0].name, name: 'children[0].name', value: 'Tom', initial: 'Tom', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); expectField({ field: stub.props.fields.children[1].name, name: 'children[1].name', value: 'Jerry', initial: 'Jerry', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); stub.props.fields.children[0].name.onChange('Tim'); expectField({ field: stub.props.fields.children[0].name, name: 'children[0].name', value: 'Tim', initial: 'Tom', valid: true, dirty: true, error: undefined, touched: false, visited: false, readonly: false }); expectField({ field: stub.props.fields.children[1].name, name: 'children[1].name', value: 'Jerry', initial: 'Jerry', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); }); it('should trigger sync error on change that invalidates value', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], validate: function validate(values) { var errors = {}; if (values.foo && values.foo.length > 8) { errors.foo = 'Too long'; } if (!values.bar) { errors.bar = 'Required'; } return errors; } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { initialValues: { foo: 'fooValue', bar: 'barValue' } }) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue', initial: 'fooValue', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); expectField({ field: stub.props.fields.bar, name: 'bar', value: 'barValue', initial: 'barValue', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); (0, _expect2.default)(stub.props.valid).toBe(true); (0, _expect2.default)(stub.props.invalid).toBe(false); (0, _expect2.default)(stub.props.errors).toEqual({}); stub.props.fields.foo.onChange('fooValue!'); expectField({ field: stub.props.fields.foo, name: 'foo', value: 'fooValue!', initial: 'fooValue', valid: false, dirty: true, error: 'Too long', touched: false, visited: false, readonly: false }); stub.props.fields.bar.onChange(''); expectField({ field: stub.props.fields.bar, name: 'bar', value: '', initial: 'barValue', valid: false, dirty: true, error: 'Required', touched: false, visited: false, readonly: false }); (0, _expect2.default)(stub.props.valid).toBe(false); (0, _expect2.default)(stub.props.invalid).toBe(true); (0, _expect2.default)(stub.props.errors).toEqual({ foo: 'Too long', bar: 'Required' }); }); it('should trigger sync error on change that invalidates nested value', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo.bar'], validate: function validate(values) { var errors = {}; if (values.foo.bar && values.foo.bar.length > 8) { errors.foo = { bar: 'Too long' }; } return errors; } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { initialValues: { foo: { bar: 'fooBar' } } }) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); expectField({ field: stub.props.fields.foo.bar, name: 'foo.bar', value: 'fooBar', initial: 'fooBar', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); (0, _expect2.default)(stub.props.valid).toBe(true); (0, _expect2.default)(stub.props.invalid).toBe(false); (0, _expect2.default)(stub.props.errors).toEqual({}); stub.props.fields.foo.bar.onChange('fooBarBaz'); expectField({ field: stub.props.fields.foo.bar, name: 'foo.bar', value: 'fooBarBaz', initial: 'fooBar', valid: false, dirty: true, error: 'Too long', touched: false, visited: false, readonly: false }); (0, _expect2.default)(stub.props.valid).toBe(false); (0, _expect2.default)(stub.props.invalid).toBe(true); (0, _expect2.default)(stub.props.errors).toEqual({ foo: { bar: 'Too long' } }); }); it('should trigger sync error on change that invalidates array value', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo[]', 'bar[].name'], validate: function validate(values) { var errors = {}; if (values.foo && values.foo.length && values.foo[0] && values.foo[0].length > 8) { errors.foo = ['Too long']; } if (values.bar && values.bar.length && values.bar[0] && values.bar[0].name === 'Ralphie') { errors.bar = [{ name: 'You\'ll shoot your eye out, kid!' }]; } return errors; } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { initialValues: { foo: ['fooBar'], bar: [{ name: '' }] } }) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); expectField({ field: stub.props.fields.foo[0], name: 'foo[0]', value: 'fooBar', initial: 'fooBar', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); expectField({ field: stub.props.fields.bar[0].name, name: 'bar[0].name', value: '', initial: '', valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: false }); (0, _expect2.default)(stub.props.valid).toBe(true); (0, _expect2.default)(stub.props.invalid).toBe(false); (0, _expect2.default)(stub.props.errors).toEqual({}); stub.props.fields.foo[0].onChange('fooBarBaz'); expectField({ field: stub.props.fields.foo[0], name: 'foo[0]', value: 'fooBarBaz', initial: 'fooBar', valid: false, dirty: true, error: 'Too long', touched: false, visited: false, readonly: false }); stub.props.fields.bar[0].name.onChange('Ralphie'); expectField({ field: stub.props.fields.bar[0].name, name: 'bar[0].name', value: 'Ralphie', initial: '', valid: false, dirty: true, error: 'You\'ll shoot your eye out, kid!', touched: false, visited: false, readonly: false }); (0, _expect2.default)(stub.props.valid).toBe(false); (0, _expect2.default)(stub.props.invalid).toBe(true); (0, _expect2.default)(stub.props.errors).toEqual({ foo: ['Too long'], bar: [{ name: 'You\'ll shoot your eye out, kid!' }] }); }); it('should call destroy on unmount', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'] })(Form); var div = document.createElement('div'); _reactDom2.default.render(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { initialValues: { foo: 'fooValue', bar: 'barValue' } }) ), div); var before = store.getState(); (0, _expect2.default)(before.form).toBeA('object'); (0, _expect2.default)(before.form[form]).toBeA('object'); (0, _expect2.default)(before.form[form].foo).toBeA('object'); (0, _expect2.default)(before.form[form].bar).toBeA('object'); _reactDom2.default.unmountComponentAtNode(div); var after = store.getState(); (0, _expect2.default)(after.form).toBeA('object'); (0, _expect2.default)(after.form[form]).toNotExist(); }); it('should NOT call destroy on unmount if destroyOnUnmount is disabled', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], destroyOnUnmount: false })(Form); var div = document.createElement('div'); _reactDom2.default.render(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { initialValues: { foo: 'fooValue', bar: 'barValue' } }) ), div); var before = store.getState(); (0, _expect2.default)(before.form).toBeA('object'); (0, _expect2.default)(before.form[form]).toBeA('object'); (0, _expect2.default)(before.form[form].foo).toBeA('object'); (0, _expect2.default)(before.form[form].bar).toBeA('object'); _reactDom2.default.unmountComponentAtNode(div); var after = store.getState(); (0, _expect2.default)(after.form).toBeA('object'); (0, _expect2.default)(after.form[form]).toBeA('object'); (0, _expect2.default)(after.form[form].foo).toBeA('object'); (0, _expect2.default)(after.form[form].bar).toBeA('object'); }); it('should hoist statics', function () { var FormWithStatics = function (_Component2) { _inherits(FormWithStatics, _Component2); function FormWithStatics() { _classCallCheck(this, FormWithStatics); return _possibleConstructorReturn(this, _Component2.apply(this, arguments)); } FormWithStatics.prototype.render = function render() { return _react2.default.createElement('div', null); }; return FormWithStatics; }(_react.Component); FormWithStatics.someStatic1 = 'cat'; FormWithStatics.someStatic2 = 42; var Decorated = reduxForm({ form: 'testForm', fields: ['foo', 'bar'] })(FormWithStatics); (0, _expect2.default)(Decorated.someStatic1).toBe('cat'); (0, _expect2.default)(Decorated.someStatic2).toBe(42); }); it('should not provide mutators when readonly', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], readonly: true })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); expectField({ field: stub.props.fields.foo, name: 'foo', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: true }); expectField({ field: stub.props.fields.bar, name: 'bar', value: undefined, initial: undefined, valid: true, dirty: false, error: undefined, touched: false, visited: false, readonly: true }); }); it('should initialize an array field', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['children[].name'], initialValues: { children: [{ name: 'Tom' }, { name: 'Jerry' }] } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); expectField({ field: stub.props.fields.children[0].name, name: 'children[0].name', value: 'Tom', initial: 'Tom', valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.children[1].name, name: 'children[1].name', value: 'Jerry', initial: 'Jerry', valid: true, dirty: false, error: undefined, touched: false, visited: false }); }); it('should call onSubmit prop', function (done) { var submit = function submit(values) { (0, _expect2.default)(values).toEqual({ foo: undefined, bar: undefined }); done(); }; var FormComponent = function (_Component3) { _inherits(FormComponent, _Component3); function FormComponent() { _classCallCheck(this, FormComponent); return _possibleConstructorReturn(this, _Component3.apply(this, arguments)); } FormComponent.prototype.render = function render() { return _react2.default.createElement('form', { onSubmit: this.props.handleSubmit }); }; return FormComponent; }(_react.Component); FormComponent.propTypes = { handleSubmit: _react.PropTypes.func.isRequired }; var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], readonly: true })(FormComponent); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { onSubmit: submit }) )); var formElement = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'form'); _reactAddonsTestUtils2.default.Simulate.submit(formElement); }); it('should call async onSubmit prop', function (done) { var submit = function submit(values) { (0, _expect2.default)(values).toEqual({ foo: undefined, bar: undefined }); return new Promise(function (resolve) { setTimeout(function () { resolve(); }, 100); }).then(done); }; var FormComponent = function (_Component4) { _inherits(FormComponent, _Component4); function FormComponent() { _classCallCheck(this, FormComponent); return _possibleConstructorReturn(this, _Component4.apply(this, arguments)); } FormComponent.prototype.render = function render() { return _react2.default.createElement('form', { onSubmit: this.props.handleSubmit }); }; return FormComponent; }(_react.Component); FormComponent.propTypes = { handleSubmit: _react.PropTypes.func.isRequired }; var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], readonly: true })(FormComponent); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, { onSubmit: submit }) )); var formElement = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'form'); _reactAddonsTestUtils2.default.Simulate.submit(formElement); }); it('should NOT call async validation if form is pristine and initialized', function () { var store = makeStore(); var form = 'testForm'; var errorValue = { foo: 'no bears allowed' }; var asyncValidate = (0, _expect.createSpy)().andReturn(Promise.reject(errorValue)); var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], asyncValidate: asyncValidate, asyncBlurFields: ['foo'], initialValues: { foo: 'dog', bar: 'cat' } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); stub.props.fields.foo.onBlur('dog'); (0, _expect2.default)(asyncValidate).toNotHaveBeenCalled(); }); it('should call async validation if form is dirty and initialized', function () { var store = makeStore(); var form = 'testForm'; var errorValue = { foo: 'no bears allowed' }; var asyncValidate = (0, _expect.createSpy)().andReturn(Promise.reject(errorValue)); var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], asyncValidate: asyncValidate, asyncBlurFields: ['foo'], initialValues: { foo: 'dog', bar: 'cat' } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); stub.props.fields.foo.onBlur('bear'); (0, _expect2.default)(asyncValidate).toHaveBeenCalled(); }); it('should call async validation if form is pristine and NOT initialized', function () { var store = makeStore(); var form = 'testForm'; var errorValue = { foo: 'no bears allowed' }; var asyncValidate = (0, _expect.createSpy)().andReturn(Promise.reject(errorValue)); var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], asyncValidate: asyncValidate, asyncBlurFields: ['foo'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); stub.props.fields.foo.onBlur(); (0, _expect2.default)(asyncValidate).toHaveBeenCalled(); }); it('should call async validation on submit even if pristine and initialized', function () { var submit = (0, _expect.createSpy)(); var FormComponent = function (_Component5) { _inherits(FormComponent, _Component5); function FormComponent() { _classCallCheck(this, FormComponent); return _possibleConstructorReturn(this, _Component5.apply(this, arguments)); } FormComponent.prototype.render = function render() { return _react2.default.createElement('form', { onSubmit: this.props.handleSubmit(submit) }); }; return FormComponent; }(_react.Component); FormComponent.propTypes = { handleSubmit: _react.PropTypes.func.isRequired }; var store = makeStore(); var form = 'testForm'; var errorValue = { foo: 'no dogs allowed' }; var asyncValidate = (0, _expect.createSpy)().andReturn(Promise.reject(errorValue)); var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], asyncValidate: asyncValidate, asyncBlurFields: ['foo'], initialValues: { foo: 'dog', bar: 'cat' } })(FormComponent); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var formElement = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'form'); _reactAddonsTestUtils2.default.Simulate.submit(formElement); (0, _expect2.default)(asyncValidate).toHaveBeenCalled(); (0, _expect2.default)(submit).toNotHaveBeenCalled(); }); it('should call submit function passed to handleSubmit', function (done) { var submit = function submit(values) { (0, _expect2.default)(values).toEqual({ foo: undefined, bar: undefined }); done(); }; var FormComponent = function (_Component6) { _inherits(FormComponent, _Component6); function FormComponent() { _classCallCheck(this, FormComponent); return _possibleConstructorReturn(this, _Component6.apply(this, arguments)); } FormComponent.prototype.render = function render() { return _react2.default.createElement('form', { onSubmit: this.props.handleSubmit(submit) }); }; return FormComponent; }(_react.Component); FormComponent.propTypes = { handleSubmit: _react.PropTypes.func.isRequired }; var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], readonly: true })(FormComponent); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var formElement = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'form'); _reactAddonsTestUtils2.default.Simulate.submit(formElement); }); it('should call submit function passed to async handleSubmit', function (done) { var submit = function submit(values) { (0, _expect2.default)(values).toEqual({ foo: undefined, bar: undefined }); return new Promise(function (resolve) { setTimeout(function () { resolve(); }, 100); }).then(done); }; var FormComponent = function (_Component7) { _inherits(FormComponent, _Component7); function FormComponent() { _classCallCheck(this, FormComponent); return _possibleConstructorReturn(this, _Component7.apply(this, arguments)); } FormComponent.prototype.render = function render() { return _react2.default.createElement('form', { onSubmit: this.props.handleSubmit(submit) }); }; return FormComponent; }(_react.Component); FormComponent.propTypes = { handleSubmit: _react.PropTypes.func.isRequired }; var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['foo', 'bar'], readonly: true })(FormComponent); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var formElement = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'form'); _reactAddonsTestUtils2.default.Simulate.submit(formElement); }); it('should initialize a non-array field with an array value and let it read it back', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['children'], initialValues: { children: [1, 2] } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); expectField({ field: stub.props.fields.children, name: 'children', value: [1, 2], initial: [1, 2], valid: true, dirty: false, error: undefined, touched: false, visited: false }); }); it('should initialize an array field with an array value', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['colors[]'], initialValues: { colors: ['red', 'blue'] } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.fields.colors).toBeA('array'); (0, _expect2.default)(stub.props.fields.colors.length).toBe(2); expectField({ field: stub.props.fields.colors[0], name: 'colors[0]', value: 'red', initial: 'red', valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.colors[1], name: 'colors[1]', value: 'blue', initial: 'blue', valid: true, dirty: false, error: undefined, touched: false, visited: false }); }); it('should initialize a deep array field with values', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['users[].name', 'users[].age'], initialValues: { users: [{ name: 'Bob', age: 27 }] } })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.fields.users).toBeA('array'); (0, _expect2.default)(stub.props.fields.users.length).toBe(1); (0, _expect2.default)(stub.props.fields.users[0]).toBeA('object'); expectField({ field: stub.props.fields.users[0].name, name: 'users[0].name', value: 'Bob', initial: 'Bob', valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.users[0].age, name: 'users[0].age', value: 27, initial: 27, valid: true, dirty: false, error: undefined, touched: false, visited: false }); }); it('should add array values with defaults', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['users[].name', 'users[].age'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.fields.users).toBeA('array'); (0, _expect2.default)(stub.props.fields.users.length).toBe(0); (0, _expect2.default)(stub.props.fields.users.addField).toBeA('function'); var before = stub.props.fields.users; // add field stub.props.fields.users.addField({ name: 'Bob', age: 27 }); // check field (0, _expect2.default)(stub.props.fields.users.length).toBe(1); (0, _expect2.default)(stub.props.fields.users[0]).toBeA('object'); expectField({ field: stub.props.fields.users[0].name, name: 'users[0].name', value: 'Bob', initial: 'Bob', valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.users[0].age, name: 'users[0].age', value: 27, initial: 27, valid: true, dirty: false, error: undefined, touched: false, visited: false }); var after = stub.props.fields.users; (0, _expect2.default)(after).toNotBe(before); // should be a new instance // check state (0, _expect2.default)(store.getState().form.testForm.users).toBeA('array'); (0, _expect2.default)(store.getState().form.testForm.users.length).toBe(1); (0, _expect2.default)(store.getState().form.testForm.users[0].name).toEqual({ initial: 'Bob', value: 'Bob' }); (0, _expect2.default)(store.getState().form.testForm.users[0].age).toEqual({ initial: 27, value: 27 }); }); // Test to demonstrate bug: https://github.com/erikras/redux-form/issues/630 it('should add array values when root is not an array', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['acknowledgements.items[].number', 'acknowledgements.items[].name', 'acknowledgements.show'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.fields.acknowledgements).toBeA('object'); (0, _expect2.default)(stub.props.fields.acknowledgements.items).toBeA('array'); (0, _expect2.default)(stub.props.fields.acknowledgements.items.length).toBe(0); (0, _expect2.default)(stub.props.fields.acknowledgements.items.addField).toBeA('function'); // add field stub.props.fields.acknowledgements.items.addField({ number: 1, name: 'foo' }); // check field (0, _expect2.default)(stub.props.fields.acknowledgements.items.length).toBe(1); (0, _expect2.default)(stub.props.fields.acknowledgements.items[0]).toBeA('object'); expectField({ field: stub.props.fields.acknowledgements.items[0].number, name: 'acknowledgements.items[0].number', value: 1, initial: 1, valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.acknowledgements.items[0].name, name: 'acknowledgements.items[0].name', value: 'foo', initial: 'foo', valid: true, dirty: false, error: undefined, touched: false, visited: false }); }); // Test to demonstrate bug: https://github.com/erikras/redux-form/issues/468 it('should add array values with DEEP defaults', function () { var store = makeStore(); var form = 'testForm'; var Decorated = reduxForm({ form: form, fields: ['proposals[].arrival', 'proposals[].departure', 'proposals[].note', 'proposals[].rooms[].name', 'proposals[].rooms[].adults', 'proposals[].rooms[].children'] })(Form); var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( _reactRedux.Provider, { store: store }, _react2.default.createElement(Decorated, null) )); var stub = _reactAddonsTestUtils2.default.findRenderedComponentWithType(dom, Form); (0, _expect2.default)(stub.props.fields.proposals).toBeA('array'); (0, _expect2.default)(stub.props.fields.proposals.length).toBe(0); (0, _expect2.default)(stub.props.fields.proposals.addField).toBeA('function'); // add field var today = new Date(); stub.props.fields.proposals.addField({ arrival: today, departure: today, note: '', rooms: [{ name: 'Room 1', adults: 2, children: 0 }] }); stub.props.fields.proposals[0].rooms.addField({ name: 'Room 2', adults: 0, children: 2 }); // check field (0, _expect2.default)(stub.props.fields.proposals.length).toBe(1); (0, _expect2.default)(stub.props.fields.proposals[0]).toBeA('object'); expectField({ field: stub.props.fields.proposals[0].arrival, name: 'proposals[0].arrival', value: today, initial: today, valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.proposals[0].departure, name: 'proposals[0].departure', value: today, initial: today, valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.proposals[0].note, name: 'proposals[0].note', value: '', initial: '', valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.proposals[0].rooms[0].name, name: 'proposals[0].rooms[0].name', value: 'Room 1', initial: 'Room 1', valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.proposals[0].rooms[0].adults, name: 'proposals[0].rooms[0].adults', value: 2, initial: 2, valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.proposals[0].rooms[0].children, name: 'proposals[0].rooms[0].children', value: 0, initial: 0, valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.proposals[0].rooms[1].name, name: 'proposals[0].rooms[1].name', value: 'Room 2', initial: 'Room 2', valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.proposals[0].rooms[1].adults, name: 'proposals[0].rooms[1].adults', value: 0, initial: 0, valid: true, dirty: false, error: undefined, touched: false, visited: false }); expectField({ field: stub.props.fields.proposals[0].rooms[1].children, name: 'proposals[0].rooms[1].children', value: 2, initial: 2, valid: true, dirty: false, error: undefined, touched: false, visited: false }); }); // Test to demonstrate https://github.com/erikras/redux-form/issues/612 //it('should work with a root-level array field', () => { // const store = makeStore(); // const form = 'test