Action Keys

// action-keys.js
export const SET_NAME = 'SET_NAME';
export const SET_IS_LOADING = 'SET_IS_LOADING';
export const SET_CUSTOMER_EMAIL = 'SET_CUSTOMER_EMAIL';
export const SET_CUSTOMER_AGE = 'SET_CUSTOMER_AGE';
export const SET_CUSTOMER_INFO = 'SET_CUSTOMER_INFO';
export const SET_DATA = 'SET_DATA';
export const SET_FRIEND_NAMES = 'SET_FRIEND_NAMES';
export const ADD_FRIEND_NAME = 'ADD_FRIEND_NAME';
export const REMOVE_FRIEND_NAME = 'REMOVE_FRIEND_NAME';
export const SET_FRIEND_NAME = 'SET_FRIEND_NAME';
export const SET_CONNECTIONS = 'SET_CONNECTIONS';
export const ADD_CONNECTION = 'ADD_CONNECTION';
export const REMOVE_CONNECTION = 'REMOVE_CONNECTION';
export const SET_CONNECTION_TYPE = 'SET_CONNECTION_TYPE';
export const SET_CONNECTION_CON_MAN = 'SET_CONNECTION_CON_MAN';
export const SET_CONNECTION_CON_DATA = 'SET_CONNECTION_CON_DATA';

Action Creators

// actions.js
import * as actionKeys from './action-keys';
/**
* @param {string} name
*/
export const setName = name => ({
type: actionKeys.SET_NAME,
payload: name
});
/**
* @param {boolean} isLoading
*/
export const setIsLoading = isLoading => ({
type: actionKeys.SET_IS_LOADING,
payload: isLoading
});
/**
* @param {string} email
*/
export const setCustomerEmail = email => ({
type: actionKeys.SET_CUSTOMER_EMAIL,
payload: email
});
/**
* @param {number} age
*/
export const setCustomerAge = age => ({
type: actionKeys.SET_CUSTOMER_AGE,
payload: age
});
/**
* @param {any} info
*/
export const setCustomerInfo = info => ({
type: actionKeys.SET_CUSTOMER_INFO,
payload: info
});
/**
* @param {any} data
*/
export const setData = data => ({
type: actionKeys.SET_DATA,
payload: data
});
/**
* @param {string[]} friendNames
*/
export const setFriendNames = friendNames => ({
type: actionKeys.SET_FRIEND_NAMES,
payload: friendNames
});
/**
* @param {string} friendName
*/
export const addFriendName = friendName => ({
type: actionKeys.ADD_FRIEND_NAME,
payload: friendName
});
/**
* @param {number} index
*/
export const removeFriendName = index => ({
type: actionKeys.REMOVE_FRIEND_NAME,
payload: index
});
/**
* @param {number} index
* @param {string} friendName
*/
export const setFriendName = (index, friendName) => ({
type: actionKeys.SET_FRIEND_NAME,
payload: { index, friendName }
});
/**
* @param {Array} connections
*/
export const setConnections = connections => ({
type: actionKeys.SET_CONNECTIONS,
payload: connections
});
/**
* @param {any} connection
*/
export const addConnection = connection => ({
type: actionKeys.ADD_CONNECTION,
payload: connection
});
/**
* @param {number} index
*/
export const removeConnection = index => ({
type: actionKeys.REMOVE_CONNECTION,
payload: index
});
/**
* @param {number} index
* @param {string} type
*/
export const setConnectionType = (index, type) => ({
type: actionKeys.SET_CONNECTION_TYPE,
payload: { index, type }
});
/**
* @param {number} index
* @param {string} man
*/
export const setConnectionConMan = (index, man) => ({
type: actionKeys.SET_CONNECTION_CON_MAN,
payload: { index, man }
});
/**
* @param {number} index
* @param {any} data
*/
export const setConnectionConData = (index, data) => ({
type: actionKeys.SET_CONNECTION_CON_DATA,
payload: { index, data }
});

Reducer

