fix(object): retain deletions to properties/array elements
This commit is contained in:
parent
cb4f155a29
commit
09e5b9c922
|
@ -2002,7 +2002,7 @@
|
|||
"dependencies": {
|
||||
"jest-cli": {
|
||||
"version": "20.0.4",
|
||||
"resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-20.0.4.tgz",
|
||||
"resolved": "https://npm.onfido.co.uk:443/jest-cli/-/jest-cli-20.0.4.tgz",
|
||||
"integrity": "sha1-5TKxnYiuW8bEF+iwWTpv6VSx3JM=",
|
||||
"dev": true
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ describe('buildStoreChunk', () => {
|
|||
innerNested3: Types.reducer(Types.string('baz')),
|
||||
}),
|
||||
}),
|
||||
nested5: Types.reducer(Types.shape({
|
||||
arrayExample: Types.arrayOf(Types.string()),
|
||||
})),
|
||||
});
|
||||
const nonNestedChunk = buildStoreChunk('example2', Types.reducer(Types.string('foo')));
|
||||
|
||||
|
@ -51,7 +54,7 @@ describe('buildStoreChunk', () => {
|
|||
}));
|
||||
|
||||
it('Selectors object has the correct top level structure for a nested chunk', () => {
|
||||
expect(Object.keys(chunk.selectors)).toEqual(['nested1', 'nested2', 'nested3', 'nested4']);
|
||||
expect(Object.keys(chunk.selectors)).toEqual(['nested1', 'nested2', 'nested3', 'nested4', 'nested5']);
|
||||
});
|
||||
it('Selectors object is a function for a non-nested chunk', () => {
|
||||
expect(isFunction(nonNestedChunk.selectors)).toBe(true);
|
||||
|
@ -69,7 +72,7 @@ describe('buildStoreChunk', () => {
|
|||
|
||||
describe('Actions', () => {
|
||||
it('Actions object has the correct top level structure for a nested chunk', () => {
|
||||
expect(Object.keys(chunk.actions)).toEqual(['nested1', 'nested2', 'nested3', 'nested4']);
|
||||
expect(Object.keys(chunk.actions)).toEqual(['nested1', 'nested2', 'nested3', 'nested4', 'nested5']);
|
||||
});
|
||||
it('Actions object has the correct top level structure for a non nested chunk', () => {
|
||||
expect(Object.keys(nonNestedChunk.actions)).toEqual(['replace', 'reset']);
|
||||
|
@ -97,6 +100,14 @@ describe('buildStoreChunk', () => {
|
|||
store.dispatch(chunk.actions.nested1.reset());
|
||||
expect(chunk.selectors.nested1(store.getState())).toEqual('foo');
|
||||
});
|
||||
|
||||
it('Dispatching an empty array property should replace existing array', () => {
|
||||
store.dispatch(chunk.actions.nested5.replace({ arrayExample: ['2'] }));
|
||||
store.dispatch(chunk.actions.nested5.update({ arrayExample: [] }));
|
||||
expect(chunk.selectors.nested5(store.getState())).toEqual({
|
||||
arrayExample: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Combined actions and selectors (non nested chunk)', () => {
|
||||
|
|
|
@ -65,7 +65,10 @@ describe('Validation functionality', () => {
|
|||
});
|
||||
it('Array should return an empty array if a non-array is passed', () => {
|
||||
expect(validateArray('foo')).toEqual([]);
|
||||
})
|
||||
});
|
||||
it('Array should allow an empty array', () => {
|
||||
expect(validateArray([])).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Objects', () => {
|
||||
|
@ -138,6 +141,16 @@ describe('Validation functionality', () => {
|
|||
test2: 'bar',
|
||||
});
|
||||
});
|
||||
|
||||
const testObjectStructure7 = Types.shape({
|
||||
test1: Types.arrayOf(Types.string()),
|
||||
});
|
||||
it('Should allow an empty array to be passed for an array property', () => {
|
||||
expect(validateShape(testObjectStructure7, { test1: [] })).toEqual({
|
||||
test1: [],
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Non covered types', () => {
|
||||
|
|
|
@ -40,7 +40,6 @@ export type ShapeReducerOptions = {
|
|||
//==============================
|
||||
import isObject from 'lodash/isObject';
|
||||
import omit from 'lodash/omit';
|
||||
import merge from 'lodash/fp/merge';
|
||||
import { validateShape } from '../validatePayload';
|
||||
import { createReducerBehaviors } from '../reducers';
|
||||
import { PROP_TYPES } from '../structure';
|
||||
|
@ -119,16 +118,16 @@ export function createReducer(objectStructure: StructureType, behaviors: ShapeRe
|
|||
if (matchedBehaviors.length) {
|
||||
//Sanitize the payload using the reducer shape, then apply the sanitized
|
||||
//payload to the state using the behavior linked to this action type.
|
||||
return reduce((interimState, matchedBehavior) => merge(
|
||||
return reduce((interimState, matchedBehavior) => ({
|
||||
...interimState,
|
||||
...behaviors[matchedBehavior.type].reducer(
|
||||
interimState,
|
||||
behaviors[matchedBehavior.type].reducer(
|
||||
interimState,
|
||||
behaviors[matchedBehavior.type].validate
|
||||
? validateShape(objectStructure, matchedBehavior.payload)
|
||||
: matchedBehavior.payload,
|
||||
initialState
|
||||
)
|
||||
), state)(matchedBehaviors);
|
||||
behaviors[matchedBehavior.type].validate
|
||||
? validateShape(objectStructure, matchedBehavior.payload)
|
||||
: matchedBehavior.payload,
|
||||
initialState
|
||||
)
|
||||
}), state)(matchedBehaviors);
|
||||
}
|
||||
|
||||
return state;
|
||||
|
|
|
@ -45,6 +45,7 @@ export function validateShape(objectStructure: any, value: mixed): Object {
|
|||
}
|
||||
|
||||
const validatedValue = getTypeValidation(valueType().type)(valueType, value);
|
||||
|
||||
if (validatedValue === undefined) {
|
||||
console.warn(`The property, ${name}, was populated with a type ${ typeof value } which does not` +
|
||||
` match that specified in the reducer configuration ${ wildcardKeyPresent ? ', nor did it match a wildcardKey': ''}. It has been stripped from` +
|
||||
|
|
Loading…
Reference in New Issue