Skip to content
This repository has been archived by the owner on Aug 16, 2019. It is now read-only.

Commit

Permalink
12 Fix bug deleting entities
Browse files Browse the repository at this point in the history
This commit:

* Fixes a bug in which entities deleted by the server were not deleted in state.

This happened when the server did not respond with the deleted entity’s ID, which is a likely scenario causing a bug in most cases.

To delete an entity, dispatch the `destroy` thunk action passing in the entity to delete as the parameter. The entity to delete must have an `id` key.
  • Loading branch information
mikestone14 committed Jun 1, 2018
1 parent fc7befc commit f20c0dd
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 17 deletions.
32 changes: 32 additions & 0 deletions src/base_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ class BaseConfig {
...this._genericActions(TYPES.DESTROY),
...this._genericActions(TYPES.LOAD),
...this._genericActions(TYPES.UPDATE),
destroy: this._destroyThunkAction(),
silentDestroy: this._destroyThunkAction({ silent: true }),
};
}

Expand Down Expand Up @@ -145,6 +147,36 @@ class BaseConfig {
}
}

_destroyThunkAction (options = {}) {
const { TYPES } = BaseConfig;

return (args) => {
return (dispatch) => {
if (!options.silent) {
dispatch(this._genericRequest(TYPES.DESTROY)());
}

return this.destroyFunc(args)
.then(() => {
const thunk = this._genericSuccess(TYPES.DESTROY);
const action = thunk(args);

dispatch(action);

return args;
})
.catch((response) => {
const thunk = this._genericFailure(TYPES.DESTROY);
const errorsObject = this.parseServerErrorsFunc(response);

dispatch(thunk(errorsObject));

throw errorsObject;
});
};
};
}

_genericActions (type) {
if (!type) {
throw new Error('generic action type is not defined');
Expand Down
2 changes: 1 addition & 1 deletion src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class ReduxEntityConfig extends BaseConfig {
loading: false,
errors: {},
data: {
...entitiesExceptID(state.data, payload.data),
...entitiesExceptID(state.data, payload.data.id),
},
};
}
Expand Down
4 changes: 2 additions & 2 deletions test/config.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('ReduxEntityConfig - class', () => {
createFailure: config._genericFailure('CREATE'),
createRequest: config._genericRequest('CREATE'),
createSuccess: config._genericSuccess('CREATE'),
destroy: config._genericThunkAction('DESTROY'),
destroy: config._destroyThunkAction('DESTROY'),
destroyFailure: config._genericFailure('DESTROY'),
destroyRequest: config._genericRequest('DESTROY'),
destroySuccess: config._genericSuccess('DESTROY'),
Expand All @@ -121,7 +121,7 @@ describe('ReduxEntityConfig - class', () => {
loadRequest: config._genericRequest('LOAD'),
loadSuccess: config._genericSuccess('LOAD'),
silentCreate: config._genericThunkAction('CREATE', { silent: true }),
silentDestroy: config._genericThunkAction('DESTROY', { silent: true }),
silentDestroy: config._destroyThunkAction('DESTROY', { silent: true }),
silentLoad: config._genericThunkAction('LOAD', { silent: true }),
silentLoadAll: config._genericThunkAction('LOAD_ALL', { silent: true }),
silentUpdate: config._genericThunkAction('UPDATE', { silent: true }),
Expand Down
2 changes: 1 addition & 1 deletion test/config_reducer.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe('ReduxEntityConfig - reducer', () => {

describe('successful action', () => {
it('removes the user from state', () => {
const destroySuccessAction = actions.destroySuccess(userStub.id);
const destroySuccessAction = actions.destroySuccess({ id: userStub.id });

const newState = reducer(state, destroySuccessAction);

Expand Down
34 changes: 21 additions & 13 deletions test/config_thunks.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,9 @@ const schemas = {
const userStub = stubs.users.valid;

const store = {
entities: {
invites: {
errors: {},
data: {},
loading: false,
},
users: {
errors: {},
data: {},
loading: false,
},
},
errors: {},
data: {},
loading: false,
};
const standardError = {
status: 422,
Expand Down Expand Up @@ -146,7 +137,10 @@ describe('ReduxEntityConfig - thunks', () => {
entityName: 'users',
schema: schemas.USERS,
});
const mockStore = reduxMockStore(store);
const mockStore = reduxMockStore({
...store,
data: { [userStub.id]: userStub },
});

it('calls the destroyFunc', () => {
const params = { id: 1 };
Expand All @@ -168,6 +162,20 @@ describe('ReduxEntityConfig - thunks', () => {
expect(dispatchedActionTypes).toNotInclude('users_DESTROY_FAILURE');
});
});

it('removes the entity from state', () => {
const promise = config.actions.destroy({ id: userStub.id });

return mockStore.dispatch(promise)
.then(() => {
const dispatchedActions = mockStore.getActions();
const destroySuccessAction = dispatchedActions.find(action => action.type === 'users_DESTROY_SUCCESS');
const state = mockStore.getState();

expect(destroySuccessAction.payload).toEqual({ data: { id: userStub.id } });
expect(config.reducer(state, destroySuccessAction)).toEqual(store);
});
});
});

describe('unsuccessful call', () => {
Expand Down

0 comments on commit f20c0dd

Please sign in to comment.