// root-reducer.js
import * as actionKeys from './action-keys';
const DEFAULT_STATE = {
"name": "",
"isLoading": true,
"customer": {
"email": "",
"age": 21,
"info": null
},
"data": null,
"friendNames": [
""
],
"connections": [
{
"type": "colleague",
"con": {
"man": "Malcolm",
"data": null
}
}
]
};
export const rootReducer = (state = DEFAULT_STATE, action) => {
switch (action.type)
{
case actionKeys.SET_NAME:
return {
...state,
name: action.payload
}
case actionKeys.SET_IS_LOADING:
return {
...state,
isLoading: action.payload
}
case actionKeys.SET_CUSTOMER_EMAIL:
return {
...state,
customer: {
...state.customer,
email: action.payload
}
}
case actionKeys.SET_CUSTOMER_AGE:
return {
...state,
customer: {
...state.customer,
age: action.payload
}
}
case actionKeys.SET_CUSTOMER_INFO:
return {
...state,
customer: {
...state.customer,
info: action.payload
}
}
case actionKeys.SET_DATA:
return {
...state,
data: action.payload
}
case actionKeys.SET_FRIEND_NAMES:
return {
...state,
friendNames: action.payload
}
case actionKeys.ADD_FRIEND_NAME:
return {
...state,
friendNames: state.friendNames.concat(action.payload)
}
case actionKeys.REMOVE_FRIEND_NAME:
return {
...state,
friendNames: state.friendNames.filter((_, index) => index !== action.payload)
}
case actionKeys.SET_FRIEND_NAME:
return {
...state,
friendNames: state.friendNames.map((item, index) => index === action.payload.index ? action.payload.friendName : item)
}
case actionKeys.SET_CONNECTIONS:
return {
...state,
connections: action.payload
}
case actionKeys.ADD_CONNECTION:
return {
...state,
connections: state.connections.concat(action.payload)
}
case actionKeys.REMOVE_CONNECTION:
return {
...state,
connections: state.connections.filter((_, index) => index !== action.payload)
}
case actionKeys.SET_CONNECTION_TYPE:
return {
...state,
connections: state.connections.map((item, index) => index !== action.payload.index
? item
: {
...item,
type: action.payload.type
}
)
}
case actionKeys.SET_CONNECTION_CON_MAN:
return {
...state,
connections: state.connections.map((item, index) => index !== action.payload.index
? item
: {
...item,
con: {
...item.con,
man: action.payload.man
}
}
)
}
case actionKeys.SET_CONNECTION_CON_DATA:
return {
...state,
connections: state.connections.map((item, index) => index !== action.payload.index
? item
: {
...item,
con: {
...item.con,
data: action.payload.data
}
}
)
}
default:
return state;
}
}
export default rootReducer;

Selectors

// selectors.js
// get the state of this store
const selectState = state => state;
/**
* @returns {string}
*/
export const selectName = state => selectState(state).name;
/**
* @returns {boolean}
*/
export const selectIsLoading = state => selectState(state).isLoading;
/**
* @returns {string}
*/
export const selectCustomerEmail = state => selectState(state).customer.email;
/**
* @returns {number}
*/
export const selectCustomerAge = state => selectState(state).customer.age;
export const selectCustomerInfo = state => selectState(state).customer.info;
export const selectData = state => selectState(state).data;
/**
* @returns {string[]}
*/
export const selectFriendNames = state => selectState(state).friendNames;
/**
* @returns {string}
*/
export const selectFriendName = (state, index) => selectState(state).friendNames[index];
export const selectConnections = state => selectState(state).connections;
/**
* @returns {string}
*/
export const selectConnectionType = (state, index) => selectState(state).connections[index].type;
/**
* @returns {string}
*/
export const selectConnectionConMan = (state, index) => selectState(state).connections[index].con.man;
export const selectConnectionConData = (state, index) => selectState(state).connections[index].con.data;

Tests

