UNPKG

redux-form

Version:

A higher order component decorator for forms using Redux and React

1,896 lines (1,843 loc) 92.7 kB
import expect from 'expect'; import reducer, {globalErrorKey} from '../reducer'; import bindActionData from '../bindActionData'; import {addArrayValue, blur, change, focus, initialize, removeArrayValue, reset, startAsyncValidation, startSubmit, stopAsyncValidation, stopSubmit, swapArrayValues, touch, untouch, destroy} from '../actions'; import {isFieldValue, makeFieldValue} from '../fieldValue'; const compare = (a, b) => { if (a.value > b.value) { return 1; } if (a.value < b.value) { return -1; } return 0; }; describe('reducer', () => { it('should initialize state to {}', () => { const state = reducer(); expect(state) .toExist() .toBeA('object'); expect(Object.keys(state).length).toBe(0); }); it('should not modify state when action has no form', () => { const state = {foo: 'bar'}; expect(reducer(state, {type: 'SOMETHING_ELSE'})).toBe(state); }); it('should initialize form state when action has form', () => { const state = reducer(undefined, {form: 'foo'}); expect(state) .toExist() .toBeA('object'); expect(Object.keys(state).length).toBe(1); expect(state.foo) .toExist() .toBeA('object') .toEqual({ _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); }); it('should add an empty array value with empty state', () => { const state = reducer({}, { ...addArrayValue('myField'), form: 'foo' }); expect(state.foo) .toEqual({ myField: [ { value: undefined } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(false); expect(isFieldValue(state.foo.myField[0])).toBe(true); }); it('should add an empty deep array value with empty state', () => { const state = reducer({}, { ...addArrayValue('myField.myArray'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { myArray: [ { value: undefined } ] }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(false); expect(isFieldValue(state.foo.myField.myArray)).toBe(false); expect(isFieldValue(state.foo.myField.myArray[0])).toBe(true); }); it('should add a deep array value with initial value', () => { const state = reducer({}, { ...addArrayValue('myField.myArray', 20, undefined), form: 'foo' }); expect(state.foo) .toEqual({ myField: { myArray: [ { value: 20 } ] }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(false); expect(isFieldValue(state.foo.myField.myArray)).toBe(false); expect(isFieldValue(state.foo.myField.myArray[0])).toBe(true); }); it('should push an array value', () => { const state = reducer({ testForm: { myField: [ makeFieldValue({ value: 'foo' }), makeFieldValue({ value: 'bar' }) ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...addArrayValue('myField', 'baz'), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { value: 'foo' }, { value: 'bar' }, { value: 'baz' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(true); expect(isFieldValue(state.testForm.myField[2])).toBe(true); }); it('should insert an array value', () => { const state = reducer({ testForm: { myField: [ makeFieldValue({ value: 'foo' }), makeFieldValue({ value: 'bar' }) ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...addArrayValue('myField', 'baz', 1), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { value: 'foo' }, { value: 'baz' }, { value: 'bar' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(true); expect(isFieldValue(state.testForm.myField[2])).toBe(true); }); // TODO: Find a way to make this pass: /* it('should push an array value which is a deep object', () => { const state = reducer({ testForm: { friends: [ { name: { initial: 'name-1', value: 'name-1' }, address: { street: { initial: 'street-1', value: 'street-1' }, postalCode: { initial: 'postalCode-1', value: 'postalCode-1' } } }, { name: { initial: 'name-2', value: 'name-2' }, address: { street: { initial: 'street-2', value: 'street-2' }, postalCode: { initial: 'postalCode-2', value: 'postalCode-2' } } } ], _active: undefined, _asyncValidating: false, _error: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...addArrayValue('friends', { name: 'name-3', address: { street: 'street-3', postalCode: 'postalCode-3' } }, undefined), form: 'testForm' }); expect(state.testForm) .toEqual({ friends: [ { name: { initial: 'name-1', value: 'name-1' }, address: { street: { initial: 'street-1', value: 'street-1' }, postalCode: { initial: 'postalCode-1', value: 'postalCode-1' } } }, { name: { initial: 'name-2', value: 'name-2' }, address: { street: { initial: 'street-2', value: 'street-2' }, postalCode: { initial: 'postalCode-2', value: 'postalCode-2' } } }, { name: { initial: 'name-3', value: 'name-3' }, address: { street: { initial: 'street-3', value: 'street-3' }, postalCode: { initial: 'postalCode-3', value: 'postalCode-3' } } } ], _active: undefined, _asyncValidating: false, _error: undefined, _initialized: false, _submitting: false, _submitFailed: false }); }); */ it('should push a deep array value which is a nested object', () => { const state = reducer({ testForm: { myField: [ { foo: makeFieldValue({ initial: {a: 'foo-a1', b: 'foo-b1'}, value: {a: 'foo-a1', b: 'foo-b1'}, }), bar: makeFieldValue({ initial: {a: 'bar-a1', b: 'bar-b1'}, value: {a: 'bar-a1', b: 'bar-b1'}, }) }, { foo: makeFieldValue({ initial: {a: 'foo-a2', b: 'foo-b2'}, value: {a: 'foo-a2', b: 'foo-b2'}, }), bar: makeFieldValue({ initial: {a: 'bar-a2', b: 'bar-b2'}, value: {a: 'bar-a2', b: 'bar-b2'}, }) }, ], _active: undefined, _asyncValidating: false, _error: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...addArrayValue('myField', { foo: {a: 'foo-a3', b: 'foo-b3'}, bar: {a: 'bar-a3', b: 'bar-b3'} }, undefined), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { foo: { initial: {a: 'foo-a1', b: 'foo-b1'}, value: {a: 'foo-a1', b: 'foo-b1'}, }, bar: { initial: {a: 'bar-a1', b: 'bar-b1'}, value: {a: 'bar-a1', b: 'bar-b1'}, } }, { foo: { initial: {a: 'foo-a2', b: 'foo-b2'}, value: {a: 'foo-a2', b: 'foo-b2'}, }, bar: { initial: {a: 'bar-a2', b: 'bar-b2'}, value: {a: 'bar-a2', b: 'bar-b2'}, } }, { foo: { initial: {a: 'foo-a3', b: 'foo-b3'}, value: {a: 'foo-a3', b: 'foo-b3'}, }, bar: { initial: {a: 'bar-a3', b: 'bar-b3'}, value: {a: 'bar-a3', b: 'bar-b3'}, } }, ], _active: undefined, _asyncValidating: false, _error: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(false); expect(isFieldValue(state.testForm.myField[0].foo)).toBe(true); expect(isFieldValue(state.testForm.myField[0].bar)).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(false); expect(isFieldValue(state.testForm.myField[1].foo)).toBe(true); expect(isFieldValue(state.testForm.myField[1].bar)).toBe(true); expect(isFieldValue(state.testForm.myField[2])).toBe(false); expect(isFieldValue(state.testForm.myField[2].foo)).toBe(true); expect(isFieldValue(state.testForm.myField[2].bar)).toBe(true); }); it('should push a subarray value which is an object', () => { const state = reducer({ testForm: { myField: [ { myField2: [ { foo: makeFieldValue({ initial: 'foo-1-1', value: 'foo-1-1' }), bar: makeFieldValue({ initial: 'bar-1-1', value: 'bar-1-1' }) }, { foo: makeFieldValue({ initial: 'foo-1-2', value: 'foo-1-2' }), bar: makeFieldValue({ initial: 'bar-1-2', value: 'bar-1-2' }) } ] }, { myField2: [ { foo: makeFieldValue({ initial: 'foo-2-1', value: 'foo-2-1' }), bar: makeFieldValue({ initial: 'bar-2-1', value: 'bar-2-1' }) }, { foo: makeFieldValue({ initial: 'foo-2-2', value: 'foo-2-2' }), bar: makeFieldValue({ initial: 'bar-2-2', value: 'bar-2-2' }) } ] } ], _active: undefined, _asyncValidating: false, _error: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...addArrayValue('myField[1].myField2', {foo: 'foo-2-3', bar: 'bar-2-3'}, undefined), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { myField2: [ { foo: { initial: 'foo-1-1', value: 'foo-1-1' }, bar: { initial: 'bar-1-1', value: 'bar-1-1' } }, { foo: { initial: 'foo-1-2', value: 'foo-1-2' }, bar: { initial: 'bar-1-2', value: 'bar-1-2' } }, ], }, { myField2: [ { foo: { initial: 'foo-2-1', value: 'foo-2-1' }, bar: { initial: 'bar-2-1', value: 'bar-2-1' } }, { foo: { initial: 'foo-2-2', value: 'foo-2-2' }, bar: { initial: 'bar-2-2', value: 'bar-2-2' } }, { foo: { initial: 'foo-2-3', value: 'foo-2-3' }, bar: { initial: 'bar-2-3', value: 'bar-2-3' } }, ], }, ], _active: undefined, _asyncValidating: false, _error: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(false); expect(isFieldValue(state.testForm.myField[0].myField2)).toBe(false); expect(isFieldValue(state.testForm.myField[0].myField2[0])).toBe(false); expect(isFieldValue(state.testForm.myField[0].myField2[0].foo)).toBe(true); expect(isFieldValue(state.testForm.myField[0].myField2[0].bar)).toBe(true); expect(isFieldValue(state.testForm.myField[0].myField2[1])).toBe(false); expect(isFieldValue(state.testForm.myField[0].myField2[1].foo)).toBe(true); expect(isFieldValue(state.testForm.myField[0].myField2[1].bar)).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(false); expect(isFieldValue(state.testForm.myField[1].myField2)).toBe(false); expect(isFieldValue(state.testForm.myField[1].myField2[0])).toBe(false); expect(isFieldValue(state.testForm.myField[1].myField2[0].foo)).toBe(true); expect(isFieldValue(state.testForm.myField[1].myField2[0].bar)).toBe(true); expect(isFieldValue(state.testForm.myField[1].myField2[1])).toBe(false); expect(isFieldValue(state.testForm.myField[1].myField2[1].foo)).toBe(true); expect(isFieldValue(state.testForm.myField[1].myField2[1].bar)).toBe(true); expect(isFieldValue(state.testForm.myField[1].myField2[2])).toBe(false); expect(isFieldValue(state.testForm.myField[1].myField2[2].foo)).toBe(true); expect(isFieldValue(state.testForm.myField[1].myField2[2].bar)).toBe(true); }); it('should set value on blur with empty state', () => { const state = reducer({}, { ...blur('myField', 'myValue'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { value: 'myValue' }, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set value on blur and touch with empty state', () => { const state = reducer({}, { ...blur('myField', 'myValue'), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myField: { value: 'myValue', touched: true }, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set value on blur and touch with initial value', () => { const state = reducer({ foo: { myField: makeFieldValue({ initial: 'initialValue', value: 'initialValue', touched: false }), _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...blur('myField', 'myValue'), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myField: { initial: 'initialValue', value: 'myValue', touched: true }, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should not modify value if undefined is passed on blur (for android react native)', () => { const state = reducer({ foo: { myField: makeFieldValue({ initial: 'initialValue', value: 'myValue', touched: false }), _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...blur('myField'), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myField: { initial: 'initialValue', value: 'myValue', touched: true }, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should not modify value if undefined is passed on blur, even if no value existed (for android react native)', () => { const state = reducer({ foo: { myField: makeFieldValue({ value: undefined }), _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...blur('myField'), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myField: { value: undefined, touched: true }, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set nested value on blur', () => { const state = reducer({ foo: { myField: { mySubField: makeFieldValue({ value: undefined }) }, _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...blur('myField.mySubField', 'hello'), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myField: { mySubField: { value: 'hello', touched: true } }, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(false); expect(isFieldValue(state.foo.myField.mySubField)).toBe(true); }); it('should set array value on blur', () => { const state = reducer({ foo: { myArray: [ makeFieldValue({value: undefined}) ], _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...blur('myArray[0]', 'hello'), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myArray: [ { value: 'hello', touched: true } ], _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myArray[0])).toBe(true); }); it('should set value on change with empty state', () => { const state = reducer({}, { ...change('myField', 'myValue'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { value: 'myValue' }, _active: undefined, // CHANGE doesn't touch _active _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set value on change and touch with empty state', () => { const state = reducer({}, { ...change('myField', 'myValue'), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myField: { value: 'myValue', touched: true }, _active: undefined, // CHANGE doesn't touch _active _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set value on change and touch with initial value', () => { const state = reducer({ foo: { myField: makeFieldValue({ initial: 'initialValue', value: 'initialValue', touched: false }), _active: 'myField', _asyncValidating: false, [globalErrorKey]: 'Some global error', _initialized: false, _submitting: false, _submitFailed: false } }, { ...change('myField', 'myValue'), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myField: { initial: 'initialValue', value: 'myValue', touched: true }, _active: 'myField', _asyncValidating: false, [globalErrorKey]: 'Some global error', _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set value on change and remove field-level submit and async errors', () => { const state = reducer({ foo: { myField: makeFieldValue({ value: 'initial', submitError: 'submit error', asyncError: 'async error' }), _active: 'myField', _asyncValidating: false, [globalErrorKey]: 'Some global error', _initialized: false, _submitting: false, _submitFailed: false } }, { ...change('myField', 'different'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { value: 'different' }, _active: 'myField', _asyncValidating: false, [globalErrorKey]: 'Some global error', _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set nested value on change with empty state', () => { const state = reducer({}, { ...change('myField.mySubField', 'myValue'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { mySubField: { value: 'myValue' } }, _active: undefined, // CHANGE doesn't touch _active _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(false); expect(isFieldValue(state.foo.myField.mySubField)).toBe(true); }); it('should set visited on focus and update active with no previous state', () => { const state = reducer({}, { ...focus('myField'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { visited: true }, _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set visited on focus and update active on deep field with no previous state', () => { const state = reducer({}, { ...focus('myField.subField'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { subField: { visited: true } }, _active: 'myField.subField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(false); expect(isFieldValue(state.foo.myField.subField)).toBe(true); }); it('should set visited on focus and update current with previous state', () => { const state = reducer({ foo: { myField: makeFieldValue({ initial: 'initialValue', value: 'initialValue', visited: false }), _active: 'otherField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...focus('myField'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { initial: 'initialValue', value: 'initialValue', visited: true }, _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set initialize values on initialize on empty state', () => { const state = reducer({}, { ...initialize({myField: 'initialValue'}, ['myField']), form: 'foo' }); expect(state.foo) .toEqual({ myField: { initial: 'initialValue', value: 'initialValue' }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: true, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should allow initializing null values', () => { const state = reducer({}, { ...initialize({bar: 'baz', dog: null}, ['bar', 'dog']), form: 'foo' }); expect(state.foo) .toEqual({ bar: { initial: 'baz', value: 'baz' }, dog: { initial: null, value: null }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: true, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.bar)).toBe(true); expect(isFieldValue(state.foo.dog)).toBe(true); }); it('should initialize nested values on initialize on empty state', () => { const state = reducer({}, { ...initialize({myField: {subField: 'initialValue'}}, ['myField.subField'], {}), form: 'foo' }); expect(state.foo) .toEqual({ myField: { subField: { initial: 'initialValue', value: 'initialValue' } }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: true, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(false); expect(isFieldValue(state.foo.myField.subField)).toBe(true); }); it('should initialize array values on initialize on empty state', () => { const state = reducer({}, { ...initialize({myField: ['initialValue']}, ['myField[]'], {}), form: 'foo' }); expect(state.foo) .toEqual({ myField: [ { initial: 'initialValue', value: 'initialValue' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: true, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(false); expect(isFieldValue(state.foo.myField[0])).toBe(true); }); it('should initialize array values with subvalues on initialize on empty state', () => { const state = reducer({}, { ...initialize({ accounts: [ { name: 'Bobby Tables', email: 'bobby@gmail.com' }, { name: 'Sammy Tables', email: 'sammy@gmail.com' } ] }, ['accounts[].name', 'accounts[].email'], {}), form: 'foo' }); expect(state.foo) .toEqual({ accounts: [ { name: { initial: 'Bobby Tables', value: 'Bobby Tables' }, email: { initial: 'bobby@gmail.com', value: 'bobby@gmail.com' } }, { name: { initial: 'Sammy Tables', value: 'Sammy Tables' }, email: { initial: 'sammy@gmail.com', value: 'sammy@gmail.com' } } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: true, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.accounts)).toBe(false); expect(isFieldValue(state.foo.accounts[0])).toBe(false); expect(isFieldValue(state.foo.accounts[0].name)).toBe(true); expect(isFieldValue(state.foo.accounts[0].email)).toBe(true); expect(isFieldValue(state.foo.accounts[1])).toBe(false); expect(isFieldValue(state.foo.accounts[1].name)).toBe(true); expect(isFieldValue(state.foo.accounts[1].email)).toBe(true); }); it('should set initialize values, making form pristine when initializing', () => { const state = reducer({ foo: { myField: makeFieldValue({ value: 'dirtyValue', touched: true }), _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...initialize({myField: 'cleanValue'}, ['myField']), form: 'foo', touch: true }); expect(state.foo) .toEqual({ myField: { initial: 'cleanValue', value: 'cleanValue' }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: true, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should pop an array value', () => { const state = reducer({ testForm: { myField: [ makeFieldValue({ value: 'foo' }), makeFieldValue({ value: 'bar' }) ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...removeArrayValue('myField'), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { value: 'foo' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(true); }); it('should not change empty array value on remove', () => { const state = reducer({ testForm: { myField: [], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...removeArrayValue('myField'), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); }); it('should remove an array value from start of array', () => { const state = reducer({ testForm: { myField: [ makeFieldValue({ value: 'foo' }), makeFieldValue({ value: 'bar' }), makeFieldValue({ value: 'baz' }) ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...removeArrayValue('myField', 0), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { value: 'bar' }, { value: 'baz' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(true); }); it('should remove an array value from middle of array', () => { const state = reducer({ testForm: { myField: [ makeFieldValue({ value: 'foo' }), makeFieldValue({ value: 'bar' }), makeFieldValue({ value: 'baz' }) ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...removeArrayValue('myField', 1), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { value: 'foo' }, { value: 'baz' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(true); }); it('should not change empty array value on swap', () => { const state = reducer({ testForm: { myField: [], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...swapArrayValues('myField'), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); }); it('should should swap two array values at different indexes', () => { const state = reducer({ testForm: { myField: [ makeFieldValue({ value: 'foo' }), makeFieldValue({ value: 'bar' }), makeFieldValue({ value: 'baz' }) ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...swapArrayValues('myField', 0, 2), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { value: 'baz' }, { value: 'bar' }, { value: 'foo' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(true); expect(isFieldValue(state.testForm.myField[2])).toBe(true); }); it('should not change array on swap with the same index', () => { const state = reducer({ testForm: { myField: [ makeFieldValue({ value: 'foo' }), makeFieldValue({ value: 'bar' }), makeFieldValue({ value: 'baz' }) ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...swapArrayValues('myField', 1, 1), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { value: 'foo' }, { value: 'bar' }, { value: 'baz' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(true); expect(isFieldValue(state.testForm.myField[2])).toBe(true); }); it('should not change array on swap with out of bounds index', () => { const state = reducer({ testForm: { myField: [ makeFieldValue({ value: 'foo' }), makeFieldValue({ value: 'bar' }), makeFieldValue({ value: 'baz' }) ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...swapArrayValues('myField', 1, 4), form: 'testForm' }); expect(state.testForm) .toEqual({ myField: [ { value: 'foo' }, { value: 'bar' }, { value: 'baz' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.testForm.myField)).toBe(false); expect(isFieldValue(state.testForm.myField[0])).toBe(true); expect(isFieldValue(state.testForm.myField[1])).toBe(true); expect(isFieldValue(state.testForm.myField[2])).toBe(true); }); it('should reset values on reset on with previous state', () => { const state = reducer({ foo: { myField: makeFieldValue({ initial: 'initialValue', value: 'dirtyValue', touched: true }), myOtherField: makeFieldValue({ initial: 'otherInitialValue', value: 'otherDirtyValue', touched: true }), _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...reset(), form: 'foo' }); expect(state.foo) .toEqual({ myField: { initial: 'initialValue', value: 'initialValue' }, myOtherField: { initial: 'otherInitialValue', value: 'otherInitialValue' }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); expect(isFieldValue(state.foo.myOtherField)).toBe(true); }); it('should reset deep values on reset on with previous state', () => { const state = reducer({ foo: { deepField: { myField: makeFieldValue({ initial: 'initialValue', value: 'dirtyValue', touched: true }), myOtherField: makeFieldValue({ initial: 'otherInitialValue', value: 'otherDirtyValue', touched: true }) }, _active: 'myField', _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...reset(), form: 'foo' }); expect(state.foo) .toEqual({ deepField: { myField: { initial: 'initialValue', value: 'initialValue' }, myOtherField: { initial: 'otherInitialValue', value: 'otherInitialValue' } }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.deepField)).toBe(false); expect(isFieldValue(state.foo.deepField.myField)).toBe(true); expect(isFieldValue(state.foo.deepField.myOtherField)).toBe(true); }); it('should set asyncValidating on startAsyncValidation', () => { const state = reducer({ foo: { doesnt: 'matter', should: 'notchange', _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...startAsyncValidation(), form: 'foo' }); expect(state.foo) .toEqual({ doesnt: 'matter', should: 'notchange', _active: undefined, _asyncValidating: true, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); }); it('should set asyncValidating with field name on startAsyncValidation', () => { const state = reducer({ foo: { myField: makeFieldValue({ initial: 'initialValue', value: 'initialValue' }), doesnt: 'matter', should: 'notchange', _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...startAsyncValidation('myField'), form: 'foo' }); expect(state.foo) .toEqual({ myField: { initial: 'initialValue', value: 'initialValue' }, doesnt: 'matter', should: 'notchange', _active: undefined, _asyncValidating: 'myField', [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.myField)).toBe(true); }); it('should set submitting on startSubmit', () => { const state = reducer({ foo: { doesnt: 'matter', should: 'notchange', _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...startSubmit(), form: 'foo' }); expect(state.foo) .toEqual({ doesnt: 'matter', should: 'notchange', _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: true, _submitFailed: false }); }); it('should set submitting on startSubmit, and NOT reset submitFailed', () => { const state = reducer({ foo: { doesnt: 'matter', should: 'notchange', _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: true } }, { ...startSubmit(), form: 'foo' }); expect(state.foo) .toEqual({ doesnt: 'matter', should: 'notchange', _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: true, _submitFailed: true }); }); it('should set asyncError on nested fields on stopAsyncValidation', () => { const state = reducer({ foo: { bar: { myField: makeFieldValue({ initial: 'initialValue', value: 'dirtyValue', touched: true }), myOtherField: makeFieldValue({ initial: 'otherInitialValue', value: 'otherDirtyValue', touched: true }) }, _active: undefined, _asyncValidating: true, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...stopAsyncValidation({ bar: { myField: 'Error about myField', myOtherField: 'Error about myOtherField' } }), form: 'foo' }); expect(state.foo) .toEqual({ bar: { myField: { initial: 'initialValue', value: 'dirtyValue', touched: true, asyncError: 'Error about myField' }, myOtherField: { initial: 'otherInitialValue', value: 'otherDirtyValue', touched: true, asyncError: 'Error about myOtherField' } }, _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.bar)).toBe(false); expect(isFieldValue(state.foo.bar.myField)).toBe(true); expect(isFieldValue(state.foo.bar.myOtherField)).toBe(true); }); it('should set asyncError on array fields on stopAsyncValidation', () => { const state = reducer({ foo: { bar: [ makeFieldValue({ initial: 'initialValue', value: 'dirtyValue', touched: true }), makeFieldValue({ initial: 'otherInitialValue', value: 'otherDirtyValue', touched: true }) ], _active: undefined, _asyncValidating: true, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false } }, { ...stopAsyncValidation({ bar: [ 'Error about myField', 'Error about myOtherField' ] }), form: 'foo' }); expect(state.foo) .toEqual({ bar: [ { initial: 'initialValue', value: 'dirtyValue', touched: true, asyncError: 'Error about myField' }, { initial: 'otherInitialValue', value: 'otherDirtyValue', touched: true, asyncError: 'Error about myOtherField' } ], _active: undefined, _asyncValidating: false, [globalErrorKey]: undefined, _initialized: false, _submitting: false, _submitFailed: false }); expect(isFieldValue(state.foo.bar)).toBe(false); expect(isFieldValue(state.foo.bar[0])).toBe(true); expect(isFieldValue(state.foo.bar[1])).toBe(true); }); it('should unset asyncValidating on stopAsyncValidation', () => { const state = reducer({ foo: { myField: makeFieldValue({ initial: 'initialValue', value: 'dirtyValue', touched: true }), myOtherField: makeFieldValue({ initial: 'otherIni