diff --git a/frontend/app_constants/HTTP_STATUS.js b/frontend/app_constants/HTTP_STATUS.js index 5d5ce0532e..e891bc0e42 100644 --- a/frontend/app_constants/HTTP_STATUS.js +++ b/frontend/app_constants/HTTP_STATUS.js @@ -1,3 +1,4 @@ export default { + INTERNAL_ERROR: /^50[0-5]$/, UNAUTHENTICATED: 401, }; diff --git a/frontend/redux/middlewares/redirect/index.js b/frontend/redux/middlewares/redirect/index.js new file mode 100644 index 0000000000..7e620dcd58 --- /dev/null +++ b/frontend/redux/middlewares/redirect/index.js @@ -0,0 +1,24 @@ +/* eslint-disable no-unused-vars */ +import { get } from 'lodash'; +import { push } from 'react-router-redux'; + +import APP_CONSTANTS from 'app_constants'; + +const { HTTP_STATUS, PATHS } = APP_CONSTANTS; + +const redirectMiddleware = store => next => (action) => { + const { type, payload } = action; + + if (type.endsWith('FAILURE')) { + const httpStatus = get(payload, 'errors.http_status'); + + if (HTTP_STATUS.INTERNAL_ERROR.test(httpStatus)) { + store.dispatch(push(PATHS.KOLIDE_500)); + } + } + + return next(action); +}; + +export default redirectMiddleware; + diff --git a/frontend/redux/middlewares/redirect/redirect.tests.js b/frontend/redux/middlewares/redirect/redirect.tests.js new file mode 100644 index 0000000000..8a6148aac4 --- /dev/null +++ b/frontend/redux/middlewares/redirect/redirect.tests.js @@ -0,0 +1,34 @@ +import expect from 'expect'; + +import { reduxMockStore } from 'test/helpers'; + +const errorAction = { + type: 'users_LOAD_FAILURE', + payload: { + errors: { + http_status: 500, + base: 'Something went wrong', + }, + }, +}; +const errorActionThunk = (dispatch) => { + dispatch(errorAction); + + return Promise.reject(); +}; + +describe('redirect - middleware', () => { + it('redirect to /500 when a 500 error message is dispatched', () => { + const mockStore = reduxMockStore(); + const expectedRedirectAction = { + type: '@@router/CALL_HISTORY_METHOD', + payload: { + args: ['/500'], + method: 'push', + }, + }; + + mockStore.dispatch(errorActionThunk); + expect(mockStore.getActions()).toInclude(expectedRedirectAction); + }); +}); diff --git a/frontend/redux/store.js b/frontend/redux/store.js index ed9a1f3c30..766b5fa145 100644 --- a/frontend/redux/store.js +++ b/frontend/redux/store.js @@ -5,6 +5,7 @@ import { routerMiddleware } from 'react-router-redux'; import thunkMiddleware from 'redux-thunk'; import authMiddleware from './middlewares/auth'; +import redirectMiddleware from './middlewares/redirect'; import reducers from './reducers'; const initialState = {}; @@ -13,6 +14,7 @@ const appliedMiddleware = applyMiddleware( thunkMiddleware, routerMiddleware(browserHistory), authMiddleware, + redirectMiddleware, loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAILURE'], }), diff --git a/frontend/router/paths.js b/frontend/router/paths.js index b5d8f7e875..9623cf7210 100644 --- a/frontend/router/paths.js +++ b/frontend/router/paths.js @@ -7,6 +7,7 @@ export default { }, FORGOT_PASSWORD: '/login/forgot', HOME: '/', + KOLIDE_500: '/500', LOGIN: '/login', LOGOUT: '/logout', MANAGE_HOSTS: '/hosts/manage', diff --git a/frontend/test/helpers.jsx b/frontend/test/helpers.jsx index ec6ef2b4cd..db71f8e5c4 100644 --- a/frontend/test/helpers.jsx +++ b/frontend/test/helpers.jsx @@ -6,13 +6,14 @@ import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import authMiddleware from 'redux/middlewares/auth'; +import redirectMiddleware from 'redux/middlewares/redirect'; export const fillInFormInput = (inputComponent, value) => { return inputComponent.simulate('change', { target: { value } }); }; export const reduxMockStore = (store = {}) => { - const middlewares = [thunk, authMiddleware]; + const middlewares = [thunk, authMiddleware, redirectMiddleware]; const mockStore = configureStore(middlewares); return mockStore(store);