From 3c0aa552f9e4f1d436e79db0385c36babf6c81ae Mon Sep 17 00:00:00 2001 From: JUDIT GRESKOVITS Date: Mon, 21 Aug 2017 18:27:21 +0100 Subject: [PATCH] feat(cp-frontend): Add reducers and selectors unit tests --- packages/cp-frontend/src/state/reducers/ui.js | 4 +- packages/cp-frontend/src/state/selectors.js | 12 +- .../test/unit/state/reducers/ui.js | 106 +++++++ .../cp-frontend/test/unit/state/selectors.js | 270 ++++++++++++++++++ 4 files changed, 386 insertions(+), 6 deletions(-) create mode 100644 packages/cp-frontend/test/unit/state/reducers/ui.js create mode 100644 packages/cp-frontend/test/unit/state/selectors.js diff --git a/packages/cp-frontend/src/state/reducers/ui.js b/packages/cp-frontend/src/state/reducers/ui.js index 82dea020..06ac7d46 100644 --- a/packages/cp-frontend/src/state/reducers/ui.js +++ b/packages/cp-frontend/src/state/reducers/ui.js @@ -1,7 +1,7 @@ import { handleActions } from 'redux-actions'; import { toggleServicesQuickActions, toggleInstancesTooltip } from '@state/actions'; -const _toggleServicesQuickActions = (state, action) => { +export const _toggleServicesQuickActions = (state, action) => { const { position, service, show } = action.payload; const s = @@ -29,7 +29,7 @@ const _toggleServicesQuickActions = (state, action) => { }; }; -const _toggleInstancesTooltip = (state, action) => { +export const _toggleInstancesTooltip = (state, action) => { const { position, instance, show, type } = action.payload; const s = diff --git a/packages/cp-frontend/src/state/selectors.js b/packages/cp-frontend/src/state/selectors.js index 7d1015e9..23a2d3de 100644 --- a/packages/cp-frontend/src/state/selectors.js +++ b/packages/cp-frontend/src/state/selectors.js @@ -37,7 +37,7 @@ const serviceBySlug = serviceSlug => : null ); -const instancesByServiceId = serviceId => +/* const instancesByServiceId = serviceId => createSelector( [apollo], apollo => @@ -52,7 +52,7 @@ const instancesByServiceId = serviceId => return is; }, []) : null - ); + ); */ // Apollo gql utils // @@ -177,7 +177,11 @@ const processServicesForTopology = services => { export { deploymentGroupBySlug as deploymentGroupBySlugSelector, serviceBySlug as serviceBySlugSelector, + getInstanceStatuses, + getInstancesActive, + getInstancesHealthy, + getService, processServices, - processServicesForTopology, - instancesByServiceId + processServicesForTopology /* , + instancesByServiceId */ }; diff --git a/packages/cp-frontend/test/unit/state/reducers/ui.js b/packages/cp-frontend/test/unit/state/reducers/ui.js new file mode 100644 index 00000000..36b9726a --- /dev/null +++ b/packages/cp-frontend/test/unit/state/reducers/ui.js @@ -0,0 +1,106 @@ +import { + _toggleServicesQuickActions, + _toggleInstancesTooltip +} from '@state/reducers/ui'; +import state from '@state/state'; + +describe('ui reducer', () => { + + it('toggleServicesQuickActions shows correctly', () => { + const uiState = state.ui; + const expectedUiState = { + ...state.ui, + services: { + ...state.ui.services, + quickActions: { + show: true, + position: { + top: 10, + left: 10 + }, + service: { + id: 'service-id' + } + } + } + } + const action = { payload: { + show: true, + position: { + top: 10, + left: 10 + }, + service: { + id: 'service-id' + } + }}; + const result = _toggleServicesQuickActions(uiState, action); + expect(result).toEqual(expectedUiState); + }); + + it('toggleServicesQuickActions hides correctly', () => { + const uiState = state.ui; + const expectedUiState = { + ...state.ui, + services: { + ...state.ui.services, + quickActions: { + show: false + } + } + } + const action = { payload: { show: false }}; + const result = _toggleServicesQuickActions(uiState, action); + expect(result).toEqual(expectedUiState); + }); + + it('toggleInstancesTooltip shows correctly', () => { + const uiState = state.ui; + const expectedUiState = { + ...state.ui, + instances: { + ...state.ui.instances, + tooltip: { + show: true, + position: { + top: 10, + left: 10 + }, + instance: { + id: 'instance-id' + }, + type: 'healthy' + } + } + } + const action = { payload: { + show: true, + position: { + top: 10, + left: 10 + }, + instance: { + id: 'instance-id' + }, + type: 'healthy' + }}; + const result = _toggleInstancesTooltip(uiState, action); + expect(result).toEqual(expectedUiState); + }); + + it('toggleServicesQuickActions hides correctly', () => { + const uiState = state.ui; + const expectedUiState = { + ...state.ui, + instances: { + ...state.ui.instances, + tooltip: { + show: false + } + } + } + const action = { payload: { show: false }}; + const result = _toggleInstancesTooltip(uiState, action); + expect(result).toEqual(expectedUiState); + }); +}) diff --git a/packages/cp-frontend/test/unit/state/selectors.js b/packages/cp-frontend/test/unit/state/selectors.js new file mode 100644 index 00000000..31f9c2a2 --- /dev/null +++ b/packages/cp-frontend/test/unit/state/selectors.js @@ -0,0 +1,270 @@ +import { + deploymentGroupBySlugSelector, + serviceBySlugSelector, + getInstanceStatuses, + getInstancesActive, + getInstancesHealthy, + getService, + processServices, + processServicesForTopology +} from '@state/selectors'; + +describe('Redux selectors and Apollo helpers', () => { + + describe('getInstanceStatuses', () => { + + it('gathers instance statuses correctly', () => { + const service = { + instances: [ + { status: 'RUNNING' }, + { status: 'RUNNING' }, + { status: 'READY' }, + { status: 'RUNNING' }, + { status: 'INCOMPLETE' }, + { status: 'READY' }, + { status: 'OFFLINE' }, + { status: 'STOPPED' }, + { status: 'STOPPED' }, + { status: 'RUNNING' } + ] + }; + const expectedResult = [ + { status: 'RUNNING', count: 4 }, + { status: 'READY', count: 2 }, + { status: 'INCOMPLETE', count: 1 }, + { status: 'OFFLINE', count: 1 }, + { status: 'STOPPED', count: 2 } + ]; + const result = getInstanceStatuses(service); + expect(result).toEqual(expectedResult); + }); + + it('does not throw a hissy fit if there are no instances', () => { + const service = { + instances: [] + }; + const expectedResult = []; + const result = getInstanceStatuses(service); + expect(result).toEqual(expectedResult); + }); + }); + + describe('getInstancesActive', () => { + + it('returns true if all instances\' status is active', () => { + const statuses = [ + { status: 'RUNNING' }, + { status: 'READY' }, + { status: 'ACTIVE' }, + { status: 'RUNNING' } + ]; + const expectedResult = true; + const result = getInstancesActive(statuses); + expect(result).toEqual(expectedResult); + }); + + it('returns false if no instances\' status is active', () => { + const statuses = [ + { status: 'STOPPING' }, + { status: 'FAILED' }, + { status: 'UNKNOWN' }, + { status: 'STOPPED' } + ]; + const expectedResult = false; + const result = getInstancesActive(statuses); + expect(result).toEqual(expectedResult); + }); + + it('returns true if some instances\' status is active', () => { + const statuses = [ + { status: 'STOPPING' }, + { status: 'FAILED' }, + { status: 'ACTIVE' }, + { status: 'RUNNING' } + ]; + const expectedResult = true; + const result = getInstancesActive(statuses); + expect(result).toEqual(expectedResult); + }); + }); + + describe('getInstancesHealthy', () => { + + it('returns the number of healthy instances correctly', () => { + const instances = [ + { healthy: 'HEALTHY' }, + { healthy: 'UNHEALTHY' }, + { healthy: 'MAINTENANCE' }, + { healthy: 'UNKNOWN' }, + { healthy: 'UNAVAILABLE' }, + { healthy: 'HEALTHY' } + ]; + const expectedResult = { total: 6, healthy: 2 }; + const result = getInstancesHealthy(instances); + expect(result).toEqual(expectedResult); + }); + }); + + describe('getService', () => { + + it('returns the service decorated with details for display correctly', () => { + + const result = getService(nginxService, 0); + expect(result).toEqual(nginxExpectedResult); + }); + + it('returns the consul service decorated with details for display correctly', () => { + + const result = getService(consulService, 1); + expect(result).toEqual(consulExpectedResult); + }); + }); + + describe('processServices', () => { + + it('returns the services decorated with details for display correctly', () => { + const services = [ + nginxService, + consulService + ]; + const expectedResult = [ + nginxExpectedResult, + consulExpectedResult + ]; + const result = processServices(services); + expect(result).toEqual(expectedResult); + }); + + it('removes deleted services', () => { + const services = [{ + status: 'DELETED' + }]; + const expectedResult = []; + const result = processServices(services); + expect(result).toEqual(expectedResult); + }); + }); + + describe('processServicesForTopology', () => { + + it('returns the services decorated with details for display correctly', () => { + const services = [ + { + ...nginxService, + id: 'nginx-service-0', + connections: [ + 'consul-service-0', + 'consul-service-1' + ] + }, + { + ...nginxService, + id: 'nginx-service-1' + }, + { + ...consulService, + id: 'consul-service-0', + connections: [ + 'consul-service-1' + ] + }, + { + ...consulService, + id: 'consul-service-1' + } + ]; + const expectedResult = [ + { + ...nginxExpectedResult, + id: 'nginx-service-0', + connections: [ + 'consul-service-0', + 'consul-service-1' + ], + connected: true, + index: 0 + }, + { + ...nginxExpectedResult, + id: 'nginx-service-1', + connected: false, + index: 1 + }, + { + ...consulExpectedResult, + id: 'consul-service-0', + connections: [ + 'consul-service-1' + ], + connected: true, + index: 2 + }, + { + ...consulExpectedResult, + id: 'consul-service-1', + connected: true, + index: 3 + } + ]; + const result = processServicesForTopology(services); + expect(result).toEqual(expectedResult); + }); + }); +}); + +const nginxService = { + instances: [ + { status: 'RUNNING', healthy: 'HEALTHY' }, + { status: 'RUNNING', healthy: 'HEALTHY' }, + { status: 'READY', healthy: 'HEALTHY' }, + { status: 'RUNNING', healthy: 'UNHEALTHY' }, + { status: 'INCOMPLETE', healthy: 'UNKNOWN' }, + { status: 'READY', healthy: 'HEALTHY' }, + { status: 'OFFLINE', healthy: 'UNAVAILABLE' }, + { status: 'STOPPED', healthy: 'UNAVAILABLE' }, + { status: 'STOPPED', healthy: 'UNAVAILABLE' }, + { status: 'RUNNING', healthy: 'HEALTHY' } + ], + status: 'ACTIVE', + slug: 'nginx' +}; + +const nginxExpectedResult = { + ...nginxService, + instanceStatuses: [ + { status: 'RUNNING', count: 4 }, + { status: 'READY', count: 2 }, + { status: 'INCOMPLETE', count: 1 }, + { status: 'OFFLINE', count: 1 }, + { status: 'STOPPED', count: 2 } + ], + instancesActive: true, + instancesHealthy: { total: 10, healthy: 5 }, + transitionalStatus: false, + isConsul: false, + index: 0 +}; + +const consulService = { + instances: [ + { status: 'RUNNING', healthy: 'HEALTHY' }, + { status: 'READY', healthy: 'HEALTHY' }, + { status: 'PROVISIONING', healthy: 'UNKNOWN' } + ], + status: 'PROVISIONING', + slug: 'consul' +}; + +const consulExpectedResult = { + ...consulService, + instanceStatuses: [ + { status: 'RUNNING', count: 1 }, + { status: 'READY', count: 1 }, + { status: 'PROVISIONING', count: 1 } + ], + instancesActive: true, + instancesHealthy: { total: 3, healthy: 2 }, + transitionalStatus: true, + isConsul: true, + index: 1 +};