From a2eb94015e645b8298494eefb15ed60a0558276f Mon Sep 17 00:00:00 2001 From: Kulbhushan Kaushik Date: Thu, 1 Dec 2022 14:59:13 -0500 Subject: [PATCH 01/10] commit --- .../vehicle-parts/vehicle-parts.spec.js | 408 ++++++++++++++++++ src/layouts/vehicle-parts/vehicle-parts.vue | 222 ++++++++++ src/mixins/vehicle-questions-mixin.js | 6 +- src/store/index.js | 38 ++ 4 files changed, 670 insertions(+), 4 deletions(-) create mode 100644 src/layouts/vehicle-parts/vehicle-parts.spec.js create mode 100644 src/layouts/vehicle-parts/vehicle-parts.vue diff --git a/src/layouts/vehicle-parts/vehicle-parts.spec.js b/src/layouts/vehicle-parts/vehicle-parts.spec.js new file mode 100644 index 00000000..12292117 --- /dev/null +++ b/src/layouts/vehicle-parts/vehicle-parts.spec.js @@ -0,0 +1,408 @@ +// Components +import vehicleParts from "@/layouts/vehicle-parts/vehicle-parts.vue"; +import glassPartQuestion from "@/layouts/vehicle-parts/glass-part-question/glass-part-question"; + +// Supporting Files +import { settleAllPromises } from "@/helpers/layout-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { nextTick } from "vue"; +import baseMixin from "@/mixins/base-mixin.js"; +import { useMainStore } from "@/store"; +import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; + + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + + +const basePartResponse = { + partsOrQuestions: [ + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "DB12209GTYN", + description: "heated glass, solar, 1 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null, + }, + { + partNumber: "DB12209YPYNOEM", + description: "heated glass, solar, 1 hole", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null, + }, + ], + partQuestions: null, + }, + ], +}; + +describe("vehicle-parts.vue", () => { + test("Set cms content called on load", async (done) => { + //Arrange + useMainStore().pageData = jest.fn(); + useMainStore().pageData.mockReturnValue(basePartResponse); + useMainStore().lineItems = { glassParts: null }; + + const { wrapper, apiPromise } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn() + }, + route: { + query: { + issPage: "vehicle-parts", + }, + }, + }, + }); + + //Act + vehicleParts.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: "vehicle-parts" } }, + undefined, + (c) => c(wrapper.vm) + ); + wrapper.vm.setCmsContent = jest.fn(); + + //Assert + apiPromise.finally(() => { + expect(wrapper.vm.setCmsContent).toHaveBeenCalled(); + done(); + }); + }); + + test("PageData / isRepair populated in Vuex. arePagePrerequisitesValid should be true ", async () => { + //Arrange + useMainStore().pageData = jest.fn(); + useMainStore().pageData.mockReturnValue(basePartResponse); + useMainStore().lineItems = { glassParts: null }; + + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn(), + }, + route: { + query: { + issPage: "vehicle-parts", + }, + }, + }, + }); + + //Act + vehicleParts.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-parts" } }, + undefined, + (c) => c(wrapper.vm) + ); + + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + await nextTick(); + + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); + + test("Initial data, should populate this.selectedGlassParts", async () => { + //Arrange + useMainStore().pageData = jest.fn(); + useMainStore().pageData.mockReturnValue(basePartResponse); + useMainStore().lineItems = { glassParts: [{ partNumber: "DB12209YPYNOEM" }] }; + + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn(), + }, + route: { + query: { + issPage: "vehicle-parts", + }, + }, + }, + }); + + //Act + vehicleParts.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: "vehicle-parts" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await nextTick(); + + //Assert + expect(wrapper.vm.selectedGlassParts).toEqual({ + "Rear-Stationary": { + partNumber: "DB12209YPYNOEM", + description: "heated glass, solar, 1 hole", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null, + }, + }); + }); + + test("User had part questions > navigateBack triggers a router.navigateWithoutSaving change with correct scenario", async () => { + //Arrange + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn(), + }, + route: { + query: { + issPage: "vehicle-parts", + }, + }, + }, + }); + + //Act + vehicleParts.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: "vehicle-parts" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.navigateBack(); + + //Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, + wrapper.vm.$route + ); + }); + + test("User did not have part questions > navigateBack triggers a router.navigate change with correct scenario", async () => { + //Arrange + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn(), + }, + route: { + query: { + issPage: "vehicle-parts", + }, + }, + }, + }); + + //Act + vehicleParts.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: "vehicle-parts" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.navigateBack(); + + //Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS, + wrapper.vm.$route + ); + }); + + test("ForwardButtonAction triggers a router.navigate change if there are child part questions", async () => { + //Arrange + useMainStore().pageData = jest.fn(); + useMainStore().pageData.mockReturnValue({ + partsOrQuestions: [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: [ + { + partNumber: "FW03861GTYN", + description: + "rain sensor, heated glass, auto dimming mirror, solar, 3rd visor band, condensation sensor", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + recalibrationType: null, + 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, + }, + ], + }, + ], + }, + ], + partQuestions: null, + }, + ], + }); + useMainStore().lineItems = { glassParts: {} }; + + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn(), + }, + route: { + query: { + issPage: "vehicle-parts", + }, + }, + }, + }); + + wrapper.setData({ + selectedGlassParts: { "Rear-Stationary": { partNumber: "FW03861GTYN" } }, + }); + + //Act + vehicleParts.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: "vehicle-parts" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); + }); + + test("ForwardButtonAction triggers a router.navigate change if there are capability questions", async () => { + //Arrange + useMainStore().pageData = jest.fn(); + useMainStore().pageData.mockReturnValue({ + partsOrQuestions: [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: [ + { + partNumber: "DB12209GTYN", + description: "heated glass, solar, 1 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + ], + }); + useMainStore().lineItems = { glassParts: {} }; + useMainStore().vehicle = { carId: "TEST_CAR_ID" }; + + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { + navigate: jest.fn(), + }, + route: { + query: { + issPage: "vehicle-parts", + }, + }, + actionList: [ + { + actionName: "getCapabilityQuestions", + data: [], + }, + ], + }, + }); + + wrapper.setData({ + selectedGlassParts: { "Rear-Stationary": { partNumber: "DB12209GTYN" } }, + }); + + //Act + vehicleParts.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: "vehicle-parts" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); + }); + +}); + +function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {} }) { + //Mock api responses + const apiResponses = { + cmsContent: { + SiteSubHeaderWidget: pageHeaderWidgetHeaderText, + VehicleBannerWidget: { + GenericVehicleImage: + "https://digitalisscms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", + }, + FunnelHeaderWidget: { + LogoImage: + "https://digitalisscms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", + }, + ColorQuestionWidget: "Please choose your rear window tint color", + FeatureQuestionWidget: "Ok no choose features", + AlertWidget: { + BodyText: "Please choose your tint color", + HeadlineText: "Just a few more steps to go", + }, + }, + }; + + const apiPromise = Promise.resolve(apiResponses); + + settleAllPromises.mockImplementation(() => apiPromise); + fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + + const mountOptions = getMountOptions(mountOptionsMockData); + const wrapper = shallowMount(vehicleParts, mountOptions); + + const partQuestionRearWrapper = wrapper.findComponent({ name: "glassPartQuestion" }); + partQuestionRearWrapper.vm.initializeComponent = glassPartQuestion.methods.initializeComponent; + + wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; + wrapper.vm.$refs.siteFooter.removeLoader = jest.fn(); + + return { wrapper, apiPromise }; +} diff --git a/src/layouts/vehicle-parts/vehicle-parts.vue b/src/layouts/vehicle-parts/vehicle-parts.vue new file mode 100644 index 00000000..b734f58a --- /dev/null +++ b/src/layouts/vehicle-parts/vehicle-parts.vue @@ -0,0 +1,222 @@ + + + diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index d06c1010..533a2b27 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -1,6 +1,6 @@ import { issPageValues } from "@/router/router-constants/issPage-values"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; -import { useMainStore } from "../store"; +import { useMainStore } from "@/store"; export default { methods: { @@ -405,9 +405,7 @@ export default { // mimic part-questions page data for consistency for (let partOrQuestion of partsOrQuestions) { if (this.hasCapabilityQuestions([partOrQuestion])) { - let capabilityQuestionsForGlassLocation = ( - await self.mainStore.getCapabilityQuestions(useMainStore().vehicle.carId, partOrQuestion.parts[0].partNumber) - ).data; + let capabilityQuestionsForGlassLocation = (await useMainStore().getCapabilityQuestions(useMainStore().vehicle.carId, partOrQuestion.parts[0].partNumber)); capabilityQuestionsForGlassLocation.forEach((question) => { question.answers = question.answers.map((answer) => { diff --git a/src/store/index.js b/src/store/index.js index 6a098a76..6a51b97e 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -91,6 +91,7 @@ export const useMainStore = defineStore({ getters: { vehicle: (state) => state.order.vehicle, damage: (state) => state.order.damage, + lineItems: (state) => state.order.lineItems, eventBusItem: (state) => ( eventCategory, eventSubCategory) => { const matchedEvent = state.applicationUser.eventBus.find( @@ -354,12 +355,38 @@ export const useMainStore = defineStore({ this.applicationUser.pageData[issPageValues.CAPABILITY_QUESTIONS] = null; }, + resetSupportingItemsState() { + this.order.lineItems.supportingItems = null; + }, + resetDamageState() { this.order.damage.isRepair = null; this.order.damage.numberOfChips = null; this.order.damage.glassToReplace = null; }, + resetMoldingAndCapabilityQuestionAnswersIfNeeded(matchedParts) { + const partsOrQuestionsDataToCompareWith = + this.pageData(issPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ?? + this.pageData(issPageValues.CAPABILITY_QUESTIONS)?.partsOrQuestions ?? + []; + + const previouslySelectedPartNumbers = getAllPartNumbers(partsOrQuestionsDataToCompareWith); + const currentlySelectedPartNumbers = getAllPartNumbers(matchedParts); + + const haveSelectedVehiclePartsChanged = + previouslySelectedPartNumbers !== currentlySelectedPartNumbers; + + if (haveSelectedVehiclePartsChanged) { + this.updateGlassParts(null); + this.resetSupportingItemsState(); + this.updateMoldingQuestionAnswers(null); + this.updateCapabilityQuestionAnswers(null); + this.updatePageData({ page: issPageValues.MOLDING_QUESTIONS, data: null}); + this.updatePageData({ page: issPageValues.CAPABILITY_QUESTIONS, data: null}); + } + }, + updateVehicleYear(year) { if(this.order.vehicle.year != year) { @@ -726,3 +753,14 @@ function convertGlassPieceNamingFromApi(glassArray) { return glassArray; } +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(",") + : []; +} From 5fb48ea1eecb42e503fe1abd7608c5ba6488e909 Mon Sep 17 00:00:00 2001 From: Kulbhushan Kaushik Date: Mon, 5 Dec 2022 08:54:32 -0500 Subject: [PATCH 02/10] commit --- src/mixins/vehicle-questions-mixin.js | 2 +- src/store/index.js | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 533a2b27..dd1b0570 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -405,7 +405,7 @@ export default { // mimic part-questions page data for consistency for (let partOrQuestion of partsOrQuestions) { if (this.hasCapabilityQuestions([partOrQuestion])) { - let capabilityQuestionsForGlassLocation = (await useMainStore().getCapabilityQuestions(useMainStore().vehicle.carId, partOrQuestion.parts[0].partNumber)); + let capabilityQuestionsForGlassLocation = (await this.mainStore.getCapabilityQuestions(this.mainStore.vehicle.carId, partOrQuestion.parts[0].partNumber)); capabilityQuestionsForGlassLocation.forEach((question) => { question.answers = question.answers.map((answer) => { diff --git a/src/store/index.js b/src/store/index.js index 6a51b97e..d875d8c7 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -57,12 +57,6 @@ const getDefaultState = () => { isVerified: false, }, }, - serviceLocation: { - address: null, - city: null, - state: null, - zipCode: null, - }, referralNumber: null, referralDate: null, accountNumber: 0, From 3efb2f6e153c0df0a1edd6ffc8c38c7a32f6e3fa Mon Sep 17 00:00:00 2001 From: Kulbhushan Kaushik Date: Mon, 5 Dec 2022 10:35:25 -0500 Subject: [PATCH 03/10] COMMIT --- src/layouts/vehicle-parts/vehicle-parts.spec.js | 13 ++++++++++++- src/mixins/vehicle-questions-mixin.js | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/layouts/vehicle-parts/vehicle-parts.spec.js b/src/layouts/vehicle-parts/vehicle-parts.spec.js index 12292117..4b67fe64 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.spec.js +++ b/src/layouts/vehicle-parts/vehicle-parts.spec.js @@ -23,6 +23,14 @@ jest.mock("@/helpers/cms-content-helper", () => ({ fetchCmsContentForPage: jest.fn(), })); +useMainStore().getters = { + pageData: jest.fn(), + damage: { + isRepair: false, + }, +}; + + const basePartResponse = { partsOrQuestions: [ @@ -69,6 +77,9 @@ describe("vehicle-parts.vue", () => { issPage: "vehicle-parts", }, }, + useMainStore: { + getters: useMainStore().getters, + }, }, }); @@ -110,7 +121,7 @@ describe("vehicle-parts.vue", () => { //Act vehicleParts.beforeRouteEnter.call( wrapper.vm, - { query: { fmgPage: "vehicle-parts" } }, + { query: { issPage: "vehicle-parts" } }, undefined, (c) => c(wrapper.vm) ); diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index dd1b0570..9e482eea 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -405,7 +405,7 @@ export default { // mimic part-questions page data for consistency for (let partOrQuestion of partsOrQuestions) { if (this.hasCapabilityQuestions([partOrQuestion])) { - let capabilityQuestionsForGlassLocation = (await this.mainStore.getCapabilityQuestions(this.mainStore.vehicle.carId, partOrQuestion.parts[0].partNumber)); + let capabilityQuestionsForGlassLocation = (await this.mainStore.getCapabilityQuestions(this.mainStore.vehicle.carId, partOrQuestion.parts[0].partNumber)).data; capabilityQuestionsForGlassLocation.forEach((question) => { question.answers = question.answers.map((answer) => { From b770d9c0789f291df4591309cf53b0684ce23a69 Mon Sep 17 00:00:00 2001 From: Kulbhushan Kaushik Date: Mon, 5 Dec 2022 14:51:22 -0500 Subject: [PATCH 04/10] commit --- src/layouts/vehicle-parts/vehicle-parts.spec.js | 14 ++++++++++---- src/mixins/vehicle-questions-mixin.js | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/layouts/vehicle-parts/vehicle-parts.spec.js b/src/layouts/vehicle-parts/vehicle-parts.spec.js index 4b67fe64..ed6732be 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.spec.js +++ b/src/layouts/vehicle-parts/vehicle-parts.spec.js @@ -61,7 +61,7 @@ const basePartResponse = { }; describe("vehicle-parts.vue", () => { - test("Set cms content called on load", async (done) => { + test("Set cms content called on load", async () => { //Arrange useMainStore().pageData = jest.fn(); useMainStore().pageData.mockReturnValue(basePartResponse); @@ -95,7 +95,6 @@ describe("vehicle-parts.vue", () => { //Assert apiPromise.finally(() => { expect(wrapper.vm.setCmsContent).toHaveBeenCalled(); - done(); }); }); @@ -104,6 +103,7 @@ describe("vehicle-parts.vue", () => { useMainStore().pageData = jest.fn(); useMainStore().pageData.mockReturnValue(basePartResponse); useMainStore().lineItems = { glassParts: null }; + useMainStore().damage.isRepair = false; const { wrapper } = setupMocks({ mountOptionsMockData: { @@ -202,7 +202,7 @@ describe("vehicle-parts.vue", () => { //Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, + navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS, wrapper.vm.$route ); }); @@ -234,7 +234,7 @@ describe("vehicle-parts.vue", () => { //Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS, + navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS, wrapper.vm.$route ); }); @@ -371,6 +371,7 @@ describe("vehicle-parts.vue", () => { (c) => c(wrapper.vm) ); + await wrapper.vm.forwardButtonAction(); //Assert @@ -401,10 +402,15 @@ function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {} }, }; + const store = useMainStore(); + let actionResult = []; + store.getCapabilityQuestions.mockImplementation(() => Promise.resolve({data: actionResult,})); + const apiPromise = Promise.resolve(apiResponses); settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + const mountOptions = getMountOptions(mountOptionsMockData); const wrapper = shallowMount(vehicleParts, mountOptions); diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 9e482eea..8a67d9b4 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -405,7 +405,7 @@ export default { // mimic part-questions page data for consistency for (let partOrQuestion of partsOrQuestions) { if (this.hasCapabilityQuestions([partOrQuestion])) { - let capabilityQuestionsForGlassLocation = (await this.mainStore.getCapabilityQuestions(this.mainStore.vehicle.carId, partOrQuestion.parts[0].partNumber)).data; + let capabilityQuestionsForGlassLocation = (await useMainStore().getCapabilityQuestions(useMainStore().vehicle.carId, partOrQuestion.parts[0].partNumber)).data; capabilityQuestionsForGlassLocation.forEach((question) => { question.answers = question.answers.map((answer) => { @@ -432,7 +432,7 @@ export default { const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions); // save to store lineItems.glassParts - self.mainStore.updateGlassParts(collectedGlassParts); + useMainStore().updateGlassParts(collectedGlassParts); self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,self.$route); } From 81a35dd0bb87b69b0f7d44173d44bb5a7c7f0b25 Mon Sep 17 00:00:00 2001 From: Johan Gunawan Date: Mon, 5 Dec 2022 16:08:35 -0500 Subject: [PATCH 05/10] Fix console warning in DevTools --- src/layouts/vehicle-year/year-question/year-question.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/vehicle-year/year-question/year-question.vue b/src/layouts/vehicle-year/year-question/year-question.vue index 84dfd15f..8af5fce9 100644 --- a/src/layouts/vehicle-year/year-question/year-question.vue +++ b/src/layouts/vehicle-year/year-question/year-question.vue @@ -24,7 +24,7 @@ }; }, props: { - modelValue: String, + modelValue: Number, cmsWidgetName: String, }, components: { From 8a1933d76f055873c7b5c4f77481a458f5024ce0 Mon Sep 17 00:00:00 2001 From: Johan Gunawan Date: Mon, 5 Dec 2022 16:10:45 -0500 Subject: [PATCH 06/10] Change String to Number The actual implementation in the component is using number instead of a string. The tests should match that. --- .../vehicle-year/year-question/year-question.spec.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/layouts/vehicle-year/year-question/year-question.spec.js b/src/layouts/vehicle-year/year-question/year-question.spec.js index c5e418d1..39138d8f 100644 --- a/src/layouts/vehicle-year/year-question/year-question.spec.js +++ b/src/layouts/vehicle-year/year-question/year-question.spec.js @@ -6,8 +6,8 @@ import { useMainStore } from "@/store"; describe("year-question.vue", () => { test("Selected year is emitted upon selection.", async () => { //Arrange - const { wrapper } = setupMocks({ modelValueProp: "2020" }); - const yearToSelect = "2021"; + const { wrapper } = setupMocks({ modelValueProp: 2020 }); + const yearToSelect = 2021; //Act wrapper.setValue({ modelValue: yearToSelect }); @@ -15,7 +15,7 @@ describe("year-question.vue", () => { //Assert expect(wrapper.emitted()["update:modelValue"][0]).toEqual([ - { modelValue: "2021" }, + { modelValue: 2021 }, ]); }); }); @@ -24,7 +24,7 @@ describe("year-question.vue", () => { test("Data from store api are used as radio question answers.", async () => { //Arrange const { wrapper, cmsContent } = setupMocks({ - dataFromStoreApi: ["2023", "2022", "2021"], + dataFromStoreApi: [2023, 2022, 2021], }); //Act @@ -46,7 +46,7 @@ describe("year-question.vue", () => { function setupMocks({ - modelValueProp = "1900", + modelValueProp = 1900, cmsQuestionText = "CMS text goes here", dataFromStoreApi = [], }) { From 75b7833a802cf2b1f69eb95ab611ceb5566d1423 Mon Sep 17 00:00:00 2001 From: Johan Gunawan Date: Mon, 5 Dec 2022 17:13:34 -0500 Subject: [PATCH 07/10] Remove unnecessary computed SiteSubHeader component already has a computed property for backButtonAccessibleText. --- src/layouts/vehicle-make/vehicle-make.vue | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/layouts/vehicle-make/vehicle-make.vue b/src/layouts/vehicle-make/vehicle-make.vue index baa96ece..c7b9e0f1 100644 --- a/src/layouts/vehicle-make/vehicle-make.vue +++ b/src/layouts/vehicle-make/vehicle-make.vue @@ -5,9 +5,8 @@
@@ -97,12 +96,6 @@ this.$route ); }, - }, - computed: { - backButtonAccessibleText() - { - return this.getCmsContent(this.cmsWidgetName, "BackButtonAccessibleText") - }, - }, + } }; \ No newline at end of file From 60d98f993809760fc5af5c5da712c6269d8471ba Mon Sep 17 00:00:00 2001 From: Johan Gunawan Date: Mon, 5 Dec 2022 17:28:31 -0500 Subject: [PATCH 08/10] Array needs to be initialized --- src/layouts/vehicle-make/make-question/make-question.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/vehicle-make/make-question/make-question.vue b/src/layouts/vehicle-make/make-question/make-question.vue index 9ed4f4ea..15e86c3c 100644 --- a/src/layouts/vehicle-make/make-question/make-question.vue +++ b/src/layouts/vehicle-make/make-question/make-question.vue @@ -20,7 +20,7 @@ name: "make-question", data() { return { - makes: Array, + makes: [], }; }, props: { From 45e73d3087fac6933fabdc44c240a9c38f446593 Mon Sep 17 00:00:00 2001 From: Kulbhushan Kaushik Date: Tue, 6 Dec 2022 08:37:41 -0500 Subject: [PATCH 09/10] vehicle-questions-mixin unit tests --- src/mixins/vehicle-questions-mixin.spec.js | 2343 ++++++++++++++++++++ 1 file changed, 2343 insertions(+) create mode 100644 src/mixins/vehicle-questions-mixin.spec.js diff --git a/src/mixins/vehicle-questions-mixin.spec.js b/src/mixins/vehicle-questions-mixin.spec.js new file mode 100644 index 00000000..2e0c213d --- /dev/null +++ b/src/mixins/vehicle-questions-mixin.spec.js @@ -0,0 +1,2343 @@ +import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; +import { shallowMount } from "@vue/test-utils"; +import { setupMocksForJsFiles, getMountOptions } from "@/helpers/unit-test-helper.js"; +import { issPageValues } from "@/router/router-constants/issPage-values"; +import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; +import {useMainStore} from "@/store"; + +describe("vehicle-questions-mixin", () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("hasPartQuestions", () => { + test("has no part questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasPartQuestions = wrapper.vm.hasPartQuestions([ + { + partQuestions: [], + }, + ]); + + // Assert + expect(hasPartQuestions).toBe(false); + }); + + test("has undefined part questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasPartQuestions = wrapper.vm.hasPartQuestions([]); + + // Assert + expect(hasPartQuestions).toBe(false); + }); + + test("has part questions => return true", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasPartQuestions = wrapper.vm.hasPartQuestions([ + { + partQuestions: [ + { + testProperty: "some value", + }, + ], + }, + ]); + + // Assert + expect(hasPartQuestions).toBe(true); + }); + }); + + describe("hasGlassLocationWithMultipleParts", () => { + test("has one part for one glass location => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ + { + glassName: "Something", + glassLocation: "somewhere", + parts: [ + { + partNumber: "1234567", + }, + ], + }, + ]); + + // Assert + expect(hasGlassLocationWithMultipleParts).toBe(false); + }); + + test("has one part for every glass location => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ + { + glassName: "Something", + glassLocation: "somewhere", + parts: [ + { + partNumber: "1234567", + }, + ], + }, + { + glassName: "Another glass", + glassLocation: "somewhere else", + parts: [ + { + partNumber: "1234568", + }, + ], + }, + { + glassName: "Special glass", + glassLocation: "Another where", + parts: [ + { + partNumber: "1234569", + }, + ], + }, + ]); + + // Assert + expect(hasGlassLocationWithMultipleParts).toBe(false); + }); + + test("has multiple parts for one glass location => return true", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ + { + glassName: "Something", + glassLocation: "somewhere", + parts: [ + { + partNumber: "1234567", + }, + ], + }, + { + glassName: "Another glass", + glassLocation: "somewhere else", + parts: [ + { + partNumber: "1234568", + }, + ], + }, + { + glassName: "Special glass", + glassLocation: "Another where", + parts: [ + { + partNumber: "1234569", + }, + { + partNumber: "1234560", + }, + ], + }, + ]); + + // Assert + expect(hasGlassLocationWithMultipleParts).toBe(true); + }); + }); + + describe("hasChildPartQuestions", () => { + test("has no child part questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasChildPartQuestions = wrapper.vm.hasChildPartQuestions([ + { + parts: [ + { + childPartQuestions: [], + }, + ], + }, + ]); + + // Assert + expect(hasChildPartQuestions).toBe(false); + }); + + test("has undefined child part questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasChildPartQuestions = wrapper.vm.hasChildPartQuestions([]); + + // Assert + expect(hasChildPartQuestions).toBe(false); + }); + + test("has child part questions => return true", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasChildPartQuestions = wrapper.vm.hasChildPartQuestions([ + { + parts: [ + { + 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, + }, + ], + }, + ], + }, + ], + }, + ]); + + // Assert + expect(hasChildPartQuestions).toBe(true); + }); + }); + + describe("hasCapabilityQuestions", () => { + test("has no capability questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasCapabilityQuestions = wrapper.vm.hasCapabilityQuestions([ + { + parts: [ + { + requiresCapabilityQuestions: false, + }, + ], + }, + ]); + + // Assert + expect(hasCapabilityQuestions).toBe(false); + }); + + test("has undefined capability questions => return false", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasCapabilityQuestions = wrapper.vm.hasCapabilityQuestions([]); + + // Assert + expect(hasCapabilityQuestions).toBe(false); + }); + + test("has capability questions => return true", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const hasCapabilityQuestions = wrapper.vm.hasCapabilityQuestions([ + { + parts: [ + { + requiresCapabilityQuestions: true, + }, + ], + }, + ]); + + // Assert + expect(hasCapabilityQuestions).toBe(true); + }); + }); + + describe("currentPageComesBeforePage", () => { + const testCases = [ + [issPageValues.PART_QUESTIONS, issPageValues.VEHICLE_PARTS, true], + [issPageValues.VEHICLE_PARTS, issPageValues.VEHICLE_PARTS, false], + [issPageValues.QUOTE, issPageValues.VEHICLE_PARTS, false], + [issPageValues.QUOTE, issPageValues.QUOTE, false], + [issPageValues.VEHICLE_PARTS, issPageValues.PART_QUESTIONS, false], + [issPageValues.PART_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, true], + [issPageValues.MOLDING_QUESTIONS, issPageValues.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 = [ + [issPageValues.PART_QUESTIONS, issPageValues.VEHICLE_PARTS, false], + [issPageValues.VEHICLE_PARTS, issPageValues.VEHICLE_PARTS, false], + [issPageValues.QUOTE, issPageValues.VEHICLE_PARTS, true], + [issPageValues.QUOTE, issPageValues.QUOTE, false], + [issPageValues.VEHICLE_PARTS, issPageValues.PART_QUESTIONS, true], + [issPageValues.PART_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, false], + [issPageValues.MOLDING_QUESTIONS, issPageValues.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("setupInitialData", () => { + describe("if no alreadyAnsweredQuestions", () => { + test("should return glass with answerData of null", async () => { + // Arrange + const glass = { + glassName: "Single", + glassLocation: "Windshield", + }; + const i = 0; + const { wrapper } = setupMocks({}); + + // Act + const returnedGlass = await wrapper.vm.setupInitialData(glass, i); + + // Assert + expect(returnedGlass).toMatchObject({ answerData: null }); + }); + }); + + describe("if alreadyAnsweredQuestions", () => { + test("should return glass with answerResult within answerData", async () => { + // Arrange + const glass = { + glassName: "Single", + glassLocation: "Windshield", + questions: [ + { + 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, + }, + ], + }, + ], + }; + const i = 0; + const alreadyAnsweredQuestions = [ + { + glassLocation: "Windshield", + glassName: "Single", + partNum: "WKT D1106 C", + answeredQuestions: [ + { + questionText: + "Does the rubber seal around your windshield have a chrome strip running through it?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + ], + }, + ]; + const { wrapper } = setupMocks({}); + + // Act + const returnedGlass = await wrapper.vm.setupInitialData( + glass, + i, + alreadyAnsweredQuestions + ); + + // Assert + expect(returnedGlass.answerData).toMatchObject({ answerResult: "WKT D1106 C" }); + }); + }); + }); + + describe("handleAnswerUpdates", () => { + describe("selectedAnswers", () => { + test("should be cleared to be empty", () => { + // Arrange + const answer = { + answerResult: "DD11132", + answeredQuestions: [ + { + questionText: "Test duplicate question 1?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.selectedAnswers = { test: "mockSelectedAnswers" }; + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [], + answerData: "testAnswerData1", + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answer, "", wrapper.vm); + + // Assert + expect(wrapper.vm.selectedAnswers).toMatchObject({}); + }); + }); + + describe("questions in glass parts that are after the answered glass", () => { + test("should have answerData cleared", () => { + // Arrange + const answer = { + answerResult: "DD11132", + answeredQuestions: [ + { + questionText: "Test duplicate question 1?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [], + answerData: "testAnswerData1", + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [], + answerData: "testAnswerData2", + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answer, "", wrapper.vm); + + // Assert + expect(wrapper.vm.questionsData[1].answerData).toEqual(null); + }); + test("should have isSuppressedPart cleared", () => { + // Arrange + const answer = { + answerResult: "DD11132", + answeredQuestions: [ + { + questionText: "Test duplicate question 1?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [], + answerData: "testAnswerData1", + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [], + answerData: "testAnswerData2", + isSuppressedPart: true, + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answer, "", wrapper.vm); + + // Assert + expect(wrapper.vm.questionsData[1].isSuppressedPart).toEqual(null); + }); + test("should set answerSelected for each glass part question to null ", () => { + // Arrange + const answer = { + answerResult: "DD11132", + answeredQuestions: [ + { + questionText: "Test duplicate question 1?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [], + answerData: "testAnswerData1", + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [ + { + questionSequence: 1, + questionText: + "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + answers: [ + { + answerResult: "", + answerText: "Yes", + nextQuestionSequence: 2, + }, + { + answerResult: "", + answerText: "No", + nextQuestionSequence: 3, + }, + ], + answerSelected: "456", + }, + { + questionSequence: 2, + questionText: + "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + answers: [ + { + answerResult: "FW04848", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "FW04846", + answerText: "No", + nextQuestionSequence: null, + }, + ], + answerSelected: "789", + }, + ], + answerData: "testAnswerData2", + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answer, "", wrapper.vm); + + // Assert + expect(wrapper.vm.questionsData[1].questions[0].answerSelected).toEqual(null); + expect(wrapper.vm.questionsData[1].questions[1].answerSelected).toEqual(null); + }); + }); + + describe("if there is a duplicate question", () => { + test("then the glass piece's key should be updated", () => { + // Arrange + const answerNo = { + answerResult: "456", + answeredQuestions: [ + { + questionText: "Test duplicate question 1?", + selectedAnswerText: "No", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + key: "testkey1", + questions: [ + { + questionSequence: 1, + questionText: "Test duplicate question 1?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + { + glassLocation: "Driver", + glassName: "Front", + key: "testkey2", + questions: [ + { + questionSequence: 1, + questionText: "Test duplicate question 1?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "234", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, "", wrapper.vm); + const glassWithDuplicate = wrapper.vm.questionsData[1]; + + // Assert + expect(glassWithDuplicate.key).not.toBe("testkey2"); + }); + + test("then that question should be supressed", () => { + // Arrange + const answerNo = { + answerResult: "456", + answeredQuestions: [ + { + questionText: "Test duplicate question 1?", + selectedAnswerText: "No", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [ + { + questionSequence: 1, + questionText: "Test duplicate question 1?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [ + { + questionSequence: 1, + questionText: "Test duplicate question 1?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "234", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, "", wrapper.vm); + const duplicateQuestion = wrapper.vm.questionsData[1].questions[0]; + + // Assert + expect(duplicateQuestion.suppressThisQuestion).toBeTruthy(); + }); + + describe("and the duplicate has a nextQuestionSequence value", () => { + test("then the question set as nextQuestionSequence should not be suppressed", () => { + // Arrange + const answerNo = { + answerResult: "456", + answeredQuestions: [ + { + questionText: "Test duplicate question 1?", + selectedAnswerText: "No", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [ + { + questionSequence: 1, + questionText: "Test duplicate question 1?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [ + { + questionSequence: 1, + questionText: "ZZZTest duplicate question 1?", + answers: [ + { + answerResult: "", + answerText: "Yes", + nextQuestionSequence: 2, + }, + { + answerResult: "", + answerText: "No", + nextQuestionSequence: 3, + }, + ], + }, + { + questionSequence: 2, + questionText: "Test question 2?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "234", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + { + questionSequence: 3, + questionText: "Test question 3?", + answers: [ + { + answerResult: "345", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + suppressThisQuestion: true, + }, + ], + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, "", wrapper.vm); + const nextQuestionAfterDuplicate = wrapper.vm.questionsData[1].questions[2]; + + // Assert + expect(nextQuestionAfterDuplicate.suppressThisQuestion).not.toBeTruthy(); + }); + + test("then the nextQuestionSequence should be updated and the original value saved", () => { + // Arrange + const answerNo = { + answerResult: "456", + answeredQuestions: [ + { + questionText: "Test question 3?", + selectedAnswerText: "No", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [ + { + questionSequence: 1, + questionText: "Test question 3?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [ + { + questionSequence: 1, + questionText: "Test question 1?", + answers: [ + { + answerResult: "", + answerText: "Yes", + nextQuestionSequence: 2, + }, + { + answerResult: "", + answerText: "No", + nextQuestionSequence: 3, + }, + ], + }, + { + questionSequence: 2, + questionText: "Test question 2?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "234", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + { + questionSequence: 3, + questionText: "Test question 3?", + answers: [ + { + answerResult: "", + answerText: "Yes", + nextQuestionSequence: 4, + }, + { + answerResult: "", + answerText: "No", + nextQuestionSequence: 5, + }, + ], + }, + { + questionSequence: 4, + questionText: "Test question 4?", + answers: [ + { + answerResult: "567", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "678", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + { + questionSequence: 5, + questionText: "Test question 5?", + answers: [ + { + answerResult: "789", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "890", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, "", wrapper.vm); + const duplicatedQuestion = wrapper.vm.questionsData[1].questions[2]; + const duplicatedQuestionAnswer = duplicatedQuestion.answers.filter((a) => { + return a.selected; + }); + const answerToTest = wrapper.vm.questionsData[1].questions[0].answers.filter( + (a) => { + return a.originalNextQuestionSequence; + } + ); + + // Assert + expect(answerToTest[0].originalNextQuestionSequence).toEqual( + duplicatedQuestion.questionSequence + ); + expect(answerToTest[0].nextQuestionSequence).toEqual( + duplicatedQuestionAnswer[0].nextQuestionSequence + ); + }); + + describe("and the duplicate was the first question for that part", () => { + test("then any questions up to the nextQuestionSequence value should be marked as suppressed", () => { + // Arrange + const answerNo = { + answerResult: "456", + answeredQuestions: [ + { + questionText: "Test duplicate question 1?", + selectedAnswerText: "No", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [ + { + questionSequence: 1, + questionText: "Test duplicate question 1?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [ + { + questionSequence: 1, + questionText: "Test duplicate question 1?", + answers: [ + { + answerResult: "", + answerText: "Yes", + nextQuestionSequence: 2, + }, + { + answerResult: "", + answerText: "No", + nextQuestionSequence: 3, + }, + ], + }, + { + questionSequence: 2, + questionText: "Test question 2?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "234", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + { + questionSequence: 3, + questionText: "Test question 3?", + answers: [ + { + answerResult: "345", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, "", wrapper.vm); + + // Assert + expect( + wrapper.vm.questionsData[1].questions[0].suppressThisQuestion + ).toBeTruthy(); + expect( + wrapper.vm.questionsData[1].questions[1].suppressThisQuestion + ).toBeTruthy(); + expect( + wrapper.vm.questionsData[1].questions[2].suppressThisQuestion + ).toBeFalsy(); + }); + }); + }); + + describe("and the duplicate has an answerResult", () => { + test("then any questions in the same glass piece that lead to the duplicate should be modified to just provide the duplicate's answerResult", async () => { + // Arrange + const answerNo = { + answerResult: "456", + answeredQuestions: [ + { + questionText: "Test question 3?", + selectedAnswerText: "No", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [ + { + questionSequence: 1, + questionText: "Test question 3?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [ + { + questionSequence: 1, + questionText: "Test question 1?", + answers: [ + { + answerResult: "", + answerText: "Yes", + nextQuestionSequence: 2, + }, + { + answerResult: "", + answerText: "No", + nextQuestionSequence: 3, + }, + ], + }, + { + questionSequence: 2, + questionText: "Test question 2?", + answers: [ + { + answerResult: "123", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "234", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + { + questionSequence: 3, + questionText: "Test question 3?", + answers: [ + { + answerResult: "345", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "456", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }, + ]; + + // Act + await wrapper.vm.handleAnswerUpdates(answerNo, "", wrapper.vm); + + const questionsToTest = wrapper.vm.questionsData[1].questions; + const answerLeadingToDuplicate = questionsToTest[0].answers[1]; + const duplicateQuestion = questionsToTest[2]; + const answerInDuplicateQuestion = duplicateQuestion.answers.filter((a) => { + return a.selected; + }); + + // Assert + expect(answerLeadingToDuplicate.answerResult).toEqual( + answerInDuplicateQuestion[0].answerResult + ); + expect(answerLeadingToDuplicate.originalAnswerResult).toBeFalsy(); + expect(answerLeadingToDuplicate.nextQuestionSequence).toEqual(null); + expect(answerLeadingToDuplicate.originalNextQuestionSequence).toEqual( + duplicateQuestion.questionSequence + ); + }); + }); + }); + }); + + describe("navigateForward", () => { + describe("should go to parts-questions", () => { + test("single glass location has part question => go to parts-questions", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: null, + partQuestions: [ + { + questionSequence: 1, + questionText: + "Is there a line running across the bottom, driver's side then up the center of the Windshield?", + answers: [ + { + answerText: "Yes", + nextQuestionSequence: null, + answerResult: "DW01144", + }, + { + answerText: "No", + nextQuestionSequence: null, + answerResult: "DW01143", + }, + ], + }, + ], + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + + test("multiple glass locations have part questions => go to parts-questions", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: null, + partQuestions: [ + { + questionSequence: 1, + questionText: + "Is there a line running across the bottom, driver's side then up the center of the Windshield?", + answers: [ + { + answerText: "Yes", + nextQuestionSequence: null, + answerResult: "DW01144", + }, + { + answerText: "No", + nextQuestionSequence: null, + answerResult: "DW01143", + }, + ], + }, + ], + }, + { + glassName: "Front", + glassLocation: "Driver", + parts: [ + { + partNumber: "DD08158GTYN", + description: "driver side, front", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Quarter", + glassLocation: "Driver", + parts: [ + { + partNumber: "DQ08162GTYN", + description: "driver side, 1 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "SideDoor", + glassLocation: "Driver", + parts: null, + partQuestions: [ + { + questionSequence: 2, + questionText: "Is this a super awesome question?", + answers: [ + { + answerText: "Yes", + nextQuestionSequence: null, + answerResult: "DW01144000", + }, + { + answerText: "Super yes", + nextQuestionSequence: null, + answerResult: "DW01143001", + }, + ], + }, + ], + }, + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "DB08165GTNN", + description: "heated glass, stationary", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + + test("multiple glass locations selected, one has part question => go to parts-questions", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: null, + partQuestions: [ + { + questionSequence: 1, + questionText: + "Is there a line running across the bottom, driver's side then up the center of the Windshield?", + answers: [ + { + answerText: "Yes", + nextQuestionSequence: null, + answerResult: "DW01144", + }, + { + answerText: "No", + nextQuestionSequence: null, + answerResult: "DW01143", + }, + ], + }, + ], + }, + { + glassName: "Front", + glassLocation: "Driver", + parts: [ + { + partNumber: "DD08158GTYN", + description: "driver side, front", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Quarter", + glassLocation: "Driver", + parts: [ + { + partNumber: "DQ08162GTYN", + description: "driver side, 1 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "SideDoor", + glassLocation: "Driver", + parts: [ + { + partNumber: "DD08160GTYN", + description: "driver side, body side, 1 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "DB08165GTNN", + description: "heated glass, stationary", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + + test("a selected glass location has part questions and multiple parts => go to parts-questions", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: null, + partQuestions: [ + { + questionSequence: 1, + questionText: + "Is there a line running across the bottom, driver's side then up the center of the Windshield?", + answers: [ + { + answerText: "Yes", + nextQuestionSequence: null, + answerResult: "DW01144", + }, + { + answerText: "No", + nextQuestionSequence: null, + answerResult: "DW01143", + }, + ], + }, + ], + }, + { + glassName: "Front", + glassLocation: "Driver", + parts: [ + { + partNumber: "DD08158GTYN", + description: "driver side, front", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Quarter", + glassLocation: "Driver", + parts: [ + { + partNumber: "DQ08162GTYN", + description: "driver side, 1 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DQ08162YPYN", + description: "driver side, 1 hole", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "SideDoor", + glassLocation: "Driver", + parts: [ + { + partNumber: "DD08160GTYN", + description: "driver side, body side, 1 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DD08160YPYN", + description: "driver side, body side, 1 hole", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "DB08165GTNN", + description: "heated glass, stationary", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DB08165YPNN", + description: "heated glass, stationary", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DB08166GTNN", + description: "stationary", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DB08167GTNN", + description: "heated glass, movable, 8 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DB08167YPNN", + description: "heated glass, movable, 8 hole", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + }); + + describe("should go to vehicle-parts", () => { + test("single glass location has multiple parts => go to vehicle-parts", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "FB25724GTYN", + description: "heated glass, solar, antenna", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "FB25759GTYN", + description: "heated glass, solar, antenna, w/diversity antenna", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + + test("multiple glass locations selected, one of them has multiple parts => go to vehicle parts", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: [ + { + partNumber: "FW03647GTNN", + description: "solar, 3rd visor band", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: [ + { + partNumber: "MWF03647", + partType: "MOULDING", + description: "Upper ", + }, + ], + }, + ], + partQuestions: null, + }, + { + glassName: "Back", + glassLocation: "Driver", + parts: [ + { + partNumber: "FD25747GTYN", + description: "solar, driver side, rear, ex models and above", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Front", + glassLocation: "Driver", + parts: [ + { + partNumber: "FD25719GTYN", + description: "solar, driver side, front, ex models and above", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Vent", + glassLocation: "Driver", + parts: [ + { + partNumber: "FV25749GTNN", + description: "solar, driver side, rear", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "FB25724GTYN", + description: "heated glass, solar, antenna", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "FB25759GTYN", + description: "heated glass, solar, antenna, w/diversity antenna", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + + test("multiple glass locations selected, multiple have multiple parts => go to vehicle-parts", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: [ + { + partNumber: "DW02101GTYN", + description: "solar", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Back", + glassLocation: "Driver", + parts: [ + { + partNumber: "DD12202GTYN", + description: "solar, driver side, rear", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DD12202YPYN", + description: "solar, driver side, rear", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Front", + glassLocation: "Driver", + parts: [ + { + partNumber: "DD12198GTYN", + description: "solar, driver side, front", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DD12200GTYN", + description: "solar, driver side, front, laminated, soundproofing", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Quarter", + glassLocation: "Driver", + parts: [ + { + partNumber: "DQ12204GTYNOEM", + description: "solar, driver side, encap", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DQ12204YPYNOEM", + description: "solar, driver side, encap", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DQ12205GTYNOEM", + description: "solar, antenna, driver side, encap", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DQ12205YPYNOEM", + description: "solar, antenna, driver side, encap", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DQ12207GTYN", + description: "solar, driver side, encap, chrome molding", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DQ12207YPYNOEM", + description: "solar, driver side, encap, chrome molding", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DQ12208GTYNOEM", + description: "solar, antenna, driver side, encap, chrome molding", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DQ12208YPYNOEM", + description: "solar, antenna, driver side, encap, chrome molding", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "DB12209GTYN", + description: "heated glass, solar, 1 hole", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + { + partNumber: "DB12209YPYN", + description: "heated glass, solar, 1 hole", + color: "Gray Tint Privacy", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + }); + + describe("should go to molding-questions", () => { + test("single glass location has child part questions => go to molding-questions", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "FB25724GTYN", + description: "heated glass, solar, antenna", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + 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, + }, + ], + }, + ], + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + }); + + describe("should go to capability-questions", () => { + test("single glass location has no child part questions but requiresCapabilityQuestions is true => go to capability-questions", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: [ + { + partNumber: "FB25724GTYN", + description: "heated glass, solar, antenna", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: true, + childParts: null, + childPartQuestions: null, + }, + ], + capabilityQuestions: [], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + wrapper.vm.$route, + {}, + {}, + { partsOrQuestions } + ); + }); + }); + + // TODO KO UNSKIP FOR QUOTE MVP + describe.skip("should go to quote page", () => { + test("single glass location selected, has no part questions and has one part => go to heritage funnel", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: [ + { + partNumber: "FW04186GTYN", + description: "solar, soundproofing, lane keep assist", + color: "Green Tint", + requiresRecalibration: true, + requiresCapabilityQuestions: false, + childParts: [ + { + partNumber: "GGG 3563 KIT", + partType: "MOULDING", + description: "Kit, Top & Sides ", + }, + ], + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + { query: { issPage: "vin-lookup" } } + ); + }); + + test("multiple glass locations selected, each has one part and no part questions => go to heritage funnel", async () => { + // Arrange + const partsOrQuestions = [ + { + glassName: "Single", + glassLocation: "Windshield", + parts: [ + { + partNumber: "FW04186GTYN", + description: "solar, soundproofing, lane keep assist", + color: "Green Tint", + requiresRecalibration: true, + requiresCapabilityQuestions: false, + childParts: [ + { + partNumber: "GGG 3563 KIT", + partType: "MOULDING", + description: "Kit, Top & Sides ", + }, + ], + }, + ], + partQuestions: null, + }, + { + glassName: "Back", + glassLocation: "Driver", + parts: [ + { + partNumber: "FD25457GTYN", + description: "solar, driver side, rear", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Front", + glassLocation: "Driver", + parts: [ + { + partNumber: "FD27090GTYN", + description: "solar, driver side, front", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Vent", + glassLocation: "Driver", + parts: [ + { + partNumber: "FV25459GTNN", + description: "solar, driver side, rear", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null, + }, + ], + partQuestions: null, + }, + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "FB25460GTYN", + description: "heated glass, solar", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null, + }, + ], + partQuestions: null, + }, + ]; + + const { wrapper } = setupMocks({ + partsOrQuestions: partsOrQuestions, + }); + + + // Act + await wrapper.vm.navigateForward(partsOrQuestions); + + // Assert + expect(useMainStore.updateGlassParts).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, + { query: { issPage: "vin-lookup" } } + ); + }); + }); + }); + + describe("navigateBack", () => { + + test("current page is quote and there are capability questions => go to capability questions", () => { + // Arrange + const { wrapper } = setupMocks({ issPage: issPageValues.QUOTE }); + wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true); + + // Act + wrapper.vm.navigateBack(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS, + { query: { issPage: issPageValues.QUOTE } } + ); + }); + + test("current page is quote and there are part questions and molding questions => go to molding questions", () => { + // Arrange + const { wrapper } = setupMocks({ issPage: issPageValues.QUOTE }); + wrapper.vm.hasPartQuestions = jest.fn().mockReturnValue(true); + wrapper.vm.hasChildPartQuestions = jest.fn().mockReturnValue(true); + + // Act + wrapper.vm.navigateBack(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS, + { query: { issPage: issPageValues.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({ issPage: issPageValues.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.navigateBack(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, + { query: { issPage: issPageValues.MOLDING_QUESTIONS } } + ); + }); + + test("current page is molding questions and there are part questions and capability questions => go to part-questions", () => { + // Arrange + const { wrapper } = setupMocks({ issPage: issPageValues.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.navigateBack(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, + { query: { issPage: issPageValues.MOLDING_QUESTIONS } } + ); + }); + }); +}); + +function setupMocks({ issPage = issPageValues.VIN_LOOKUP, hasVin, carId }) { + const baseMixin = setupMocksForJsFiles({ + actionList: [ + { + actionName: "getCapabilityQuestions", + data: [ + { + answers: [ + { + answerResult1: "testing", + }, + ], + }, + ], + }, + ], + }); + + const mocks = getMountOptions({ + router: { + navigate: jest.fn(), + }, + route: { + query: { + issPage, + }, + }, + }); + + const mockVehicleQuestionComponent = { + template: "
", + mixins: [vehicleQuestionsMixin, baseMixin.baseMixin], + }; + + const store = useMainStore(); + let actionResult = []; + store.getCapabilityQuestions.mockImplementation(() => Promise.resolve({data: actionResult,})); + + const wrapper = shallowMount(mockVehicleQuestionComponent, mocks); + + return { wrapper }; +} From 503e594393ccdaf8158541bf843d0dee692ec041 Mon Sep 17 00:00:00 2001 From: Kulbhushan Kaushik Date: Tue, 6 Dec 2022 10:16:59 -0500 Subject: [PATCH 10/10] commit --- .../part-questions/part-questions.spec.js | 398 ++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 src/layouts/part-questions/part-questions.spec.js diff --git a/src/layouts/part-questions/part-questions.spec.js b/src/layouts/part-questions/part-questions.spec.js new file mode 100644 index 00000000..5e2b7d47 --- /dev/null +++ b/src/layouts/part-questions/part-questions.spec.js @@ -0,0 +1,398 @@ +// Components +import partQuestions from "@/layouts/part-questions/part-questions"; + +// Supporting Files +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { useMainStore } from "@/store"; +import baseMixin from "@/mixins/base-mixin"; +import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; +import { nextTick } from "vue"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + + +const baseStoreGettersPageData = () => { + return { + partsOrQuestions: [ + { + parts: null, + partQuestions: [ + { + questionSequence: 1, + questionText: + "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + answers: [ + { + answerResult: "", + answerText: "Yes", + nextQuestionSequence: 2, + }, + { + answerResult: "", + answerText: "No", + nextQuestionSequence: 3, + }, + ], + }, + ], + glassLocation: "Windshield", + glassName: "Single", + answerKey: "Windshield-Single", + answerData: null, + }, + ], + }; +}; +const baseStoreGettersDamage = () => { + return { + partsQuestionAnswers: [ + { + glassLocation: "Windshield", + glassName: "Single", + result: "FW04848", + answeredQuestions: [ + { + questionText: + "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + { + questionText: + "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + selectedAnswerText: "Yes", + questionNum: 2, + }, + ], + }, + ], + }; +}; + +useMainStore().pageData = baseStoreGettersPageData; +useMainStore().damage = baseStoreGettersDamage; + +describe("partQuestions.vue...", () => { + describe("method arePagePrerequisitesValid...", () => { + test("Should return true for valid page requisites if pageData exists", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBe(true); + + wrapper.unmount(); + }); + + test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => { + // Arrange + const { wrapper } = setupMocks({}); + useMainStore().pageData = jest.fn(() => { + return undefined; + }); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBeFalsy(); + + wrapper.unmount(); + }); + + test("Should be at least one item in partsOrQuestions", () => { + // Arrange + useMainStore().pageData = jest.fn(() => { + return { + partsOrQuestions: [], + }; + }); + useMainStore().damage = baseStoreGettersDamage; + + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBeFalsy(); + + wrapper.unmount(); + }); + }); + + describe("watch on selectedAnswers should be set up...", () => { + test("Should trigger handleAnswerUpdates if watched data changes", async () => { + // Arrange + useMainStore().pageData = baseStoreGettersPageData; + useMainStore().damage = baseStoreGettersDamage; + + const { wrapper } = setupMocks({}); + const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates"); + + // Act + wrapper.setData({ + selectedAnswers: { + "Windshield-Single": { + answerResult: "FW04848", + answeredQuestions: [ + { + questionText: "One?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + { + questionText: "Two?", + selectedAnswerText: "Yes", + questionNum: 2, + }, + ], + index: 0, + }, + }, + }); + + await nextTick(); + + wrapper.setData({ + selectedAnswers: { + "Windshield-Single": { + answerResult: "NEW-ANSWER", + answeredQuestions: [ + { + questionText: "One?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + { + questionText: "Two?", + selectedAnswerText: "Yes", + questionNum: 2, + }, + ], + index: 0, + }, + }, + }); + + //Assert + expect(spy).toHaveBeenCalled(); + + wrapper.unmount(); + }); + }); + + describe("forwardButtonAction", () => { + test("Should clear out answerData", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + await wrapper.setData({ + questionsData: [ + { + glassLocation: "fbfWindshield", + glassName: "fbfSingle", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ], + }); + + wrapper.vm.getParts = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + + // Act + wrapper.vm.forwardButtonAction(); + + await nextTick(); + + //Assert + expect(wrapper.vm.questionsData[0].answerData).toEqual({}); + + wrapper.unmount(); + }); + + test("Should save to pinia store", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + + useMainStore().getParts = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + + // Act + wrapper.vm.forwardButtonAction(); + + await nextTick(); + + //Assert + expect(wrapper.vm.savePartQuestionAnswers).toHaveBeenCalled; + wrapper.unmount(); + }); + + test("Should call GET_PARTS API", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + useMainStore().getParts = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + + // Act + wrapper.vm.forwardButtonAction(); + + await nextTick(); + + //Assert + expect(wrapper.vm.getParts).toHaveBeenCalled; + + wrapper.unmount(); + }); + + test("Should trigger navigateForward", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + useMainStore().getParts = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + wrapper.vm.navigateForward = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + + wrapper.unmount(); + }); + }); +}); + +function setupMocks({ + mountOptionsMockData = { + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + actionList: [ + { + actionName: "savePartQuestionAnswers", + data: {}, + }, + { + actionName: "getParts", + data: {}, + }, + ], + route: { + query: { + fmgPage: "part-questions", + }, + }, + data() { + return { + computedSwitcher: [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ], + }; + }, + questionsData: { + get() { + return this.computedSwitcher; + }, + set(val) { + this.computedSwitcher = val; + }, + }, + }, +}) { + + useMainStore().getParts = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + + const mountOptions = getMountOptions({ + ...mountOptionsMockData, + mixins: [baseMixin, vehicleQuestionsMixin], + }); + mountOptions["attachTo"] = document.body; + + const wrapper = shallowMount(partQuestions, mountOptions); + + return { wrapper }; +}