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 }; +} 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: { 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 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..ed6732be --- /dev/null +++ b/src/layouts/vehicle-parts/vehicle-parts.spec.js @@ -0,0 +1,425 @@ +// 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(), +})); + +useMainStore().getters = { + pageData: jest.fn(), + damage: { + isRepair: false, + }, +}; + + + +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 () => { + //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", + }, + }, + useMainStore: { + getters: useMainStore().getters, + }, + }, + }); + + //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(); + }); + }); + + test("PageData / isRepair populated in Vuex. arePagePrerequisitesValid should be true ", async () => { + //Arrange + useMainStore().pageData = jest.fn(); + useMainStore().pageData.mockReturnValue(basePartResponse); + useMainStore().lineItems = { glassParts: null }; + useMainStore().damage.isRepair = false; + + 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) + ); + + 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_NO_VIN_NOR_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_NO_VIN_NOR_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 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); + + 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/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 = [], }) { 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: { diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index d06c1010..8a67d9b4 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)).data; capabilityQuestionsForGlassLocation.forEach((question) => { question.answers = question.answers.map((answer) => { @@ -434,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); } 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 }; +} diff --git a/src/store/index.js b/src/store/index.js index 2480a166..cd726469 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, @@ -96,6 +90,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( @@ -359,12 +354,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) { @@ -731,3 +752,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(",") + : []; +}