redux-form
Version:
A higher order component decorator for forms using Redux and React
1,490 lines (1,253 loc) • 121 kB
JavaScript
'use strict';
var _noop2 = require('lodash/noop');
var _noop3 = _interopRequireDefault(_noop2);
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; }; }();
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactAddonsTestUtils = require('react-addons-test-utils');
var _reactAddonsTestUtils2 = _interopRequireDefault(_reactAddonsTestUtils);
var _expect = require('expect');
var _redux = require('redux');
var _reduxImmutablejs = require('redux-immutablejs');
var _reactRedux = require('react-redux');
var _reducer = require('../reducer');
var _reducer2 = _interopRequireDefault(_reducer);
var _reduxForm = require('../reduxForm');
var _reduxForm2 = _interopRequireDefault(_reduxForm);
var _Field = require('../Field');
var _Field2 = _interopRequireDefault(_Field);
var _FieldArray = require('../FieldArray');
var _FieldArray2 = _interopRequireDefault(_FieldArray);
var _actions = require('../actions');
var _plain = require('../structure/plain');
var _plain2 = _interopRequireDefault(_plain);
var _expectations = require('../structure/plain/expectations');
var _expectations2 = _interopRequireDefault(_expectations);
var _immutable = require('../structure/immutable');
var _immutable2 = _interopRequireDefault(_immutable);
var _expectations3 = require('../structure/immutable/expectations');
var _expectations4 = _interopRequireDefault(_expectations3);
var _addExpectations = require('./addExpectations');
var _addExpectations2 = _interopRequireDefault(_addExpectations);
var _SubmissionError = require('../SubmissionError');
var _SubmissionError2 = _interopRequireDefault(_SubmissionError);
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 describeReduxForm = function describeReduxForm(name, structure, combineReducers, expect) {
var fromJS = structure.fromJS;
var getIn = structure.getIn;
var reduxForm = (0, _reduxForm2.default)(structure);
var Field = (0, _Field2.default)(structure);
var FieldArray = (0, _FieldArray2.default)(structure);
var reducer = (0, _reducer2.default)(structure);
describe(name, function () {
var makeStore = function makeStore() {
var initial = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
return (0, _redux.createStore)(combineReducers({ form: reducer }), fromJS({ form: initial }));
};
var propChecker = function propChecker(formState) {
var renderSpy = arguments.length <= 1 || arguments[1] === undefined ? _noop3.default : 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 _react2.default.createElement(
'div',
null,
_react2.default.createElement(Field, { name: 'foo', component: 'input' })
);
}
}]);
return Form;
}(_react.Component);
var Decorated = reduxForm(_extends({ form: 'testForm' }, config))(Form);
var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.createElement(Decorated, null)
));
return _reactAddonsTestUtils2.default.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 _react2.default.createElement('div', null);
}
}]);
return Form;
}(_react.Component);
expect(function () {
var Decorated = reduxForm({ form: 'testForm' })(Form);
_reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.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({}, _noop3.default, {
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 = (0, _expect.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((0, _actions.change)('testForm', 'foo', 'g')); // render 1 (now dirty)
expect(spy.calls.length).toBe(2);
dispatch((0, _actions.change)('testForm', 'foo', 'gi')); // no render
dispatch((0, _actions.change)('testForm', 'foo', 'gir')); // no render
dispatch((0, _actions.change)('testForm', 'foo', 'gira')); // no render
dispatch((0, _actions.change)('testForm', 'foo', 'giraf')); // no render
dispatch((0, _actions.change)('testForm', 'foo', 'giraff')); // render 2 (invalid)
expect(spy.calls.length).toBe(3);
dispatch((0, _actions.change)('testForm', 'foo', 'giraffe')); // no render
dispatch((0, _actions.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 = (0, _expect.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((0, _actions.change)('testForm', 'foo', 'g'));
expect(spy.calls.length).toBe(3);
dispatch((0, _actions.change)('testForm', 'foo', 'gi'));
expect(spy.calls.length).toBe(4);
dispatch((0, _actions.change)('testForm', 'foo', 'gir'));
expect(spy.calls.length).toBe(5);
dispatch((0, _actions.change)('testForm', 'foo', 'gira'));
expect(spy.calls.length).toBe(6);
dispatch((0, _actions.change)('testForm', 'foo', 'giraf'));
expect(spy.calls.length).toBe(7);
dispatch((0, _actions.change)('testForm', 'foo', 'giraff'));
expect(spy.calls.length).toBe(8);
dispatch((0, _actions.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 = (0, _expect.createSpy)(function (props) {
return _react2.default.createElement('input', props.input);
}).andCallThrough();
var formRender = (0, _expect.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 _react2.default.createElement(
'form',
null,
_react2.default.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(_react.Component);
var Decorated = reduxForm({ form: 'testForm' })(Form);
_reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.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 = (0, _expect.createSpy)(function (props) {
return _react2.default.createElement('input', props.input);
}).andCallThrough();
var formRender = (0, _expect.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 _react2.default.createElement(
'form',
null,
_react2.default.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(_react.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 _react2.default.createElement(
'div',
null,
_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.createElement(Decorated, this.state)
),
_react2.default.createElement(
'button',
{ onClick: function onClick() {
return _this6.setState({ initialValues: initialValues });
} },
'Init'
)
);
}
}]);
return Container;
}(_react.Component);
var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.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 = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'button');
_reactAddonsTestUtils2.default.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 = (0, _expect.createSpy)(function (props) {
return _react2.default.createElement('input', props.input);
}).andCallThrough();
var formRender = (0, _expect.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 _react2.default.createElement(
'form',
null,
_react2.default.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(_react.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 _react2.default.createElement(
'div',
null,
_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.createElement(Decorated, this.state)
),
_react2.default.createElement(
'button',
{ onClick: function onClick() {
return _this9.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(_react.Component);
var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.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 = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'button');
_reactAddonsTestUtils2.default.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 = (0, _expect.createSpy)(function (props) {
return _react2.default.createElement('input', props.input);
}).andCallThrough();
var formRender = (0, _expect.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 _react2.default.createElement(
'form',
null,
_react2.default.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(_react.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 _react2.default.createElement(
'div',
null,
_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.createElement(Decorated, this.state)
),
_react2.default.createElement(
'button',
{ onClick: function onClick() {
return _this12.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(_react.Component);
var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.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 = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'button');
_reactAddonsTestUtils2.default.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 = (0, _expect.createSpy)(function (props) {
return _react2.default.createElement('input', props.input);
}).andCallThrough();
var formRender = (0, _expect.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 _react2.default.createElement(
'form',
null,
_react2.default.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(_react.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 _react2.default.createElement(
'div',
null,
_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.createElement(Decorated, this.state)
),
_react2.default.createElement(
'button',
{ onClick: function onClick() {
return _this15.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(_react.Component);
var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.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 = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'button');
_reactAddonsTestUtils2.default.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 = (0, _expect.createSpy)(function (props) {
return _react2.default.createElement('input', props.input);
}).andCallThrough();
var formRender = (0, _expect.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 _react2.default.createElement(
'form',
null,
_react2.default.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(_react.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 _react2.default.createElement(
'div',
null,
_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.createElement(Decorated, this.state)
),
_react2.default.createElement(
'button',
{ onClick: function onClick() {
return _this18.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(_react.Component);
var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.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 = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'button');
_reactAddonsTestUtils2.default.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 = (0, _expect.createSpy)(function (props) {
return _react2.default.createElement('input', props.input);
}).andCallThrough();
var formRender = (0, _expect.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 _react2.default.createElement(
'form',
null,
_react2.default.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(_react.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 _react2.default.createElement(
'div',
null,
_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.createElement(Decorated, this.state)
),
_react2.default.createElement(
'button',
{ onClick: function onClick() {
return _this21.setState({ initialValues: initialValues2 });
} },
'Init'
)
);
}
}]);
return Container;
}(_react.Component);
var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.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 = _reactAddonsTestUtils2.default.findRenderedDOMComponentWithTag(dom, 'button');
_reactAddonsTestUtils2.default.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 = (0, _expect.createSpy)(function (props) {
return _react2.default.createElement('input', props.input);
}).andCallThrough();
var formRender = (0, _expect.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 _react2.default.createElement(
'form',
null,
_react2.default.createElement(Field, { name: 'deep.foo', component: inputRender, type: 'text' })
);
}
}]);
return Form;
}(_react.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 _react2.default.createElement(
'div',
null,
_react2.default.createElement(
_reactRedux.Provider,
{ store: store },
_react2.default.createElement(
'div',
null,
showForm && _react2.default.createElement(Decorated, this.state)
)
),
_react2.default.createElement(
'button',
{ onClick: function onClick() {
return _this24.setState({ showForm: !showForm });
} },
'Toggle'
)
);
}
}]);
return Container;
}(_react.Component);
var dom = _reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.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: