From ffebba8652894128df9f0c17a761678ea4679b2b Mon Sep 17 00:00:00 2001 From: Katie Date: Wed, 7 Sep 2022 16:48:08 -0400 Subject: [PATCH 1/4] Update tests for estimate --- src/layouts/estimate/estimate.spec.js | 125 ++++++++++++++++++++------ 1 file changed, 96 insertions(+), 29 deletions(-) diff --git a/src/layouts/estimate/estimate.spec.js b/src/layouts/estimate/estimate.spec.js index a24bc22b7..271e2fda5 100644 --- a/src/layouts/estimate/estimate.spec.js +++ b/src/layouts/estimate/estimate.spec.js @@ -42,7 +42,7 @@ describe("estimate.vue", () => { const { wrapper } = setupMocks({}); //Act - store.commit( storeMutations.UPDATE_IS_REPAIR, true ); + store.commit(storeMutations.UPDATE_IS_REPAIR, true); let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); @@ -55,29 +55,13 @@ describe("estimate.vue", () => { const { wrapper } = setupMocks({}); //Act - store.commit( storeMutations.UPDATE_IS_REPAIR, true ); + store.commit(storeMutations.UPDATE_IS_REPAIR, true); let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); //Assert expect(arePagePrerequisitesValid).toBe(true); }); - test.todo("isRepair is false and there are no lineItems => should return false") - test.todo("isRepair is false and lineItems is null => should return false") - test.todo("isRepair is false are there are lineItems => should return true") - test("isRepair is set to null, arePagePrerequisitesValid should return false", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - store.commit( storeMutations.UPDATE_IS_REPAIR, null ); - - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - - //Assert - expect(arePagePrerequisitesValid).toBe(false); - }); test("After selecting provide my home address on ForwardButtonAction triggers a router.navigateWithSaving", async () => { @@ -132,20 +116,103 @@ describe("estimate.vue", () => { test("Provide my license plate on ForwardButtonAction triggers a router.navigateWithSaving", async () => { - //Arrange - const { wrapper } = setupMocks({}); - await wrapper.setData({ - selectedVinLookupMethod: vinLookupMethodSelections.LICENSEPLATE - }) - - //Act - wrapper.vm.forwardButtonAction(); - - //Assert - expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); + //Arrange + const { wrapper } = setupMocks({}); + await wrapper.setData({ + selectedVinLookupMethod: vinLookupMethodSelections.LICENSEPLATE + }) + + //Act + wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); }); + describe("arePagePrerequisitesValid", () => { + beforeEach(() => { + store.commit(storeMutations.UPDATE_IS_REPAIR, false); + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, null); + }) + + test("isRepair is false and there are no glassToReplace => should return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_IS_REPAIR, false); + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []); + + // Act + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(arePagePrerequisitesValid).toBe(false); + }) + + test("isRepair is false and glassToReplace is null => should return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_IS_REPAIR, false); + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, null); + + // Act + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(arePagePrerequisitesValid).toBe(false); + }) + + test("isRepair is false are there is one glassToReplace => should return true", () => { + // Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_IS_REPAIR, false); + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, [{glassLocation: "TEST", glassName: "NAME"}]); + + // Act + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(arePagePrerequisitesValid).toBe(true); + }) + + test("isRepair is false are there are multiple glassToReplace => should return true", () => { + // Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_IS_REPAIR, false); + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, [{glassLocation: "TEST1", glassName: "NAME1"}, {glassLocation: "TEST2", glassName: "NAME2"}, {glassLocation: "TEST3", glassName: "NAME3"}]); + + // Act + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(arePagePrerequisitesValid).toBe(true); + }) + + test("isRepair is set to null => arePagePrerequisitesValid should return false", async () => { + // Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_IS_REPAIR, null); + + // Act + console.log(store.getters.damage) + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(arePagePrerequisitesValid).toBe(false); + }); + + test("isRepair is set to true => arePagePrerequisitesValid should return true", async () => { + // Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_IS_REPAIR, true); + + // Act + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(arePagePrerequisitesValid).toBe(true); + }); + }) }); function setupMocks({ From 24e4441eaf4ea3c80abb690d5cf02d5c1344abcb Mon Sep 17 00:00:00 2001 From: Katie Date: Fri, 9 Sep 2022 13:34:42 -0400 Subject: [PATCH 2/4] Add tests --- .../vehicle-parts/vehicle-parts.spec.js | 4 +- src/layouts/vehicle-style/vehicle-style.vue | 1 + src/mixins/vehicle-questions-mixin.js | 11 +- src/mixins/vehicle-questions-mixin.spec.js | 136 +++- .../router-constants/navigation-scenarios.js | 8 +- src/router/router-constants/routing-table.js | 20 +- src/store/index.js | 39 +- src/store/store.spec.js | 732 ++++++++++++++++-- 8 files changed, 847 insertions(+), 104 deletions(-) diff --git a/src/layouts/vehicle-parts/vehicle-parts.spec.js b/src/layouts/vehicle-parts/vehicle-parts.spec.js index 14c83cfdb..d1eaa8df6 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.spec.js +++ b/src/layouts/vehicle-parts/vehicle-parts.spec.js @@ -236,7 +236,7 @@ describe("vehicle-parts.vue", () => { wrapper.vm.backButtonAction(); //Assert - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, wrapper.vm.$route); + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, wrapper.vm.$route); }); @@ -277,7 +277,7 @@ describe("vehicle-parts.vue", () => { wrapper.vm.backButtonAction(); //Assert - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, wrapper.vm.$route); + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, wrapper.vm.$route); }); diff --git a/src/layouts/vehicle-style/vehicle-style.vue b/src/layouts/vehicle-style/vehicle-style.vue index b86914520..5d700e183 100644 --- a/src/layouts/vehicle-style/vehicle-style.vue +++ b/src/layouts/vehicle-style/vehicle-style.vue @@ -76,6 +76,7 @@ export default { // If we have exactly one style then navigate directly to vehicle-damage if(resultMap.styleQuestionInitialData.length === 1 && !visitedVehicleDamage) { + // TODO KO store.commit(storeMutations.UPDATE_STYLE, resultMap.styleQuestionInitialData[0]); await store.dispatch(storeActions.SET_VEHICLE, diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 616c1fb5e..49d5f2a40 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -115,6 +115,7 @@ export default { // if single parts only const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions); // save to store lineItems.glassParts + // TODO KO self.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts); self.$refs.loadingModal.showModal(); @@ -127,20 +128,20 @@ export default { const hasGlassLocationWithMultipleParts = this.hasGlassLocationWithMultipleParts(partsOrQuestions); const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions); const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions); - let backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP; + let backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS; const currentPage = this.$route.query.fmgPage; if (hasCapabilityQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.CAPABILITY_QUESTIONS)) { - backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_CAPABILITY_QUESTIONS; + backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS; } else if (hasChildPartQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.MOLDING_QUESTIONS)) { - backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS; + backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS; } else if (hasGlassLocationWithMultipleParts && this.currentPageComesAfterPage(currentPage, fmgPageValues.VEHICLE_PARTS)) { - backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS; + backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE; } else if (hasPartQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.PART_QUESTIONS)) { - backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS; + backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS; } this.$router.navigateWithoutSaving( diff --git a/src/mixins/vehicle-questions-mixin.spec.js b/src/mixins/vehicle-questions-mixin.spec.js index 05d019da5..306aa60ce 100644 --- a/src/mixins/vehicle-questions-mixin.spec.js +++ b/src/mixins/vehicle-questions-mixin.spec.js @@ -7,6 +7,7 @@ import { storeActions } from "@/constants/store-actions"; import loadingModal from '@/common-components/loading-modal/loading-modal.vue'; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { navigationScenarios } from "../router/router-constants/navigation-scenarios"; +import { getters } from "@/store" jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({ navigateToHeritageFunnel: jest.fn() @@ -154,6 +155,46 @@ describe("vehicle-questions-mixin", () => { }); }); + describe("currentPageComesBeforePage", () => { + const testCases = [[fmgPageValues.PART_QUESTIONS, fmgPageValues.VEHICLE_PARTS, true], + [fmgPageValues.VEHICLE_PARTS, fmgPageValues.VEHICLE_PARTS, false], + [fmgPageValues.QUOTE, fmgPageValues.VEHICLE_PARTS, false], + [fmgPageValues.QUOTE, fmgPageValues.QUOTE, false], + [fmgPageValues.VEHICLE_PARTS, fmgPageValues.PART_QUESTIONS, false], + [fmgPageValues.PART_QUESTIONS, fmgPageValues.CAPABILITY_QUESTIONS, true], + [fmgPageValues.MOLDING_QUESTIONS, fmgPageValues.CAPABILITY_QUESTIONS, true],]; + test.each(testCases)("%s comes before %s is %s", (currentPage, nextPage, expectedResult) => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.currentPageComesBeforePage(currentPage, nextPage); + + // Assert + expect(result).toEqual(expectedResult); + }) + }); + + describe("currentPageComesAfterPage", () => { + const testCases = [[fmgPageValues.PART_QUESTIONS, fmgPageValues.VEHICLE_PARTS, false], + [fmgPageValues.VEHICLE_PARTS, fmgPageValues.VEHICLE_PARTS, false], + [fmgPageValues.QUOTE, fmgPageValues.VEHICLE_PARTS, true], + [fmgPageValues.QUOTE, fmgPageValues.QUOTE, false], + [fmgPageValues.VEHICLE_PARTS, fmgPageValues.PART_QUESTIONS, true], + [fmgPageValues.PART_QUESTIONS, fmgPageValues.CAPABILITY_QUESTIONS, false], + [fmgPageValues.MOLDING_QUESTIONS, fmgPageValues.CAPABILITY_QUESTIONS, false],]; + test.each(testCases)("%s comes after %s is %s", (currentPage, nextPage, expectedResult) => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.currentPageComesAfterPage(currentPage, nextPage); + + // Assert + expect(result).toEqual(expectedResult); + }) + }); + describe("navigateForward", () => { describe("should go to parts-questions", () => { test("single glass location has part question => go to parts-questions", async () => { @@ -890,23 +931,23 @@ describe("vehicle-questions-mixin", () => { "childParts": null, "childPartQuestions": [ { - "questionSequence": 1, - "questionText": "Does the rubber seal around your windshield have a chrome strip running through it?", - "answers": [ - { - "answerResult": "WKT D1106 C", - "answerText": "Yes", - "nextQuestionSequence": null - }, - { - "answerResult": "WKT D1106 B", - "answerText": "No", - "nextQuestionSequence": null - } - ] + "questionSequence": 1, + "questionText": "Does the rubber seal around your windshield have a chrome strip running through it?", + "answers": [ + { + "answerResult": "WKT D1106 C", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "WKT D1106 B", + "answerText": "No", + "nextQuestionSequence": null + } + ] } ] - + } ], "partQuestions": null @@ -1096,7 +1137,7 @@ describe("vehicle-questions-mixin", () => { // Act await wrapper.vm.navigateForward(partsOrQuestions); - + // Assert expect(wrapper.vm.$store.commit).toHaveBeenCalledTimes(1); @@ -1105,7 +1146,63 @@ describe("vehicle-questions-mixin", () => { expect(navigateToHeritageFunnel).toHaveBeenCalledTimes(1); }); }); - }) + }); + + describe("backButtonAction", () => { + test("current page is quote and there are no questions => go to vin-lookup", () => { + // Arrange + const { wrapper } = setupMocks({ fmgPage: fmgPageValues.QUOTE }); + + // Act + wrapper.vm.backButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, {"query": {"fmgPage": fmgPageValues.QUOTE}}) + }) + + test("current page is quote and there are part questions and molding questions => go to molding questions", () => { + // Arrange + const { wrapper } = setupMocks({ fmgPage: fmgPageValues.QUOTE }); + wrapper.vm.hasPartQuestions = jest.fn().mockReturnValue(true); + wrapper.vm.hasChildPartQuestions = jest.fn().mockReturnValue(true); + + // Act + wrapper.vm.backButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS, {"query": {"fmgPage": fmgPageValues.QUOTE}}) + }) + + test("current page is molding questions and there are part questions, multiple parts to choose, and capability questions => go to vehicle-parts", () => { + // Arrange + const { wrapper } = setupMocks({ fmgPage: fmgPageValues.MOLDING_QUESTIONS }); + wrapper.vm.hasPartQuestions = jest.fn().mockReturnValue(true); + wrapper.vm.hasGlassLocationWithMultipleParts = jest.fn().mockReturnValue(true); + wrapper.vm.hasChildPartQuestions = jest.fn().mockReturnValue(true); + wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true); + + // Act + wrapper.vm.backButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, {"query": {"fmgPage": fmgPageValues.MOLDING_QUESTIONS}}) + }) + + test("current page is molding questions and there are part questions and capability questions => go to part-questions", () => { + // Arrange + const { wrapper } = setupMocks({ fmgPage: fmgPageValues.MOLDING_QUESTIONS }); + wrapper.vm.hasPartQuestions = jest.fn().mockReturnValue(true); + wrapper.vm.hasGlassLocationWithMultipleParts = jest.fn().mockReturnValue(false); + wrapper.vm.hasChildPartQuestions = jest.fn().mockReturnValue(true); + wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true); + + // Act + wrapper.vm.backButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, {"query": {"fmgPage": fmgPageValues.MOLDING_QUESTIONS}}) + }) + }); }); function setupMocks({ fmgPage = fmgPageValues.VIN_LOOKUP }) { @@ -1118,11 +1215,12 @@ function setupMocks({ fmgPage = fmgPageValues.VIN_LOOKUP }) { const mocks = getMountOptions({ router: { - navigate: jest.fn(), navigateWithSaving: jest.fn(), navigateWithSaving: jest.fn() + navigate: jest.fn(), navigateWithSaving: jest.fn(), navigateWithoutSaving: jest.fn() }, store: { commit: jest.fn(), - dispatch: jest.fn() + dispatch: jest.fn(), + getters: getters }, route: { query: { diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 7578a0295..9ca7f9a30 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -25,10 +25,10 @@ const navigationScenarios = { HAS_MOLDING_QUESTIONS: "HAS_MOLDING_QUESTIONS", HAS_CAPABILITY_QUESTIONS: "HAS_CAPABILITY_QUESTIONS", HAS_NO_MORE_QUESTIONS: "HAS_NO_MORE_QUESTIONS", - CLICKED_BACK_TO_GO_TO_VIN_LOOKUP: "CLICKED_BACK_TO_GO_TO_VIN_LOOKUP", - CLICKED_BACK_TO_GO_TO_PART_QUESTIONS: "CLICKED_BACK_TO_GO_TO_PART_QUESTIONS", - CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS: "CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS", - CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS: "CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS" + CLICKED_BACK_WITH_NO_QUESTIONS: "CLICKED_BACK_WITH_NO_QUESTIONS", + CLICKED_BACK_WITH_PART_QUESTIONS: "CLICKED_BACK_WITH_PART_QUESTIONS", + CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE: "CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE", + CLICKED_BACK_WITH_MOLDING_QUESTIONS: "CLICKED_BACK_WITH_MOLDING_QUESTIONS" }; export { navigationScenarios }; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index f4b47bca9..f61ee1cbd 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -237,7 +237,7 @@ const routingTable = function(store) { fmgPageValue: fmgPageValues.PART_QUESTIONS, maps: [ { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, destinationFmgPageValue: fmgPageValues.VIN_LOOKUP }, { @@ -266,11 +266,11 @@ const routingTable = function(store) { destinationFmgPageValue: fmgPageValues.REVEAL, }, { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, + scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, destinationFmgPageValue: fmgPageValues.PART_QUESTIONS, }, { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, destinationFmgPageValue: fmgPageValues.VIN_LOOKUP, }, { @@ -291,15 +291,15 @@ const routingTable = function(store) { fmgPageValue: fmgPageValues.MOLDING_QUESTIONS, maps: [ { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, destinationFmgPageValue: fmgPageValues.VIN_LOOKUP }, { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, + scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, destinationFmgPageValue: fmgPageValues.PART_QUESTIONS }, { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS, + scenario: navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS }, { @@ -316,19 +316,19 @@ const routingTable = function(store) { fmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS, maps: [ { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, + scenario: navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, destinationFmgPageValue: fmgPageValues.VIN_LOOKUP }, { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, + scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, destinationFmgPageValue: fmgPageValues.PART_QUESTIONS }, { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS, + scenario: navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS }, { - scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS, + scenario: navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS, destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS }, { diff --git a/src/store/index.js b/src/store/index.js index 5a2a3ba1d..5ed386200 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -399,7 +399,7 @@ export const getters = { funnelSelectedPassengerSideGlass: getAllValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.PASSENGER), funnelOrderPartNumbers: [...getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "partNumber"), ...getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.otherParts, "partNumber")], - + funnelOrderPartTypes: [...getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType"), ...getAllValuesOfPropertyInArrayOfObjects(state.order.lineItems.otherParts, "recalibrationType")], } }, @@ -1004,9 +1004,10 @@ export const actions = { }, savePartQuestionAnswers(context, partQuestionAnswersArray) { // if part question answers have changed, reset subsequent question answers - const previousResultsArray = context.getters.damage.partQuestionAnswers; - const havePartQuestionAnswersChanged = previousResultsArray?.length !== partQuestionAnswersArray.length || - !previousResultsArray.every((x, i) => x.result === partQuestionAnswersArray[i].result); + const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.partQuestionAnswers, "result"); + const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(partQuestionAnswersArray, "result") + const havePartQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedPartQuestionAnswersArray.length || + !sortedPreviousResultsArray?.every((x, i) => x.result === sortedPartQuestionAnswersArray[i].result); if (havePartQuestionAnswersChanged) { context.commit(storeMutations.UPDATE_GLASS_PARTS, null); @@ -1021,9 +1022,8 @@ export const actions = { context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray); }, resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) { - const previousResultsArray = [{ parts: context.getters.lineItems.glassParts }]; const partsOrQuestionsDataToCompareWith = context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ?? context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)?.partsOrQuestions ?? []; - + function getAllPartNumbers(partsOrQuestions) { return partsOrQuestions[0]?.parts ? [...partsOrQuestions].map(glass => glass.parts).flat().map(part => part.partNumber).filter(partNumber => !partNumber.toUpperCase().includes("FEE")).sort().join(",") @@ -1044,9 +1044,10 @@ export const actions = { } }, saveMoldingQuestionAnswers(context, moldingQuestionAnswers) { - const previousResultsArray = context.getters.damage.moldingQuestionAnswers; - const haveMoldingQuestionAnswersChanged = previousResultsArray?.length !== moldingQuestionAnswers.length || - !previousResultsArray.every((x, i) => x.partNum === moldingQuestionAnswers[i].partNum); + const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.moldingQuestionAnswers, "partNum"); + const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(moldingQuestionAnswers, "partNum"); + const haveMoldingQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length || + !sortedPreviousResultsArray?.every((x, i) => x.partNum === sortedMoldingQuestionAnswersArray[i].partNum); if (haveMoldingQuestionAnswersChanged) { context.commit(storeMutations.UPDATE_GLASS_PARTS, null); @@ -1058,9 +1059,10 @@ export const actions = { context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers); }, saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) { - const previousResultsArray = context.getters.damage.capabilityQuestionAnswers; - const haveCapabilityQuestionAnswersChanged = previousResultsArray?.length !== capabilityQuestionAnswers.length || - !previousResultsArray.every((x, i) => x.result === capabilityQuestionAnswers[i].result); + const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.capabilityQuestionAnswers, "result"); + const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswers, "result"); + const haveCapabilityQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedCapabilityQuestionAnswersArray.length || + !sortedPreviousResultsArray?.every((x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result); if (haveCapabilityQuestionAnswersChanged) { context.commit(storeMutations.UPDATE_GLASS_PARTS, null); @@ -1126,4 +1128,17 @@ function getHasRecalibrationPart(state) { return false; } +} + +function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) { + if (!arrayOfObjects) return null; + + return arrayOfObjects.sort((a, b) => { + if (a[propertyName] < b[propertyName]) + return -1; + else if (a[propertyName] > b[propertyName]) + return 1; + else + return 0; + }) } \ No newline at end of file diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 8a710fe99..c6c5c75f3 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -3,6 +3,7 @@ import { mutations, state, actions, getters } from "@/store"; import { storeMutations } from "@/constants/store-mutations"; import { storeActions } from "@/constants/store-actions"; import { experimentTriggers } from "@/constants/experiments"; +import { fmgPageValues } from "@/router/router-constants/fmgPage-values" // Mock global method globalMethods.callHttpClient = jest.fn(); @@ -258,9 +259,9 @@ describe("Mutations", () => { { universeName: "XYZ", settings: { - ExperimentSetting: "ExperimentValue" + ExperimentSetting: "ExperimentValue" } - } + } ] // Act @@ -657,11 +658,11 @@ describe("Actions", () => { context.commit = commit; // Act - actions.updateStoreWithSaveOrderResponse(context, + actions.updateStoreWithSaveOrderResponse(context, { - referralNumber: "123", - referralDate: new Date().toUTCString(), - referralCorrelationId: "xxx-xxx-xxx", + referralNumber: "123", + referralDate: new Date().toUTCString(), + referralCorrelationId: "xxx-xxx-xxx", accountNumber: "167132", savedSessionId: "xxx-xxx-xxx", crmCustomerId: "xxx-xxx-xxx", @@ -826,19 +827,19 @@ describe("Actions", () => { // Act - const payload = { - isCarIdDifferent: true, - isSelectedGlassAvailableForVehicle: false, - vehicleInfo: { - carId: 'C010101', vin: "XXXXX" - }, - registrationInfo: { - zipCode: "80020" - }, - serviceLocationInfo: { - state: "CO" - }, - customerEmail: "test@safleite.com" + const payload = { + isCarIdDifferent: true, + isSelectedGlassAvailableForVehicle: false, + vehicleInfo: { + carId: 'C010101', vin: "XXXXX" + }, + registrationInfo: { + zipCode: "80020" + }, + serviceLocationInfo: { + state: "CO" + }, + customerEmail: "test@safleite.com" }; actions.saveVinLookup(context, payload); @@ -1065,7 +1066,7 @@ describe("Actions", () => { context.state = { order: { damage: { - glassToReplace: [{glassName: 'Single', glassLocation: 'Windshield'}] + glassToReplace: [{ glassName: 'Single', glassLocation: 'Windshield' }] } } }; @@ -1077,7 +1078,7 @@ describe("Actions", () => { context.dispatch = dispatch; // Act - const payload = { isWindshieldRepair: false, selectedGlassToReplace: [{glassName: 'Rear', glassLocation: 'quarter'}], selectedWindshieldChipCount: 0}; + const payload = { isWindshieldRepair: false, selectedGlassToReplace: [{ glassName: 'Rear', glassLocation: 'quarter' }], selectedWindshieldChipCount: 0 }; actions.saveVehicleDamage(context, payload); // Assert @@ -1156,50 +1157,677 @@ describe("Actions", () => { }) describe("savePartQuestionAnswers", () => { - test.todo("saves partQuestionAnswers") + let context; + beforeEach(() => { + jest.clearAllMocks(); + mutations.resetState(state); + context = state; + context.commit = jest.fn().mockImplementation((storeMutation, value) => mutations[storeMutation](context, value)); + context.getters = { + ...getters, + damage: getters.damage(context) + }; + }) - test.todo("there are no previous answers => resets necessary fields") + function testPartQuestionAnswerDependenciesHaveBeenReset(context, shouldPartQuestionAnswersBeReset) { + if (shouldPartQuestionAnswersBeReset) { + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.VEHICLE_PARTS, data: null }); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null }); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null }); + } + else { + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.VEHICLE_PARTS, data: null }); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null }); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null }); + } - // mix up the order to make sure sort is working - test.todo("previous answers match current answers => does not reset fields") + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PART_QUESTION_ANSWERS, expect.anything()); + } - test.todo("previous answers does not match current answers => resets necessary fields") + test("there are no previous answers => resets necessary fields", async () => { + // Arrange + const previousPartQuestionAnswers = []; + const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }, { result: "I'M A PART2!" }]; + + actions.savePartQuestionAnswers(context, previousPartQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.savePartQuestionAnswers(context, currentPartQuestionAnswers); + + // Assert + testPartQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("previous answers does not match current answers => resets necessary fields", () => { + // Arrange + const previousPartQuestionAnswers = [{ result: "I'M A PART2!" }, { result: "I'M A PART4!" }, { result: "I'M A PART3!" }]; + const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }, { result: "I'M A PART2!" }]; + + actions.savePartQuestionAnswers(context, previousPartQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.savePartQuestionAnswers(context, currentPartQuestionAnswers); + + // Assert + testPartQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("previous answers match current answers => does not reset fields", () => { + // Arrange + const previousPartQuestionAnswers = [{ result: "I'M A PART2!" }, { result: "I'M A PART!" }, { result: "I'M A PART3!" }]; + const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }, { result: "I'M A PART2!" }]; + + actions.savePartQuestionAnswers(context, previousPartQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.savePartQuestionAnswers(context, currentPartQuestionAnswers); + + // Assert + testPartQuestionAnswerDependenciesHaveBeenReset(context, false); + }) + test("previous answers have more questions/answers than current => resets fields", () => { + // Arrange + const previousPartQuestionAnswers = [{ result: "I'M A PART2!" }, { result: "I'M A PART!" }, { result: "I'M A PART3!" }]; + const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }]; + + actions.savePartQuestionAnswers(context, previousPartQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.savePartQuestionAnswers(context, currentPartQuestionAnswers); + + // Assert + testPartQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("current answers have more questions/answers than previous => resets fields", () => { + // Arrange + const previousPartQuestionAnswers = [{ result: "I'M A PART2!" }, { result: "I'M A PART3!" }]; + const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }, { result: "I'M A PART2!" }]; + + actions.savePartQuestionAnswers(context, previousPartQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.savePartQuestionAnswers(context, currentPartQuestionAnswers); + + // Assert + testPartQuestionAnswerDependenciesHaveBeenReset(context, true); + }) }) describe("resetMoldingAndCapabilityQuestionAnswersIfNeeded", () => { - test.todo("there are no saved parts => resets necessary fields") + let context; + beforeEach(() => { + mutations.resetState(state); + context = state; + context.commit = jest.fn().mockImplementation((storeMutation, value) => mutations[storeMutation](context, value)); + context.getters = { + ...getters, + pageData: getters.pageData(context) + }; + }) - // make sure you check the different variations where molding-questions and capability-questions do or don't have pageData - // mix up the order to make sure sort is working - test.todo("previously saved parts match selected parts => does not reset fields") + function testVehiclePartDependenciesHaveBeenReset(context, shouldAnswersBeReset) { + if (shouldAnswersBeReset) { + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null }); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null }); + } + else { + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null }); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null }); + } + } - test.todo("previously saved parts do not match selected parts => resets necessary fields") + test("there are no saved parts from molding or capability question pages => resets necessary fields", () => { + // Arrange + const previouslySelectedParts = {}; + + const currentlySelectedParts = [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.MOLDING_QUESTIONS, + data: previouslySelectedParts + }); + + mutations.updatePageData(context, { + page: fmgPageValues.CAPABILITY_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, true); + }) + + describe("previously saved parts from molding-questions match selected parts => does not reset fields", () => { + test("single glass location", () => { + // Arrange + const previouslySelectedParts = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART1" }, { partNumber: "PART2" }, { partNumber: "PART3" }] + } + ] + }; + + const currentlySelectedParts = [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.MOLDING_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, false); + }) + + test("multiple glass locations", () => { + // Arrange + const previouslySelectedParts = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART1" }, { partNumber: "PART2" }, { partNumber: "PART3" }] + }, + { + glassLocation: "Driver", + glassName: "Front", + parts: [{ partNumber: "PART5" }, { partNumber: "PART4" }] + } + ] + }; + + const currentlySelectedParts = [ + { + glassLocation: "Driver", + glassName: "Front", + parts: [{ partNumber: "PART4" }, { partNumber: "PART5" }] + }, + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.MOLDING_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, false); + }) + }) + + describe("previously saved parts from capability-questions match selected parts and there are none from molding-questions => does not reset fields", () => { + test("Single glass location", () => { + // Arrange + const previouslySelectedParts = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART1" }, { partNumber: "PART2" }, { partNumber: "PART3" }] + } + ] + }; + + const currentlySelectedParts = [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.CAPABILITY_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, false); + }) + + test("multiple glass locations", () => { + // Arrange + const previouslySelectedParts = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART1" }, { partNumber: "PART2" }, { partNumber: "PART3" }] + }, + { + glassLocation: "Driver", + glassName: "Front", + parts: [{ partNumber: "PART5" }, { partNumber: "PART4" }] + } + ] + }; + + const currentlySelectedParts = [ + { + glassLocation: "Driver", + glassName: "Front", + parts: [{ partNumber: "PART4" }, { partNumber: "PART5" }] + }, + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.CAPABILITY_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, false); + }) + }) + + describe("previously saved parts from molding-questions do not match selected parts => resets necessary fields", () => { + test("single glass location", () => { + // Arrange + const previouslySelectedParts = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART1" }, { partNumber: "PART6" }, { partNumber: "PART3" }] + } + ] + }; + + const currentlySelectedParts = [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.MOLDING_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, true); + }) + + test("multiple glass locations", () => { + // Arrange + const previouslySelectedParts = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART1" }, { partNumber: "PART6" }, { partNumber: "PART3" }] + }, + { + glassLocation: "Driver", + glassName: "Front", + parts: [{ partNumber: "PART5" }, { partNumber: "PART4" }] + } + ] + }; + + const currentlySelectedParts = [ + { + glassLocation: "Driver", + glassName: "Front", + parts: [{ partNumber: "PART4" }, { partNumber: "PART5" }] + }, + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.MOLDING_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, true); + }) + }) + + describe("previously saved parts from capability-questions do not match selected parts => resets necessary fields", () => { + test("single glass location", () => { + // Arrange + const previouslySelectedParts = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART1" }, { partNumber: "PART6" }, { partNumber: "PART3" }] + } + ] + }; + + const currentlySelectedParts = [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.MOLDING_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, true); + }) + + test("multiple glass locations", () => { + // Arrange + const previouslySelectedParts = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART1" }, { partNumber: "PART6" }, { partNumber: "PART3" }] + }, + { + glassLocation: "Driver", + glassName: "Front", + parts: [{ partNumber: "PART5" }, { partNumber: "PART4" }] + } + ] + }; + + const currentlySelectedParts = [ + { + glassLocation: "Driver", + glassName: "Front", + parts: [{ partNumber: "PART4" }, { partNumber: "PART5" }] + }, + { + glassLocation: "Windshield", + glassName: "Single", + parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }] + } + ]; + + mutations.updatePageData(context, { + page: fmgPageValues.CAPABILITY_QUESTIONS, + data: previouslySelectedParts + }); + + // Act + actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts); + + // Assert + testVehiclePartDependenciesHaveBeenReset(context, true); + }) + }) }) describe("saveMoldingQuestionAnswers", () => { - test.todo("saves moldingQuestionAnswers") + let context; + beforeEach(() => { + jest.clearAllMocks(); + mutations.resetState(state); + context = state; + context.commit = jest.fn().mockImplementation((storeMutation, value) => mutations[storeMutation](context, value)); + context.getters = { + ...getters, + damage: getters.damage(context) + }; + }) - test.todo("there are no previous answers => resets necessary fields") + function testMoldingQuestionAnswerDependenciesHaveBeenReset(context, shouldAnswersBeReset) { + if (shouldAnswersBeReset) { + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null }); + } + else { + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null }); + } + } - // mix up the order to make sure sort is working - test.todo("previous answers match current answers => does not reset fields") + test("there are no previous answers => resets necessary fields", () => { + // Arrange + const previousMoldingQuestionAnswers = []; + const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART2!" }]; - test.todo("previous answers does not match current answers => resets necessary fields") + actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers); + + // Assert + testMoldingQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("previous answers match current answers => does not reset fields", () => { + // Arrange + const previousMoldingQuestionAnswers = [{ partNum: "I'M A PART2!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART!" }];; + const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART2!" }]; + + actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers); + + // Assert + testMoldingQuestionAnswerDependenciesHaveBeenReset(context, false); + }) + + test("previous answers do not match current answers => resets necessary fields", () => { + // Arrange + const previousMoldingQuestionAnswers = [{ partNum: "I'M A PART2!" }, { partNum: "I'M A PART4!" }, { partNum: "I'M A PART!" }];; + const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART2!" }]; + + actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers); + + // Assert + testMoldingQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("previous answers have more questions/answers than current => resets fields", () => { + // Arrange + const previousMoldingQuestionAnswers = [{ partNum: "I'M A PART2!" }, { partNum: "I'M A PART4!" }, { partNum: "I'M A PART!" }];; + const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }]; + + actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers); + + // Assert + testMoldingQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("current answers have more questions/answers than previous => resets fields", () => { + // Arrange + const previousMoldingQuestionAnswers = [{ partNum: "I'M A PART2!" }, { partNum: "I'M A PART!" }];; + const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART2!" }]; + + actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers); + + // Assert + testMoldingQuestionAnswerDependenciesHaveBeenReset(context, true); + }) }) describe("saveCapabilityQuestionAnswers", () => { - test.todo("saves capabilityQuestionAnswers") + let context; + beforeEach(() => { + jest.clearAllMocks(); + mutations.resetState(state); + context = state; + context.commit = jest.fn().mockImplementation((storeMutation, value) => mutations[storeMutation](context, value)); + context.getters = { + ...getters, + damage: getters.damage(context) + }; + }) - test.todo("there are no previous answers => resets necessary fields") + function testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, shouldAnswersBeReset) { + if (shouldAnswersBeReset) { + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null); + } + else { + expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null); + } + } - // mix up the order to make sure sort is working - test.todo("previous answers match current answers => does not reset fields") + test("there are no previous answers => resets necessary fields", () => { + // Arrange + const previousCapabilityQuestionAnswers = []; + const currentCapabilityQuestionAnswers = [{ result: "DYNAMIC" }, { result: "STATIC" }, { result: "UNKNOWN" }]; - test.todo("previous answers does not match current answers => resets necessary fields") + actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers); + + // Assert + testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("previous answers match current answers => does not reset fields", () => { + // Arrange + const previousCapabilityQuestionAnswers = [{ result: "STATIC" }, { result: "DYNAMIC" }, { result: "UNKNOWN" }]; + const currentCapabilityQuestionAnswers = [{ result: "DYNAMIC" }, { result: "STATIC" }, { result: "UNKNOWN" }]; + + actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers); + + // Assert + testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, false); + }) + + test("previous answers do not match current answers => resets necessary fields", () => { + // Arrange + const previousCapabilityQuestionAnswers = [{ result: "DYNAMIC" }, { result: "DYNAMIC" }, { result: "STATIC" }]; + const currentCapabilityQuestionAnswers = [{ result: "STATIC" }, { result: "STATIC" }, { result: "DYNAMIC" }]; + + actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers); + + // Assert + testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("previous answers have more questions/answers than current => resets fields", () => { + // Arrange + const previousCapabilityQuestionAnswers = [{ result: "STATIC" }, { result: "DYNAMIC" }, { result: "UNKNOWN" }]; + const currentCapabilityQuestionAnswers = [{ result: "DYNAMIC" }]; + + actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers); + + // Assert + testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true); + }) + + test("current answers have more questions/answers than previous => resets fields", () => { + // Arrange + const previousCapabilityQuestionAnswers = [{ result: "STATIC" }, { result: "UNKNOWN" }]; + const currentCapabilityQuestionAnswers = [{ result: "DYNAMIC" }, { result: "STATIC" }, { result: "UNKNOWN" }]; + actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers); + jest.clearAllMocks(); + + // Act + actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers); + + // Assert + testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true); + }) }) }); - describe("Getters", () => { it("Vehicle getter, should return vehicle data", () => { // Arrange @@ -1315,7 +1943,7 @@ describe("Getters", () => { funnelOtherParts: null, funnelGlassToReplace: null } - + //Act mutations.updateYear(storeState, mockStateValues.funnelVehicleYear); mutations.updateMake(storeState, mockStateValues.funnelVehicleMake); @@ -1334,7 +1962,7 @@ describe("Getters", () => { mutations.updateGlassParts(storeState, mockStateValues.funnelGlassParts); mutations.updateOtherParts(storeState, mockStateValues.funnelOtherParts); mutations.updateGlassToReplace(storeState, mockStateValues.funnelGlassToReplace); - + //Assert expect(getters.experimentOrder(storeState)).toEqual({ funnelVehicleYear: mockStateValues.funnelVehicleYear, @@ -1380,7 +2008,7 @@ describe("Getters", () => { funnelOtherParts: [], funnelGlassToReplace: [] } - + //Act mutations.updateYear(storeState, mockStateValues.funnelVehicleYear); mutations.updateMake(storeState, mockStateValues.funnelVehicleMake); @@ -1399,7 +2027,7 @@ describe("Getters", () => { mutations.updateGlassParts(storeState, mockStateValues.funnelGlassParts); mutations.updateOtherParts(storeState, mockStateValues.funnelOtherParts); mutations.updateGlassToReplace(storeState, mockStateValues.funnelGlassToReplace); - + //Assert expect(getters.experimentOrder(storeState)).toEqual({ funnelVehicleYear: mockStateValues.funnelVehicleYear, @@ -1451,7 +2079,7 @@ describe("Getters", () => { } ], otherParts: [ - + ], glassToReplace: [ { @@ -1460,7 +2088,7 @@ describe("Getters", () => { } ] } - + //Act mutations.updateYear(storeState, mockStateValues.vehicleYear); mutations.updateMake(storeState, mockStateValues.vehicleMake); @@ -1479,7 +2107,7 @@ describe("Getters", () => { mutations.updateGlassParts(storeState, mockStateValues.glassParts); mutations.updateOtherParts(storeState, mockStateValues.otherParts); mutations.updateGlassToReplace(storeState, mockStateValues.glassToReplace); - + //Assert expect(getters.experimentOrder(storeState)).toEqual({ funnelVehicleYear: mockStateValues.vehicleYear, @@ -1545,7 +2173,7 @@ describe("Getters", () => { } ], otherParts: [ - + ], glassToReplace: [ { @@ -1566,7 +2194,7 @@ describe("Getters", () => { } ] } - + //Act mutations.updateYear(storeState, mockStateValues.vehicleYear); mutations.updateMake(storeState, mockStateValues.vehicleMake); @@ -1585,7 +2213,7 @@ describe("Getters", () => { mutations.updateGlassParts(storeState, mockStateValues.glassParts); mutations.updateOtherParts(storeState, mockStateValues.otherParts); mutations.updateGlassToReplace(storeState, mockStateValues.glassToReplace); - + //Assert expect(getters.experimentOrder(storeState)).toEqual({ funnelVehicleYear: mockStateValues.vehicleYear, From 8e8f663be38d4228412dc6dc70e093387eba2ea3 Mon Sep 17 00:00:00 2001 From: Katie Date: Tue, 13 Sep 2022 13:13:07 -0400 Subject: [PATCH 3/4] Add more tests --- jest.config.js | 3 +- .../vehicle-style/vehicle-style.spec.js | 115 +++++++++++++----- src/layouts/vehicle-style/vehicle-style.vue | 8 +- src/layouts/vin-lookup/vin-lookup.spec.js | 46 +++++-- src/layouts/vin-lookup/vin-lookup.vue | 6 + src/router/index.js | 2 + src/store/store.spec.js | 45 +++++++ 7 files changed, 178 insertions(+), 47 deletions(-) diff --git a/jest.config.js b/jest.config.js index d9da86118..b47bb3e56 100644 --- a/jest.config.js +++ b/jest.config.js @@ -25,8 +25,7 @@ module.exports = { testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], coverageThreshold: { global: { - // TODO after release/2022.09.15, raise this back up!! - statements: 80, + statements: 90, // Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90 }, }, diff --git a/src/layouts/vehicle-style/vehicle-style.spec.js b/src/layouts/vehicle-style/vehicle-style.spec.js index 1dd3a6774..e97b14882 100644 --- a/src/layouts/vehicle-style/vehicle-style.spec.js +++ b/src/layouts/vehicle-style/vehicle-style.spec.js @@ -10,6 +10,9 @@ import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { storeActions } from "@/constants/store-actions"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import baseMixin from "@/mixins/base-mixin.js"; +import router from "@/router" +import store from "@/store" +import { storeMutations } from "@/constants/store-mutations"; // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ @@ -21,25 +24,16 @@ jest.mock("@/helpers/cms-content-helper", () => ({ fetchCmsContentForPage: jest.fn(), })); -// Mock Store -jest.mock("@/store", () => ({ - getters: { - vehicle: { - model: "TL", - }, - applicationUser:{ - pageData: { - "part-questions": null, - "vehicle-make": {}, - "vehicle-model": {}, - "vehicle-style": {}, - "vehicle-damage": {} - } - } - }, +// Mock fetchCmsContentForPage +jest.mock("@/router", () => ({ + overrideNavigation: jest.fn(), })); describe("vehicle-style.vue", () => { + beforeEach(() => { + jest.clearAllMocks(); + }) + test("Style question component is initized with api data", async (done) => { //Arrange const styleQuestionInitialData = ["2 Door", "4 Door"]; @@ -63,9 +57,7 @@ describe("vehicle-style.vue", () => { done(); }); }); -}); -describe("vehicle-style.vue", () => { test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => { //Arrange const { wrapper, apiPromise } = setupMocks({ @@ -95,20 +87,12 @@ describe("vehicle-style.vue", () => { done(); }); }); -}); -describe("vehicle-style.vue", () => { - test("selectVehicle triggers a dispatchStoreAction commit", async (done) => { + test("setVehicle triggers a dispatchStoreAction commit", async (done) => { //Arrange const { wrapper, apiPromise } = setupMocks({ pageHeaderWidgetHeaderText: "Select a style to get started", mountOptionsMockData: { - store: { - commit: jest.fn(), - getters: { - vehicle: {}, - }, - }, actionList: [ { actionName: storeActions.SET_VEHICLE, @@ -134,9 +118,7 @@ describe("vehicle-style.vue", () => { done(); }); }); -}); -describe("vehicle-style.vue", () => { test("Model set, arePagePrerequisitesValid should be true ", async () => { //Arrange const { wrapper } = setupMocks({}); @@ -155,7 +137,61 @@ describe("vehicle-style.vue", () => { //Assert expect(arePagePrerequisitesValid).toBe(true); }); + + test("there is only one vehicle style => autoselect and move to vehicle damage", async () => { + //Arrange + const { wrapper } = setupMocks({ + styleQuestionInitialData: ["2 door sedan"], + }); + + // Act + await vehicleStyle.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-style" } }, + undefined, + (c) => c(wrapper.vm) + ); + + // Assert + expect(store.commit).toHaveBeenCalledWith(storeMutations.UPDATE_STYLE, "2 door sedan"); + expect(router.overrideNavigation).toHaveBeenCalled(); + }) + + test("there is only one vehicle style and vehicle-damage was visited => don't autoselect or move to vehicle damage", async () => { + //Arrange + const { wrapper } = setupMocks({ + styleQuestionInitialData: ["2 door sedan"], + mountOptionsMockData: { + store: { + getters: { + applicationUser: { + pageData: { + "part-questions": null, + "vehicle-make": {}, + "vehicle-model": {}, + "vehicle-style": {}, + "vehicle-damage": {} + } + } + } + } + } + }); + + // Act + await vehicleStyle.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-style" } }, + undefined, + (c) => c(wrapper.vm) + ); + + // Assert + expect(store.commit).not.toHaveBeenCalledWith(storeMutations.UPDATE_STYLE, "2 door sedan"); + expect(router.overrideNavigation).not.toHaveBeenCalled(); + }) }); + function setupMocks({ vehicleStyleQuestionCmsContent = {}, styleQuestionInitialData = {}, @@ -190,7 +226,26 @@ function setupMocks({ initializeComponent: jest.fn(), }; - const mountOptions = getMountOptions(mountOptionsMockData); + store.commit = jest.fn(); + store.dispatch = jest.fn(); + store.getters = mountOptionsMockData.store?.getters ?? { + vehicle: { + model: "TL", + }, + applicationUser: { + pageData: { + "part-questions": null, + "vehicle-make": {}, + "vehicle-model": {}, + "vehicle-style": {}, + } + } + } + + const mountOptions = getMountOptions({ + ...mountOptionsMockData, + store + }); const wrapper = shallowMount(vehicleStyle, mountOptions); wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; diff --git a/src/layouts/vehicle-style/vehicle-style.vue b/src/layouts/vehicle-style/vehicle-style.vue index 5d700e183..4a31c06cc 100644 --- a/src/layouts/vehicle-style/vehicle-style.vue +++ b/src/layouts/vehicle-style/vehicle-style.vue @@ -26,6 +26,7 @@