redux-form
Version:
A higher order component decorator for forms using Redux and React
1,541 lines (1,315 loc) • 113 kB
JavaScript
import _noop from 'lodash-es/noop';
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 _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
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 */
import React, { Component } from 'react';
import TestUtils from 'react-addons-test-utils';
import { createSpy } from 'expect';
import { combineReducers as plainCombineReducers, createStore } from 'redux';
import { combineReducers as immutableCombineReducers } from 'redux-immutablejs';
import { Provider } from 'react-redux';
import createReducer from '../reducer';
import createReduxForm from '../reduxForm';
import createField from '../Field';
import createFieldArray from '../FieldArray';
import { startSubmit } from '../actions';
import plain from '../structure/plain';
import plainExpectations from '../structure/plain/expectations';
import immutable from '../structure/immutable';
import immutableExpectations from '../structure/immutable/expectations';
import addExpectations from './addExpectations';
import SubmissionError from '../SubmissionError';
import { change } from '../actions';
var describeReduxForm = function describeReduxForm(name, structure, combineReducers, expect) {
var fromJS = structure.fromJS;
var getIn = structure.getIn;
var reduxForm = createReduxForm(structure);
var Field = createField(structure);
var FieldArray = createFieldArray(structure);
var reducer = createReducer(structure);
describe(name, function () {
var makeStore = function makeStore() {
var initial = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
return createStore(combineReducers({ form: reducer }), fromJS({ form: initial }));
};
var propChecker = function propChecker(formState) {
var renderSpy = arguments.length <= 1 || arguments[1] === undefined ? _noop : arguments[1];
var config = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
var store = makeStore({ testForm: formState });
var Form = function (_Component) {
_inherits(Form, _Component);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
renderSpy(this.props);
return React.createElement(
'div',
null,
React.createElement(Field, { name: 'foo', component: 'input' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm(_extends({ form: 'testForm' }, config))(Form);
var dom = TestUtils.renderIntoDocument(React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, null)
));
return TestUtils.findRenderedComponentWithType(dom, Form).props;
};
it('should return a decorator function', function () {
expect(reduxForm).toBeA('function');
});
it('should render without error', function () {
var store = makeStore();
var Form = function (_Component2) {
_inherits(Form, _Component2);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
return React.createElement('div', null);
}
}]);
return Form;
}(Component);
expect(function () {
var Decorated = reduxForm({ form: 'testForm' })(Form);
TestUtils.renderIntoDocument(React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, null)
));
}).toNotThrow();
});
it('should provide a the correct props', function () {
var props = propChecker({});
expect(Object.keys(props).sort()).toEqual(['anyTouched', 'array', 'asyncValidate', 'asyncValidating', 'autofill', 'blur', 'change', 'destroy', 'dirty', 'dispatch', 'error', 'form', 'handleSubmit', 'initialValues', 'initialize', 'initialized', 'invalid', 'pristine', 'pure', 'reset', 'submitFailed', 'submitSucceeded', 'submitting', 'touch', 'untouch', 'valid']);
expect(props.anyTouched).toBeA('boolean');
expect(props.array).toExist().toBeA('object');
expect(Object.keys(props.array).sort()).toEqual(['insert', 'move', 'pop', 'push', 'remove', 'removeAll', 'shift', 'splice', 'swap', 'unshift']);
expect(props.array.insert).toExist().toBeA('function');
expect(props.array.move).toExist().toBeA('function');
expect(props.array.pop).toExist().toBeA('function');
expect(props.array.push).toExist().toBeA('function');
expect(props.array.remove).toExist().toBeA('function');
expect(props.array.removeAll).toExist().toBeA('function');
expect(props.array.shift).toExist().toBeA('function');
expect(props.array.splice).toExist().toBeA('function');
expect(props.array.swap).toExist().toBeA('function');
expect(props.array.unshift).toExist().toBeA('function');
expect(props.asyncValidate).toExist().toBeA('function');
expect(props.asyncValidating).toBeA('boolean');
expect(props.autofill).toExist().toBeA('function');
expect(props.blur).toExist().toBeA('function');
expect(props.change).toExist().toBeA('function');
expect(props.destroy).toExist().toBeA('function');
expect(props.dirty).toBeA('boolean');
expect(props.form).toExist().toBeA('string');
expect(props.handleSubmit).toExist().toBeA('function');
expect(props.initialize).toExist().toBeA('function');
expect(props.initialized).toBeA('boolean');
expect(props.pristine).toBeA('boolean');
expect(props.reset).toExist().toBeA('function');
expect(props.submitFailed).toBeA('boolean');
expect(props.submitSucceeded).toBeA('boolean');
expect(props.touch).toExist().toBeA('function');
expect(props.untouch).toExist().toBeA('function');
expect(props.valid).toBeA('boolean');
});
it('should provide dirty prop', function () {
expect(propChecker({}).dirty).toBe(false);
expect(propChecker({
// no initial values
values: {
foo: 'bar'
}
}).dirty).toBe(true);
expect(propChecker({
initial: {
foo: 'bar'
},
values: {
foo: 'bar'
}
}).dirty).toBe(false);
expect(propChecker({
initial: {
foo: 'bar'
},
values: {
foo: 'baz'
}
}).dirty).toBe(true);
});
it('should provide pristine prop', function () {
expect(propChecker({}).pristine).toBe(true);
expect(propChecker({
// no initial values
values: {
foo: 'bar'
}
}).pristine).toBe(false);
expect(propChecker({
initial: {
foo: 'bar'
},
values: {
foo: 'bar'
}
}).pristine).toBe(true);
expect(propChecker({
initial: {
foo: 'bar'
},
values: {
foo: 'baz'
}
}).pristine).toBe(false);
});
it('should provide valid prop', function () {
expect(propChecker({}).valid).toBe(true);
expect(propChecker({}, undefined, {
validate: function validate() {
return { foo: 'sync error' };
}
}).valid).toBe(false);
expect(propChecker({
asyncErrors: {
foo: 'bar'
}
}).valid).toBe(false);
expect(propChecker({
asyncErrors: {
nested: {
myArrayField: [undefined, undefined]
}
}
}).valid).toBe(true);
});
it('should provide invalid prop', function () {
expect(propChecker({}).invalid).toBe(false);
expect(propChecker({}, undefined, {
validate: function validate() {
return { foo: 'sync error' };
}
}).invalid).toBe(true);
expect(propChecker({
asyncErrors: {
foo: 'bar'
}
}).invalid).toBe(true);
});
it('should provide submitting prop', function () {
expect(propChecker({}).submitting).toBe(false);
expect(propChecker({ submitting: true }).submitting).toBe(true);
expect(propChecker({ submitting: false }).submitting).toBe(false);
});
it('should put props under prop namespace if specified', function () {
var props = propChecker({}, _noop, {
propNamespace: 'fooProps',
someOtherProp: 'whatever'
});
expect(props.fooProps).toExist().toBeA('object');
expect(props.dispatch).toNotExist();
expect(props.dirty).toNotExist();
expect(props.pristine).toNotExist();
expect(props.submitting).toNotExist();
expect(props.someOtherProp).toExist();
expect(props.fooProps.dispatch).toBeA('function');
expect(props.fooProps.dirty).toBeA('boolean');
expect(props.fooProps.pristine).toBeA('boolean');
expect(props.fooProps.submitting).toBeA('boolean');
expect(props.fooProps.someOtherProp).toNotExist();
});
it('should provide bound array action creators', function () {
var arrayProp = propChecker({}).array;
expect(arrayProp).toExist();
expect(arrayProp.insert).toExist().toBeA('function');
expect(arrayProp.pop).toExist().toBeA('function');
expect(arrayProp.push).toExist().toBeA('function');
expect(arrayProp.remove).toExist().toBeA('function');
expect(arrayProp.shift).toExist().toBeA('function');
expect(arrayProp.splice).toExist().toBeA('function');
expect(arrayProp.swap).toExist().toBeA('function');
expect(arrayProp.unshift).toExist().toBeA('function');
});
it('should not rerender unless form-wide props (except value!) change', function () {
var spy = createSpy();
var _propChecker = propChecker({}, spy, {
validate: function validate(values) {
var foo = getIn(values, 'foo');
return foo && foo.length > 5 ? { foo: 'Too long' } : {};
}
});
var dispatch = _propChecker.dispatch; // render 0
expect(spy.calls.length).toBe(1);
// simulate typing the word "giraffe"
dispatch(change('testForm', 'foo', 'g')); // render 1 (now dirty)
expect(spy.calls.length).toBe(2);
dispatch(change('testForm', 'foo', 'gi')); // no render
dispatch(change('testForm', 'foo', 'gir')); // no render
dispatch(change('testForm', 'foo', 'gira')); // no render
dispatch(change('testForm', 'foo', 'giraf')); // no render
dispatch(change('testForm', 'foo', 'giraff')); // render 2 (invalid)
expect(spy.calls.length).toBe(3);
dispatch(change('testForm', 'foo', 'giraffe')); // no render
dispatch(change('testForm', 'foo', '')); // render 3 (clean/valid)
expect(spy.calls.length).toBe(5); // two renders, one to change value, and other to revalidate
expect(spy.calls[0].arguments[0].dirty).toBe(false);
expect(spy.calls[0].arguments[0].invalid).toBe(false);
expect(spy.calls[0].arguments[0].pristine).toBe(true);
expect(spy.calls[0].arguments[0].valid).toBe(true);
expect(spy.calls[1].arguments[0].dirty).toBe(true);
expect(spy.calls[1].arguments[0].invalid).toBe(false);
expect(spy.calls[1].arguments[0].pristine).toBe(false);
expect(spy.calls[1].arguments[0].valid).toBe(true);
expect(spy.calls[2].arguments[0].dirty).toBe(true);
expect(spy.calls[2].arguments[0].invalid).toBe(true);
expect(spy.calls[2].arguments[0].pristine).toBe(false);
expect(spy.calls[2].arguments[0].valid).toBe(false);
expect(spy.calls[4].arguments[0].dirty).toBe(false);
expect(spy.calls[4].arguments[0].invalid).toBe(false);
expect(spy.calls[4].arguments[0].pristine).toBe(true);
expect(spy.calls[4].arguments[0].valid).toBe(true);
});
it('should rerender on every change if pure is false', function () {
var spy = createSpy();
var _propChecker2 = propChecker({}, spy, {
pure: false
});
var dispatch = _propChecker2.dispatch;
expect(spy.calls.length).toBe(2); // twice, second one is for after field registration
// simulate typing the word "giraffe"
dispatch(change('testForm', 'foo', 'g'));
expect(spy.calls.length).toBe(3);
dispatch(change('testForm', 'foo', 'gi'));
expect(spy.calls.length).toBe(4);
dispatch(change('testForm', 'foo', 'gir'));
expect(spy.calls.length).toBe(5);
dispatch(change('testForm', 'foo', 'gira'));
expect(spy.calls.length).toBe(6);
dispatch(change('testForm', 'foo', 'giraf'));
expect(spy.calls.length).toBe(7);
dispatch(change('testForm', 'foo', 'giraff'));
expect(spy.calls.length).toBe(8);
dispatch(change('testForm', 'foo', 'giraffe'));
expect(spy.calls.length).toBe(9);
});
it('should initialize values with initialValues on first render', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var initialValues = {
deep: {
foo: 'bar'
}
};
var Form = function (_Component3) {
_inherits(Form, _Component3);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({ form: 'testForm' })(Form);
TestUtils.renderIntoDocument(React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, { initialValues: initialValues })
));
expect(store.getState()).toEqualMap({
form: {
testForm: {
initial: initialValues,
values: initialValues,
registeredFields: [{ name: 'deep.foo', type: 'Field' }]
}
}
});
expect(formRender).toHaveBeenCalled();
expect(formRender.calls.length).toBe(1);
var checkProps = function checkProps(props) {
expect(props.pristine).toBe(true);
expect(props.dirty).toBe(false);
expect(props.initialized).toBe(false); // will be true on second render
expect(props.initialValues).toEqualMap(initialValues);
};
checkProps(formRender.calls[0].arguments[0]);
expect(inputRender).toHaveBeenCalled();
expect(inputRender.calls.length).toBe(1);
expect(inputRender.calls[0].arguments[0].meta.pristine).toBe(true);
expect(inputRender.calls[0].arguments[0].meta.dirty).toBe(false);
expect(inputRender.calls[0].arguments[0].input.value).toBe('bar');
});
it('should initialize with initialValues on later render if not already initialized', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var initialValues = {
deep: {
foo: 'bar'
}
};
var Form = function (_Component4) {
_inherits(Form, _Component4);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({ form: 'testForm' })(Form);
var Container = function (_Component5) {
_inherits(Container, _Component5);
function Container(props) {
_classCallCheck(this, Container);
var _this5 = _possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this, props));
_this5.state = {};
return _this5;
}
_createClass(Container, [{
key: 'render',
value: function render() {
var _this6 = this;
return React.createElement(
'div',
null,
React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, this.state)
),
React.createElement(
'button',
{ onClick: function onClick() {
return _this6.setState({ initialValues: initialValues });
} },
'Init'
)
);
}
}]);
return Container;
}(Component);
var dom = TestUtils.renderIntoDocument(React.createElement(Container, null));
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{ name: 'deep.foo', type: 'Field' }]
}
}
});
expect(formRender).toHaveBeenCalled();
expect(formRender.calls.length).toBe(1);
expect(inputRender).toHaveBeenCalled();
expect(inputRender.calls.length).toBe(1);
var checkInputProps = function checkInputProps(props, value) {
expect(props.meta.pristine).toBe(true);
expect(props.meta.dirty).toBe(false);
expect(props.input.value).toBe(value);
};
checkInputProps(inputRender.calls[0].arguments[0], '');
// initialize
var initButton = TestUtils.findRenderedDOMComponentWithTag(dom, 'button');
TestUtils.Simulate.click(initButton);
// check initialized state
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{
name: 'deep.foo',
type: 'Field'
}],
initial: initialValues,
values: initialValues
}
}
});
// no need to rerender form on initialize
expect(formRender.calls.length).toBe(1);
// check rerendered input
expect(inputRender.calls.length).toBe(2);
checkInputProps(inputRender.calls[1].arguments[0], 'bar');
});
it('should NOT reinitialize with initialValues', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var initialValues1 = {
deep: {
foo: 'bar'
}
};
var initialValues2 = {
deep: {
foo: 'baz'
}
};
var Form = function (_Component6) {
_inherits(Form, _Component6);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({ form: 'testForm' })(Form);
var Container = function (_Component7) {
_inherits(Container, _Component7);
function Container(props) {
_classCallCheck(this, Container);
var _this8 = _possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this, props));
_this8.state = { initialValues: initialValues1 };
return _this8;
}
_createClass(Container, [{
key: 'render',
value: function render() {
var _this9 = this;
return React.createElement(
'div',
null,
React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, this.state)
),
React.createElement(
'button',
{ onClick: function onClick() {
return _this9.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(Component);
var dom = TestUtils.renderIntoDocument(React.createElement(Container, null));
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{ name: 'deep.foo', type: 'Field' }],
initial: initialValues1,
values: initialValues1
}
}
});
expect(formRender).toHaveBeenCalled();
expect(formRender.calls.length).toBe(1);
expect(inputRender).toHaveBeenCalled();
expect(inputRender.calls.length).toBe(1);
var checkInputProps = function checkInputProps(props, value) {
expect(props.meta.pristine).toBe(true);
expect(props.meta.dirty).toBe(false);
expect(props.input.value).toBe(value);
};
checkInputProps(inputRender.calls[0].arguments[0], 'bar');
// initialize
var initButton = TestUtils.findRenderedDOMComponentWithTag(dom, 'button');
TestUtils.Simulate.click(initButton);
// check initialized state
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{
name: 'deep.foo',
type: 'Field'
}],
initial: initialValues1,
values: initialValues1
}
}
});
// rerender just because prop changed
expect(formRender.calls.length).toBe(2);
// no need to rerender input since nothing changed
expect(inputRender.calls.length).toBe(1);
});
it('should reinitialize with initialValues if enableReinitialize', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var initialValues1 = {
deep: {
foo: 'bar'
}
};
var initialValues2 = {
deep: {
foo: 'baz'
}
};
var Form = function (_Component8) {
_inherits(Form, _Component8);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({
form: 'testForm',
enableReinitialize: true
})(Form);
var Container = function (_Component9) {
_inherits(Container, _Component9);
function Container(props) {
_classCallCheck(this, Container);
var _this11 = _possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this, props));
_this11.state = { initialValues: initialValues1 };
return _this11;
}
_createClass(Container, [{
key: 'render',
value: function render() {
var _this12 = this;
return React.createElement(
'div',
null,
React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, this.state)
),
React.createElement(
'button',
{ onClick: function onClick() {
return _this12.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(Component);
var dom = TestUtils.renderIntoDocument(React.createElement(Container, null));
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{ name: 'deep.foo', type: 'Field' }],
initial: initialValues1,
values: initialValues1
}
}
});
expect(formRender).toHaveBeenCalled();
expect(formRender.calls.length).toBe(1);
expect(inputRender).toHaveBeenCalled();
expect(inputRender.calls.length).toBe(1);
var checkInputProps = function checkInputProps(props, value) {
expect(props.meta.pristine).toBe(true);
expect(props.meta.dirty).toBe(false);
expect(props.input.value).toBe(value);
};
checkInputProps(inputRender.calls[0].arguments[0], 'bar');
// initialize
var initButton = TestUtils.findRenderedDOMComponentWithTag(dom, 'button');
TestUtils.Simulate.click(initButton);
// check initialized state
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{
name: 'deep.foo',
type: 'Field'
}],
initial: initialValues2,
values: initialValues2
}
}
});
// rerendered twice because prop changed and values initialized
expect(formRender.calls.length).toBe(3);
// should rerender input with new value
expect(inputRender.calls.length).toBe(2);
checkInputProps(inputRender.calls[1].arguments[0], 'baz');
});
it('should retain dirty fields if keepDirtyOnReinitialize is set', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var initialValues1 = {
deep: {
foo: 'bar'
}
};
var initialValues2 = {
deep: {
foo: 'baz'
}
};
var Form = function (_Component10) {
_inherits(Form, _Component10);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({
form: 'testForm',
enableReinitialize: true,
keepDirtyOnReinitialize: true
})(Form);
var Container = function (_Component11) {
_inherits(Container, _Component11);
function Container(props) {
_classCallCheck(this, Container);
var _this14 = _possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this, props));
_this14.state = { initialValues: initialValues1 };
return _this14;
}
_createClass(Container, [{
key: 'render',
value: function render() {
var _this15 = this;
return React.createElement(
'div',
null,
React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, this.state)
),
React.createElement(
'button',
{ onClick: function onClick() {
return _this15.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(Component);
var dom = TestUtils.renderIntoDocument(React.createElement(Container, null));
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{ name: 'deep.foo', type: 'Field' }],
initial: initialValues1,
values: initialValues1
}
}
});
expect(formRender).toHaveBeenCalled();
expect(formRender.calls.length).toBe(1);
expect(inputRender).toHaveBeenCalled();
expect(inputRender.calls.length).toBe(1);
var checkInputProps = function checkInputProps(props, value, dirty) {
expect(props.meta.pristine).toBe(!dirty);
expect(props.meta.dirty).toBe(dirty);
expect(props.input.value).toBe(value);
};
checkInputProps(inputRender.calls[0].arguments[0], 'bar', false);
// Change the input value.
var onChange = inputRender.calls[0].arguments[0].input.onChange;
onChange('dirtyvalue');
// Expect rerenders due to the change.
expect(formRender.calls.length).toBe(2);
expect(inputRender.calls.length).toBe(2);
// Reinitialize the form
var initButton = TestUtils.findRenderedDOMComponentWithTag(dom, 'button');
TestUtils.Simulate.click(initButton);
// check initialized state
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{
name: 'deep.foo',
type: 'Field'
}],
initial: initialValues2,
values: {
deep: {
foo: 'dirtyvalue'
}
}
}
}
});
// Expect the form not to rerender, since the value did not change.
expect(formRender.calls.length).toBe(2);
// should rerender input with the dirty value.
expect(inputRender.calls.length).toBe(2);
checkInputProps(inputRender.calls[1].arguments[0], 'dirtyvalue', true);
});
it('should not retain dirty fields if keepDirtyOnReinitialize is not set', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var initialValues1 = {
deep: {
foo: 'bar'
}
};
var initialValues2 = {
deep: {
foo: 'baz'
}
};
var Form = function (_Component12) {
_inherits(Form, _Component12);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({
form: 'testForm',
enableReinitialize: true
})(Form);
var Container = function (_Component13) {
_inherits(Container, _Component13);
function Container(props) {
_classCallCheck(this, Container);
var _this17 = _possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this, props));
_this17.state = { initialValues: initialValues1 };
return _this17;
}
_createClass(Container, [{
key: 'render',
value: function render() {
var _this18 = this;
return React.createElement(
'div',
null,
React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, this.state)
),
React.createElement(
'button',
{ onClick: function onClick() {
return _this18.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(Component);
var dom = TestUtils.renderIntoDocument(React.createElement(Container, null));
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{ name: 'deep.foo', type: 'Field' }],
initial: initialValues1,
values: initialValues1
}
}
});
expect(formRender).toHaveBeenCalled();
expect(formRender.calls.length).toBe(1);
expect(inputRender).toHaveBeenCalled();
expect(inputRender.calls.length).toBe(1);
var checkInputProps = function checkInputProps(props, value, dirty) {
expect(props.meta.pristine).toBe(!dirty);
expect(props.meta.dirty).toBe(dirty);
expect(props.input.value).toBe(value);
};
checkInputProps(inputRender.calls[0].arguments[0], 'bar', false);
// Change the input value.
var onChange = inputRender.calls[0].arguments[0].input.onChange;
onChange('dirtyvalue');
// Expect rerenders due to the change.
expect(formRender.calls.length).toBe(2);
expect(inputRender.calls.length).toBe(2);
// Reinitialize the form
var initButton = TestUtils.findRenderedDOMComponentWithTag(dom, 'button');
TestUtils.Simulate.click(initButton);
// check initialized state
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{
name: 'deep.foo',
type: 'Field'
}],
initial: initialValues2,
values: initialValues2
}
}
});
// Expect the form to rerender, since the value was replaced.
expect(formRender.calls.length).toBe(3);
// should rerender input with the pristine value.
expect(inputRender.calls.length).toBe(3);
checkInputProps(inputRender.calls[2].arguments[0], 'baz', false);
});
it('should make pristine any dirty field that has the new initial value, when keepDirtyOnReinitialize', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var initialValues1 = {
deep: {
foo: 'bar'
}
};
var initialValues2 = {
deep: {
foo: 'futurevalue'
}
};
var Form = function (_Component14) {
_inherits(Form, _Component14);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({
form: 'testForm',
enableReinitialize: true,
keepDirtyOnReinitialize: true
})(Form);
var Container = function (_Component15) {
_inherits(Container, _Component15);
function Container(props) {
_classCallCheck(this, Container);
var _this20 = _possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this, props));
_this20.state = { initialValues: initialValues1 };
return _this20;
}
_createClass(Container, [{
key: 'render',
value: function render() {
var _this21 = this;
return React.createElement(
'div',
null,
React.createElement(
Provider,
{ store: store },
React.createElement(Decorated, this.state)
),
React.createElement(
'button',
{ onClick: function onClick() {
return _this21.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(Component);
var dom = TestUtils.renderIntoDocument(React.createElement(Container, null));
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{ name: 'deep.foo', type: 'Field' }],
initial: initialValues1,
values: initialValues1
}
}
});
expect(formRender).toHaveBeenCalled();
expect(formRender.calls.length).toBe(1);
expect(inputRender).toHaveBeenCalled();
expect(inputRender.calls.length).toBe(1);
var checkInputProps = function checkInputProps(props, value, dirty) {
expect(props.meta.pristine).toBe(!dirty);
expect(props.meta.dirty).toBe(dirty);
expect(props.input.value).toBe(value);
};
checkInputProps(inputRender.calls[0].arguments[0], 'bar', false);
// Change the input value.
var onChange = inputRender.calls[0].arguments[0].input.onChange;
onChange('futurevalue');
// Expect rerenders due to the change.
expect(formRender.calls.length).toBe(2);
expect(inputRender.calls.length).toBe(2);
// Reinitialize the form
var initButton = TestUtils.findRenderedDOMComponentWithTag(dom, 'button');
TestUtils.Simulate.click(initButton);
// check initialized state
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{
name: 'deep.foo',
type: 'Field'
}],
initial: initialValues2,
values: initialValues2
}
}
});
// Expect the form to rerender only once more because the value did
// not change.
expect(formRender.calls.length).toBe(3);
// should rerender input with the new value that is now pristine.
expect(inputRender.calls.length).toBe(3);
checkInputProps(inputRender.calls[2].arguments[0], 'futurevalue', false);
});
// Test related to #1436
/*
it('should allow initialization via action to set pristine', () => {
const store = makeStore({})
const inputRender = createSpy(props => <input {...props.input}/>).andCallThrough()
const formRender = createSpy()
const initialValues1 = {
deep: {
foo: 'bar'
}
}
const initialValues2 = {
deep: {
foo: 'baz'
}
}
class Form extends Component {
render() {
formRender(this.props)
return (
<form>
<Field name="deep.foo" component={inputRender} type="text"/>
</form>
)
}
}
const Decorated = reduxForm({
form: 'testForm',
initialValues: initialValues1
})(Form)
TestUtils.renderIntoDocument(
<Provider store={store}>
<Decorated/>
</Provider>
)
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [ { name: 'deep.foo', type: 'Field' } ],
initial: initialValues1,
values: initialValues1
}
}
})
expect(formRender).toHaveBeenCalled()
expect(formRender.calls.length).toBe(1)
expect(formRender.calls[ 0 ].arguments[ 0 ].pristine).toBe(true)
expect(inputRender).toHaveBeenCalled()
expect(inputRender.calls.length).toBe(1)
expect(inputRender.calls[ 0 ].arguments[ 0 ].meta.pristine).toBe(true)
expect(inputRender.calls[ 0 ].arguments[ 0 ].input.value).toBe('bar')
// check initialized state
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [
{
name: 'deep.foo',
type: 'Field'
}
],
initial: initialValues1,
values: initialValues1
}
}
})
// initialize with action
store.dispatch(initialize('testForm', initialValues2))
// check initialized state
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [
{
name: 'deep.foo',
type: 'Field'
}
],
initial: initialValues2,
values: initialValues2
}
}
})
// rerendered
expect(formRender.calls.length).toBe(2)
expect(formRender.calls[ 1 ].arguments[ 0 ].pristine).toBe(true)
expect(inputRender).toHaveBeenCalled()
expect(inputRender.calls.length).toBe(2)
expect(inputRender.calls[ 1 ].arguments[ 0 ].meta.pristine).toBe(true)
expect(inputRender.calls[ 1 ].arguments[ 0 ].input.value).toBe('baz')
})
*/
it('should destroy on unmount by default', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var Form = function (_Component16) {
_inherits(Form, _Component16);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({
form: 'testForm'
})(Form);
var Container = function (_Component17) {
_inherits(Container, _Component17);
function Container(props) {
_classCallCheck(this, Container);
var _this23 = _possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this, props));
_this23.state = { showForm: true };
return _this23;
}
_createClass(Container, [{
key: 'render',
value: function render() {
var _this24 = this;
var showForm = this.state.showForm;
return React.createElement(
'div',
null,
React.createElement(
Provider,
{ store: store },
React.createElement(
'div',
null,
showForm && React.createElement(Decorated, this.state)
)
),
React.createElement(
'button',
{ onClick: function onClick() {
return _this24.setState({ showForm: !showForm });
} },
'Toggle'
)
);
}
}]);
return Container;
}(Component);
var dom = TestUtils.renderIntoDocument(React.createElement(Container, null));
expect(store.getState()).toEqualMap({
form: {
testForm: {
registeredFields: [{ name: 'deep.foo', type: 'Field' }]
}
}
}, 'Form data in Redux did not get destroyed');
expect(formRender).toHaveBeenCalled();
expect(formRender.calls.length).toBe(1);
expect(inputRender).toHaveBeenCalled();
expect(inputRender.calls.length).toBe(1);
expect(inputRender.calls[0].arguments[0].input.value).toBe('');
// change field
inputRender.calls[0].arguments[0].input.onChange('bob');
// form rerenders because now dirty
expect(formRender.calls.length).toBe(2);
// input now has value
expect(inputRender.calls.length).toBe(2);
expect(inputRender.calls[1].arguments[0].input.value).toBe('bob');
// check state
expect(store.getState()).toEqualMap({
form: {
testForm: {
values: {
deep: {
foo: 'bob'
}
},
registeredFields: [{ name: 'deep.foo', type: 'Field' }]
}
}
});
// unmount form
var toggle = TestUtils.findRenderedDOMComponentWithTag(dom, 'button');
TestUtils.Simulate.click(toggle);
// check clean state
expect(store.getState()).toEqualMap({
form: {}
});
// form still not rendered again
expect(formRender.calls.length).toBe(2);
// toggle form back into existence
TestUtils.Simulate.click(toggle);
// form is back
expect(formRender.calls.length).toBe(3);
// input is back, but without value
expect(inputRender.calls.length).toBe(3);
expect(inputRender.calls[2].arguments[0].input.value).toBe('');
});
it('should not destroy on unmount if told not to', function () {
var store = makeStore({});
var inputRender = createSpy(function (props) {
return React.createElement('input', props.input);
}).andCallThrough();
var formRender = createSpy();
var Form = function (_Component18) {
_inherits(Form, _Component18);
function Form() {
_classCallCheck(this, Form);
return _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).apply(this, arguments));
}
_createClass(Form, [{
key: 'render',
value: function render() {
formRender(this.props);
return React.createElement(
'form',
null,
React.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(Component);
var Decorated = reduxForm({
form: 'testForm',
destroyOnUnmount: false
})(Form);
var Container = function (_Component19) {
_inherits(Container, _Component19);
function Container(props) {
_classCallCheck(this, Container);
var _this26 = _possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this, props));
_this26.state = { showForm: true };
return _this26;
}
_createClass(Container, [{
key: 'render',
value: function render() {
var _this27 = this;
var showForm = this.state.showForm;
return React.createElement(
'div',
null,
React.createElement(
Provider,
{ store: store },
Re