From 27fe29a076553c26e2c56dccaf52d2af789eae3a Mon Sep 17 00:00:00 2001 From: andrzejszukuc Date: Thu, 14 Feb 2019 13:38:12 +0100 Subject: [PATCH] Integration tests for MainScreenWrapperReducer Change-Id: I7e947ea2ccab8877a3b8bb01d8e6b999bee1901f Issue-ID: AAI-2143 Signed-off-by: Andrzej Szukuc --- package.json | 7 +- src/app/MainScreenWrapperActionHelper.js | 14 +- src/app/contextHandler/ContextHandlerActions.js | 22 +- src/app/personlaization/PersonalizationActions.js | 6 +- test/MainScreenWrapperReducer.test.js | 486 ++++++++++++++++++++++ 5 files changed, 502 insertions(+), 33 deletions(-) create mode 100644 test/MainScreenWrapperReducer.test.js diff --git a/package.json b/package.json index 7402e2b..2b8334a 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "isparta-loader": "^2.0.0", "istanbul": "^1.0.0-alpha.2", "istanbul-instrumenter-loader": "^0.2.0", - "jest": "^22.4.3", + "jest": "^23.0.1", "jest-enzyme": "^6.0.0", "jest-fetch-mock": "^1.5.0", "json-loader": "^0.5.4", @@ -99,14 +99,15 @@ "prompt": "^0.2.14", "react-addons-test-utils": "^15.1.0", "react-hot-loader": "^3.0.0-beta.6", - "redux-mock-store": "^1.4.0", + "redux-mock-store": "^1.5.3", "sass-loader": "^3.1.2", "source-map-loader": "^0.1.5", "style-loader": "^0.13.1", "url-loader": "^0.5.7", "webpack": "^1.13.1", "webpack-bundle-analyzer": "^3.0.3", - "webpack-dev-server": "^1.14.1" + "webpack-dev-server": "^1.14.1", + "randomstring": "^1.1.5" }, "jest": { "verbose": true, diff --git a/src/app/MainScreenWrapperActionHelper.js b/src/app/MainScreenWrapperActionHelper.js index dd7450b..3477b03 100644 --- a/src/app/MainScreenWrapperActionHelper.js +++ b/src/app/MainScreenWrapperActionHelper.js @@ -74,8 +74,7 @@ function createOverlayDataFoundEvent(overlayData, paramName, curData, responseEv } function overlayViewData(dataFetchRequest, paramName, curData, responseEventKey) { - return dispatch => { - dataFetchRequest().then( + return dispatch => dataFetchRequest().then( (response) => { return response.json(); } @@ -87,8 +86,7 @@ function overlayViewData(dataFetchRequest, paramName, curData, responseEventKey) dispatch(getSetGlobalMessageEvent(ERROR_RETRIEVING_DATA, MESSAGE_LEVEL_DANGER)); dispatch(createOverlayDataFoundEvent({}, paramName, curData, responseEventKey)); }); - }; -} +}; export function overlayNetworkCallback(urlApi, postBody, paramName, curData, responseEventKey) { let dataFetchRequest = @@ -113,8 +111,7 @@ function createViewDataFoundEvent(viewData, paramName, curViewData) { } function extensibleViewData(dataFetchRequest, paramName, curViewData) { - return dispatch => { - return dataFetchRequest().then( + return dispatch => dataFetchRequest().then( (response) => { return response.json(); } @@ -127,7 +124,6 @@ function extensibleViewData(dataFetchRequest, paramName, curViewData) { dispatch(createViewDataFoundEvent({}, paramName, curViewData)); //To-do: If need to send a flag later on to the view, add a function to have the flag }); - }; } export function extensibleViewNetworkCallback(urlApi, postBody, paramName, curViewData) { @@ -136,9 +132,7 @@ export function extensibleViewNetworkCallback(urlApi, postBody, paramName, curVi () => fetchRequestObj(BASE_URL + urlApi, POST, POST_HEADER, postBody); - return dispatch => { - dispatch(extensibleViewData(dataFetchRequest, paramName, curViewData)); - }; + return dispatch => dispatch(extensibleViewData(dataFetchRequest, paramName, curViewData)); } export function extensibleViewMessageCallback(msgText, msgSeverity) { diff --git a/src/app/contextHandler/ContextHandlerActions.js b/src/app/contextHandler/ContextHandlerActions.js index f3ede6d..35091b5 100644 --- a/src/app/contextHandler/ContextHandlerActions.js +++ b/src/app/contextHandler/ContextHandlerActions.js @@ -81,8 +81,7 @@ function createSubscriptionPayloadEvent(payload) { } function fetchSubscriptionPayload(fetchRequestCallback) { - return dispatch => { - return fetchRequestCallback().then( + return dispatch => fetchRequestCallback().then( (response) => { if (response.status >= STATUS_CODE_3XX_REDIRECTION) { return Promise.reject(new Error(response.status)); @@ -100,16 +99,13 @@ function fetchSubscriptionPayload(fetchRequestCallback) { dispatch(getSetGlobalMessageEvent(SUBSCRIPTION_FAILED_MESSAGE , MESSAGE_LEVEL_WARNING)); } ); - }; } export function getSubscriptionPayload() { let externalfetchRequest = () => networkCall.getRequest(SUBSCRIPTION_PAYLOAD_URL, GET); - return dispatch => { - dispatch(fetchSubscriptionPayload(externalfetchRequest)); - }; + return dispatch => dispatch(fetchSubscriptionPayload(externalfetchRequest)); } function validateExternalParams(externalURLParams) { @@ -129,8 +125,8 @@ function createSuggestionFoundEvent(suggestion) { function fetchDataForExternalRequest(fetchRequestCallback) { - return dispatch => { - return fetchRequestCallback().then( + return dispatch => + fetchRequestCallback().then( (response) => { if (response.status === STATUS_CODE_204_NO_CONTENT || response.status >= STATUS_CODE_3XX_REDIRECTION) { return Promise.reject(new Error(response.status)); @@ -158,7 +154,6 @@ function fetchDataForExternalRequest(fetchRequestCallback) { dispatch(getSetGlobalMessageEvent(FAILED_REQUEST , MESSAGE_LEVEL_DANGER)); } ); - }; } function validateAndFetchExternalParams(externalParams) { @@ -172,17 +167,12 @@ function validateAndFetchExternalParams(externalParams) { let externalfetchRequest = () => networkCall.fetchRequestObj(EXTERNAL_REQ_ENTITY_SEARCH_URL, POST, POST_HEADER, postBody); - return dispatch => { - dispatch(fetchDataForExternalRequest(externalfetchRequest)); - }; + return dispatch => dispatch(fetchDataForExternalRequest(externalfetchRequest)); } } export function externalUrlRequest(urlParams) { let externalURLParams = getExternalParamValues(urlParams); - return dispatch => { - dispatch( - validateAndFetchExternalParams(externalURLParams)); - }; + return dispatch => dispatch(validateAndFetchExternalParams(externalURLParams)); } export function externalMessageRequest(jsonParams) { return dispatch => { diff --git a/src/app/personlaization/PersonalizationActions.js b/src/app/personlaization/PersonalizationActions.js index b10d85f..bdf54ca 100644 --- a/src/app/personlaization/PersonalizationActions.js +++ b/src/app/personlaization/PersonalizationActions.js @@ -74,7 +74,5 @@ export function getPersonalizationDetails(){ let personalizationFetchRequest = () => networkCall.getRequest(GET_PERSONALIZED_VALUES_URL, GET); - return dispatch => { - dispatch(fetchPersonalizedValues(personalizationFetchRequest)); - }; -} \ No newline at end of file + return dispatch => dispatch(fetchPersonalizedValues(personalizationFetchRequest)); +} diff --git a/test/MainScreenWrapperReducer.test.js b/test/MainScreenWrapperReducer.test.js new file mode 100644 index 0000000..e9324cc --- /dev/null +++ b/test/MainScreenWrapperReducer.test.js @@ -0,0 +1,486 @@ +import thunk from 'redux-thunk'; +import randstr from 'randomstring'; +import configureMockStore from 'redux-mock-store'; + +import MainScreenWrapperReducer from 'app/MainScreenWrapperReducer' +import {aaiActionTypes} from 'app/MainScreenWrapperConstants'; +import {getPersonalizationDetails} from 'app/personlaization/PersonalizationActions'; +import {getInvalidSearchInputEvent} from'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarActions'; +import {extensibleViewNetworkCallback, showMainMenu, clearExtensibleViewData, setSecondaryTitle} from 'app/MainScreenWrapperActionHelper'; +import {externalUrlRequest, getSubscriptionPayload} from 'app/contextHandler/ContextHandlerActions' + +import {globalInlineMessageBarActionTypes} from "app/globalInlineMessageBar/GlobalInlineMessageBarConstants"; +import {globalAutoCompleteSearchBarActionTypes} from "app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarConstants"; +import { + contextHandlerActionTypes, + FAILED_REQUEST, + MULTIPLE_RESULT, SUBSCRIPTION_FAILED_MESSAGE, + WRONG_EXTERNAL_REQUEST_MESSAGE, + WRONG_RESULT, + ZERO_RESULT +} from "app/contextHandler/ContextHandlerConstants"; +import {PERSONALIZATION_FAILED_MESSAGE, personalizationActionTypes} from "app/personlaization/PersonalizationConstans"; + +describe('MainScreenWrapperReducerTests', () => { + fetch = require('jest-fetch-mock'); + const mockStore = configureMockStore([thunk])(); + const initialState = {Baz : 'Fooo'}; + const error = '401'; + + beforeEach(() => { + fetch.resetMocks(); + mockStore.clearActions(); + }); + + describe('extensibleViewNetworkCallbackTests', () => { + const paramName = 'boo'; + const postBody = 'baz'; + const curView = {Boz : 'Fooz'}; + const requestUrl = 'www.foo.com'; + const response = {Foo: 'Bar'}; + + describe('success tests', () => { + beforeEach(async () => { + //given + fetch.once(JSON.stringify(response)); + await mockStore.dispatch(extensibleViewNetworkCallback(requestUrl, postBody, paramName, curView)); + }); + + it('action on success test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(aaiActionTypes.EXTENSIBLE_VIEW_NETWORK_CALLBACK_RESPONSE_RECEIVED); + }); + + it('reducer on success test', () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const { + extensibleViewNetworkCallbackData, + ...rest + } = MainScreenWrapperReducer(initialState, action); + + //then + expect(rest).toEqual(initialState); + expect(extensibleViewNetworkCallbackData).toEqual({ + boo: response, + ...curView + }); + }); + }); + + describe('failure tests', () => { + beforeEach(async () => { + //given + fetch.mockRejectOnce(error); + await mockStore.dispatch(extensibleViewNetworkCallback(requestUrl, postBody, paramName, curView)); + }); + + it('action on failure test', () => { + //given + const [firstAction, secondAction, ...tail] = mockStore.getActions(); + + //then + expect(tail).toEqual([]); + expect(firstAction.type).toEqual(globalInlineMessageBarActionTypes.SET_GLOBAL_MESSAGE); + expect(secondAction.type).toEqual(aaiActionTypes.EXTENSIBLE_VIEW_NETWORK_CALLBACK_RESPONSE_RECEIVED); + }); + + it('reducer on failure test', () => { + //given + const [firstAction, secondAction, ..._] = mockStore.getActions(); + + //when + const afterFirstState = MainScreenWrapperReducer(initialState, firstAction); + const { + extensibleViewNetworkCallbackData, + ...rest + } = MainScreenWrapperReducer(initialState, secondAction); + + //then + expect(afterFirstState).toEqual(initialState); + expect(rest).toEqual(initialState); + expect(extensibleViewNetworkCallbackData).toEqual({ + boo: {}, + ...curView + }); + }); + }); + }); + + describe.each([true, false])('showMainMenuTests', value => { + beforeEach(async () => { + //given + await mockStore.dispatch(showMainMenu(value)); + }); + + it('action on show: ' + value + ' test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(aaiActionTypes.AAI_SHOW_MENU); + }); + + it('reducer on show: ' + value + ' test', () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const { + showMenu, + toggleButtonActive, + ...rest + } = MainScreenWrapperReducer(initialState, action); + + //then + expect(rest).toEqual(initialState); + expect(showMenu).toBe(value); + expect(toggleButtonActive).toBe(value); + }); + }); + + describe('clearExtensibleViewDataTests', () => { + beforeEach(async () => { + //given + await mockStore.dispatch(clearExtensibleViewData()); + }); + + it('action test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(aaiActionTypes.EXTENSIBLE_VIEW_NETWORK_CALLBACK_CLEAR_DATA); + }); + + it('reducer test', () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const { + extensibleViewNetworkCallbackData, + ...rest + } = MainScreenWrapperReducer(initialState, action); + + expect(rest).toEqual(initialState); + expect(extensibleViewNetworkCallbackData).toEqual({}); + }); + }); + + describe('getInvalidSearchInputEventTests', () => { + const msg = randstr.generate(); + + beforeEach(async () => { + await mockStore.dispatch(getInvalidSearchInputEvent(msg)); + }); + + it('action msg: ' + msg + ' test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(globalAutoCompleteSearchBarActionTypes.SEARCH_WARNING_EVENT); + }); + + it('reducer msg: ' + msg + ' test', () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const { + extensibleViewNetworkCallbackData, + ...rest + } = MainScreenWrapperReducer(initialState, action); + + //then + expect(rest).toEqual(initialState); + expect(extensibleViewNetworkCallbackData).toEqual({clearView : true}); + }); + }); + + describe('externalUrlRequestTests', () => { + const someUrlParams = 'view=A&entityId=B&entityType=C'; + + describe.each([{ + title: 'on empty url params', + prepareMock: () => {}, + urlParams: '', + expectedResponse: WRONG_EXTERNAL_REQUEST_MESSAGE + }, { + title: 'on request rejected by the server', + prepareMock: () => fetch.mockRejectOnce('401'), + urlParams: someUrlParams, + expectedResponse: FAILED_REQUEST + }, { + title: 'on empty suggestions', + prepareMock: () => fetch.once(JSON.stringify({})), + urlParams: someUrlParams, + expectedResponse: WRONG_RESULT + }, { + title: 'on no results', + prepareMock: () => fetch.once(JSON.stringify({totalFound: 0, suggestions: []})), + urlParams: someUrlParams, + expectedResponse: ZERO_RESULT + }, { + title: 'on multiple results', + prepareMock: () => fetch.once(JSON.stringify({totalFound: 2, suggestions: ['Foo', 'Bar']})), + urlParams: someUrlParams, + expectedResponse: MULTIPLE_RESULT + }])('failure tests', ({title, prepareMock, urlParams, expectedResponse}) => { + beforeEach(async () => { + //given + prepareMock(); + await mockStore.dispatch(externalUrlRequest(urlParams)); + }); + + it('action ' + title + ' test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(globalInlineMessageBarActionTypes.SET_GLOBAL_MESSAGE); + expect(action.data.msgText).toEqual(expectedResponse); + }); + + it('reducer ' + title + ' test', () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const state = MainScreenWrapperReducer(initialState, action); + + //then + expect(state).toEqual(initialState); + }); + }); + + describe("success tests", () => { + //given + const response = {totalFound: 1, suggestions: ['Foo']}; + + beforeEach(async () => { + //given + fetch.resetMocks(); + fetch.once(JSON.stringify(response)); + + await mockStore.dispatch(externalUrlRequest(someUrlParams)); + }); + + it('action on exactly one suggestion test', () => { + //when + const [firstAction, secondAction, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(firstAction.type).toBe( globalInlineMessageBarActionTypes.CLEAR_GLOBAL_MESSAGE); + expect(secondAction.type).toBe(contextHandlerActionTypes.SINGLE_SUGGESTION_FOUND); + }); + + it('reducer on exactly one suggestion test', () => { + //given + const [firstAction, secondAction, ..._] = mockStore.getActions(); + + //when + const state = MainScreenWrapperReducer(initialState, firstAction); + const { + externalRequestFound, + ...rest + } = MainScreenWrapperReducer(state, secondAction); + + //then + expect(state).toEqual(initialState); + expect(rest).toEqual(initialState); + expect(externalRequestFound).toEqual({suggestion: response.suggestions[0]}); + }); + }); + }); + + describe('setSecondaryTitleTests', () => { + //given + const title = randstr.generate(); + + beforeEach(async () => { + //given + await mockStore.dispatch(setSecondaryTitle(title)); + }); + + it('action test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(aaiActionTypes.SET_SECONDARY_TITLE); + }); + + it('reducer test', () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const { + secondaryTitle, + ...rest + } = MainScreenWrapperReducer(initialState, action); + + //then + expect(rest).toEqual(initialState); + expect(secondaryTitle).toEqual(title); + }); + }); + + describe('getSubscriptionPayloadTests', () => { + describe('failure tests', () => { + beforeEach(async () => { + //given + fetch.mockRejectOnce(error); + await mockStore.dispatch(getSubscriptionPayload()); + }); + + it('action on request rejected by server test', async () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(globalInlineMessageBarActionTypes.SET_GLOBAL_MESSAGE); + expect(action.data.msgText).toEqual(SUBSCRIPTION_FAILED_MESSAGE); + }); + + it('reducer on request rejected by server test', async () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const state = MainScreenWrapperReducer(initialState, action); + + //then + expect(state).toEqual(initialState); + }); + }); + + const subscriptionData = 'Foo'; + + describe.each([{ + title: 'on disabled subscription', + payload: {subscriptionEnabled: false}, + type: contextHandlerActionTypes.SUBSCRIPTION_PAYLOAD_EMPTY, + detail : undefined + }, { + title: 'on enabled subscription', + payload: {subscriptionEnabled: true, subscriptionDetails: subscriptionData}, + type: contextHandlerActionTypes.SUBSCRIPTION_PAYLOAD_FOUND, + detail : subscriptionData + }])('success tests', ({title, payload, type, detail}) => { + beforeEach(async () => { + //given + fetch.once(JSON.stringify(payload)); + await mockStore.dispatch(getSubscriptionPayload()); + }); + + it('action ' + title + ' test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(type); + }); + + it('reducer ' + title + ' test', () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const { + subscriptionEnabled, + subscriptionPayload, + ...rest + } = MainScreenWrapperReducer(initialState, action); + + //then + expect(rest).toEqual(initialState); + expect(subscriptionEnabled).toBe(payload.subscriptionEnabled); + expect(subscriptionPayload).toEqual(detail); + }); + }); + }); + + describe("getPersonalizationDetailsTests", () => { + describe('failure tests', () => { + beforeEach(async () => { + //given + fetch.mockRejectOnce(error); + await mockStore.dispatch(getPersonalizationDetails()); + }); + + it('action on request rejected by server test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(globalInlineMessageBarActionTypes.SET_GLOBAL_MESSAGE); + expect(action.data.msgText).toEqual(PERSONALIZATION_FAILED_MESSAGE); + }); + + it('reducer on request rejected by server test', () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const state = MainScreenWrapperReducer(initialState, action); + + //then + expect(state).toEqual(initialState); + }); + }); + + describe('success tests', () => { + const personalizationPayload = {topLeftHeader: 'Foo', htmlDocumentTitle: 'Bar'}; + + beforeEach(async () => { + //given + fetch.once(JSON.stringify(personalizationPayload)); + await mockStore.dispatch(getPersonalizationDetails()); + }); + + it('action on personalization payload found test', () => { + //when + const [action, ...rest] = mockStore.getActions(); + + //then + expect(rest).toEqual([]); + expect(action.type).toBe(personalizationActionTypes.PERSONALIZATION_PAYLOAD_FOUND); + }); + + it("Reducer on personalization payload found test", async () => { + //given + const [action, ..._] = mockStore.getActions(); + + //when + const { + aaiTopLeftPersonalizedHeader, + aaiPersonalizedHtmlDocumentTitle, + ...rest + } = MainScreenWrapperReducer(initialState, action); + + //then + expect(rest).toEqual(initialState); + expect(aaiTopLeftPersonalizedHeader).toEqual(personalizationPayload.topLeftHeader); + expect(aaiPersonalizedHtmlDocumentTitle).toEqual(personalizationPayload.htmlDocumentTitle); + }); + }); + }); +}); -- 2.16.6