// store.test.js
import * as actionCreators from './actions';
import rootReducer from './root-reducer';
import * as selectors from './selectors';
describe('rootReducer', () => {
const initialState = rootReducer(undefined, { type: '@@INIT' });
test('setName', () => {
const action = actionCreators.setName('Noelia Hammes');
const finalState = rootReducer(initialState, action);
expect(selectors.selectName(finalState)).toEqual('Noelia Hammes')
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setIsLoading', () => {
const action = actionCreators.setIsLoading(true);
const finalState = rootReducer(initialState, action);
expect(selectors.selectIsLoading(finalState)).toEqual(true)
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setCustomerEmail', () => {
const action = actionCreators.setCustomerEmail('Luciano_Stamm@yahoo.com');
const finalState = rootReducer(initialState, action);
expect(selectors.selectCustomerEmail(finalState)).toEqual('Luciano_Stamm@yahoo.com')
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setCustomerAge', () => {
const action = actionCreators.setCustomerAge(41789);
const finalState = rootReducer(initialState, action);
expect(selectors.selectCustomerAge(finalState)).toEqual(41789)
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setCustomerInfo', () => {
const action = actionCreators.setCustomerInfo({}); // populate data?
const finalState = rootReducer(initialState, action);
expect(selectors.selectCustomerInfo(finalState)).toEqual({})
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setData', () => {
const action = actionCreators.setData({}); // populate data?
const finalState = rootReducer(initialState, action);
expect(selectors.selectData(finalState)).toEqual({})
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setFriendNames', () => {
const action = actionCreators.setFriendNames(['Wilhelmine Metz DVM']);
const finalState = rootReducer(initialState, action);
expect(selectors.selectFriendNames(finalState)).toEqual(['Wilhelmine Metz DVM'])
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('addFriendName', () => {
const action = actionCreators.addFriendName('Tressie Cremin');
const finalState = rootReducer(initialState, action);
expect(selectors.selectFriendNames(finalState)).toContainEqual('Tressie Cremin')
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('removeFriendName', () => {
const oriState = rootReducer(initialState, actionCreators.setFriendNames(['Wilhelmine Metz DVM', 'Tressie Cremin']))
const action = actionCreators.removeFriendName(0);
const finalState = rootReducer(oriState, action);
expect(selectors.selectFriendNames(finalState)).not.toContainEqual('Wilhelmine Metz DVM')
expect(selectors.selectFriendNames(finalState)).toContainEqual('Tressie Cremin')
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setFriendName', () => {
const oriState = { ...initialState };
const action = actionCreators.setFriendName(0, 'Cheyenne Kerluke');
const finalState = rootReducer(oriState, action);
expect(selectors.selectFriendName(finalState, 0)).toEqual('Cheyenne Kerluke')
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setConnections', () => {
const action = actionCreators.setConnections([{
type: '',
con: {
man: '',
data: {},
},
}]); // populate data?
const finalState = rootReducer(initialState, action);
expect(selectors.selectConnections(finalState)).toEqual([{
type: '',
con: {
man: '',
data: {},
},
}])
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('addConnection', () => {
const action = actionCreators.addConnection({
type: '',
con: {
man: '',
data: {},
},
}); // populate data?
const finalState = rootReducer(initialState, action);
expect(selectors.selectConnections(finalState)).toContainEqual({
type: '',
con: {
man: '',
data: {},
},
})
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('removeConnection', () => {
const oriState = rootReducer(initialState, actionCreators.setConnections([{
type: '',
con: {
man: '',
data: {},
},
}, {
type: '',
con: {
man: '',
data: {},
},
}]))
// populate data?
const action = actionCreators.removeConnection(0);
const finalState = rootReducer(oriState, action);
expect(selectors.selectConnections(finalState)).not.toContainEqual({
type: '',
con: {
man: '',
data: {},
},
})
expect(selectors.selectConnections(finalState)).toContainEqual({
type: '',
con: {
man: '',
data: {},
},
})
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setConnectionType', () => {
const oriState = { ...initialState };
const action = actionCreators.setConnectionType(0, '');
const finalState = rootReducer(oriState, action);
expect(selectors.selectConnectionType(finalState, 0)).toEqual('')
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setConnectionConMan', () => {
const oriState = { ...initialState };
const action = actionCreators.setConnectionConMan(0, '');
const finalState = rootReducer(oriState, action);
expect(selectors.selectConnectionConMan(finalState, 0)).toEqual('')
// assert new object is created
expect(finalState).not.toBe(initialState);
});
test('setConnectionConData', () => {
const oriState = { ...initialState };
const action = actionCreators.setConnectionConData(0, {});
const finalState = rootReducer(oriState, action);
expect(selectors.selectConnectionConData(finalState, 0)).toEqual({})
// assert new object is created
expect(finalState).not.toBe(initialState);
});
});