Skip to content
This repository has been archived by the owner on Feb 19, 2023. It is now read-only.

Commit

Permalink
feat(#104): added / improved test cases for main redux code
Browse files Browse the repository at this point in the history
  • Loading branch information
Andreas Gasser committed Apr 3, 2019
1 parent 1b0473d commit 39cd305
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 19 deletions.
55 changes: 49 additions & 6 deletions src/redux/__tests__/configureStore.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import thunkMiddleware from 'redux-thunk';
/* global testUtils */
import { compose } from 'redux';

import { createMiddleware as createErrorMiddleware } from '../../util/ErrorHandler';

import configureStore, { __testables__ } from '../configureStore'; //
import configureStore, { __testables__ } from '../configureStore';

import {
applicationMessageAdd,
applicationMessageShow,
} from '../application/message';

const {
getComposeEnhancers,
getEnhancers,
getMiddleware,
} = __testables__; //
getErrorOptions,
} = __testables__;

it('should create redux store', () => {
const { store } = configureStore();
Expand Down Expand Up @@ -83,3 +86,43 @@ describe('redux getEnhancers test suite', () => {
expect(getEnhancers()).toEqual([]);
});
});

describe('redux getErrorOptions test sutie', () => {
const mockstore = testUtils.createMockStore();

it('should return object with error middleware options', () => {
const options = getErrorOptions();
expect(options).toBeTruthy();

// check for attributes
const { logToUI } = options;
expect(logToUI).toBeInstanceOf(Function);
});

it('logToUI should fire "addMessage" redux action', () => {
const error = {
title: 'Error',
detail: 'Error detail',
};

const store = mockstore();
const { dispatch } = store;

const options = getErrorOptions();
const { logToUI } = options;

const expectedActions = [
applicationMessageAdd({
title: error.title,
text: JSON.stringify(error.detail),
showRefresh: true,
}),
applicationMessageShow(),
];

// fire action
logToUI(error, dispatch);

expect(store.getActions()).toEqual(expectedActions);
});
});
55 changes: 55 additions & 0 deletions src/redux/__tests__/rootReducer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import rootReducer from '../rootReducer';

import {
appIdle,
appReset,
__testables__ as applicationTestables,
} from '../application';
import {
__testables__ as authTestables
} from '../auth';

const { applicationDidLoad } = applicationTestables;
const { authSetToken } = authTestables;

describe('root reducer test suite', () => {
let mockedDateNow;

beforeAll(() => {
const now = Date.now();
mockedDateNow = jest.spyOn(Date, 'now').mockImplementation(() => now);
});

afterAll(() => {
mockedDateNow.restoreMock();
});

const firstLevelKeys = [
'appTime',
'application',
'auth',
'images',
'labels',
'faces',
'user',
];

it('should return root redux tree', () => {
const rootState = rootReducer(undefined, appIdle());
expect(Object.keys(rootState)).toEqual(firstLevelKeys);
});

it('should reset reducer data on APP_RESET', () => {
// fire some actions to reducer
const rootState1 = rootReducer(undefined, appIdle());
const rootState2 = rootReducer(rootState1, applicationDidLoad());
const rootState3 = rootReducer(rootState2, authSetToken('invalid token'));

// check for non empty redux state
expect(rootState3).not.toEqual(rootReducer(undefined, appIdle));

// fire reset and check again
expect(rootReducer(rootState3, appReset()))
.toEqual(rootState1);
});
});
4 changes: 4 additions & 0 deletions src/redux/application/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ const status = (state = AppStatus.INITIAL, action) => {
}
};

export const __testables__ = {
applicationWillLoad,
applicationDidLoad,
};

export default combineReducers({
status,
Expand Down
36 changes: 24 additions & 12 deletions src/redux/configureStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,19 @@ const getComposeEnhancers = () => {

const getEnhancers = () => [];

const getErrorOptions = () => ({
logToUI: (error, dispatch) => {
const message = {
title: error.title,
text: error.detail ? JSON.stringify(error.detail) : null,
showRefresh: true,
};
addMessage(message)(dispatch);
}
});

const configureStore = (initialState = {}) => {
// configure error middleware
const errorOptions = {
logToUI: (error, dispatch) => {
const message = {
title: error.title,
text: error.detail ? JSON.stringify(error.detail) : null,
showRefresh: true,
};
addMessage(message)(dispatch);
}
};
const errorOptions = getErrorOptions();
const errorMiddleware = createMiddleware(errorOptions);

const middleware = [
Expand All @@ -74,7 +75,13 @@ const configureStore = (initialState = {}) => {
* Not the best design but works for now, redo later on
* or in next project find different solution for that...
*/
onAuthError: (message) => store.dispatch(logOutUser(message)), //AUTH_LOG_OUT
/* istanbul ignore next */
onAuthError: (message) =>
/* istanbul ignore next */
store.dispatch(
/* istanbul ignore next */
logOutUser(message)
), //AUTH_LOG_OUT
}),
}),
errorMiddleware,
Expand All @@ -99,15 +106,19 @@ const configureStore = (initialState = {}) => {
store.subscribe(configureReactors(store, reactors));

// idle configuration
/* istanbul ignore next */
const idleDispatcher = () => {
/* istanbul ignore next */
store.dispatch({ type: APP_IDLE });
};

// debounce app idle all 30 seconds
/* istanbul ignore next */
const deBounced = debounce(() => {
// The requestAnimationFrame ensures it doesn't run when tab isn't active
// the requestIdleCallback makes sure the browser isn't busy with something
// else.
/* istanbul ignore next */
requestAnimationFrame(() => ric(idleDispatcher, { timeout: 500 }));
}, 30000);

Expand All @@ -131,6 +142,7 @@ export const __testables__ = { // eslint-disable-line no-underscore-dangle
getEnhancers,
getComposeEnhancers,
getPersistedReducer,
getErrorOptions,
};

export default configureStore;
7 changes: 6 additions & 1 deletion src/redux/rootReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import facesReducer from './faces';
import userReducer from './user';

const reducers = combineReducers({
appTime: Date.now,
/**
* Do not use Date.now as pointer to prevent
* jest mock issues (by using pointer jest mock cannot
* replace function call)
*/
appTime: () => Date.now(),
application: applicationReducer,
auth: authReducer,
images: imagesReducer,
Expand Down

0 comments on commit 39cd305

Please sign in to comment.