diff --git a/src/constants/vehicle-selection-options.js b/src/constants/vehicle-selection-options.js new file mode 100644 index 00000000..01897ea9 --- /dev/null +++ b/src/constants/vehicle-selection-options.js @@ -0,0 +1,6 @@ +const vehicleSelectionOptions = Object.freeze({ + VEHICLE_NOT_LISTED: 'Vehicle not listed', + }); + + export {vehicleSelectionOptions}; + \ No newline at end of file diff --git a/src/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.spec.js b/src/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.spec.js new file mode 100644 index 00000000..c9efabf3 --- /dev/null +++ b/src/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.spec.js @@ -0,0 +1,33 @@ +import policyVehiclesQuestion from "@/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue"; +import { shallowMount } from "@vue/test-utils"; + + +describe("policy-vehicles-question.vue", () => { + test("Selected vehicle is emitted upon selection", async () => { + //Arrange + const vehicleToSelect = "Test1"; + const wrapper = shallowMount(policyVehiclesQuestion, { + mixins: [mockMixin], + propsData: { + vehicles: ["Test1", "Test2"] + }, + }); + + //Act + wrapper.setValue({ modelValue: vehicleToSelect }); + await wrapper.vm.$nextTick(); + + //Assert + expect(wrapper.emitted()["update:modelValue"][0]).toEqual([ + { modelValue: "Test1" }, + ]); + }); +}); + +const mockMixin = { + methods: { + getCmsContent: jest.fn(()=>{ + return [ "vehicle not listed" ]; + }) + }, +}; \ No newline at end of file diff --git a/src/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue b/src/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue index 62f2522e..6d19b5da 100644 --- a/src/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue +++ b/src/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue @@ -5,7 +5,9 @@ buttonTypeString="listButton" isOverflowScrollable :answers="answers" - isRequired /> + v-model="selectedVehicleVin" + isRequired + :validation-rules="validationRules" /> diff --git a/src/layouts/policy-vehicles/policy-vehicles.spec.js b/src/layouts/policy-vehicles/policy-vehicles.spec.js new file mode 100644 index 00000000..1d2f6875 --- /dev/null +++ b/src/layouts/policy-vehicles/policy-vehicles.spec.js @@ -0,0 +1,185 @@ +import policyVehicles from "@/layouts/policy-vehicles/policy-vehicles"; +import { settleAllPromises } from "@/helpers/layout-helper.js"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { useMainStore } from "@/store"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import {vehicleSelectionOptions} from "@/constants/vehicle-selection-options"; +import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), + doesCopyContainRouterLink: jest.fn(), + splitCopyOnCMSPlaceHolder: jest.fn().mockImplementation(() => "test"), + getRouterLinkRouteFromCopy: jest.fn(), + getRouterLinkDisplayTextFromCopy: jest.fn(), + splitCMSCopyOnParagraphTag: jest.fn(), +})); + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +describe("policy-vehicles.vue", () => { + test("Should navigate to CLICKED_BACK if backButtonAction is run", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + await wrapper.vm.backButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigate).toBeCalled(); + }); + test("Should navigate to CLICKED_BACK if backButtonAction is run", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + await wrapper.vm.backButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigate).toBeCalled(); + }); + + test("Selected vehicle VIN do match vehicles listed in our system (CarIDs) found then navigate forward to vehicle-damage page.", async () => { + //Arrange + const { wrapper } = setupMocks({}); + + // Act + await wrapper.setData({ + selectedVehicleVin: "5NMS3CADXLH233004" + }); + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE, + undefined, + {}, + {} + ); + }); + test("Selected vehicle VIN do not match vehicles listed in our system (CarIDs) found then navigate forward to bailout page.", async () => { + //Arrange + const { wrapper } = setupMocks({}); + + // Act + await wrapper.setData({ + selectedVehicleVin: "5NMS3CADXLH233004", + bailout: true + }); + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT, + undefined, + {}, + {} + ); + }); + test("if user select vehicle not listed option then navigate forward to vehicle-selection page.", async () => { + //Arrange + const { wrapper } = setupMocks({}); + + // Act + await wrapper.setData({ + selectedVehicleVin: vehicleSelectionOptions.VEHICLE_NOT_LISTED, + }); + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE, + undefined, + {}, + {} + ); + }); +}); + +function setupMocks({ + route = null, + lookupVehicleByVinResponse +}) +{ + useMainStore().applicationUser = { + pageData: { + "policy-vehicles": + [ + { + vehicleMake: "Hyundai", + vehicleModel: "Santa Fe", + vehicleStyle: "4 door utility", + vehicleYear: 2020, + vin: "5NMS3CADXLH233004", + }, + ], + } + }; + useMainStore().lookupVehicleByVin = jest.fn().mockImplementation(() => { + return Promise.resolve({ + data: lookupVehicleByVinResponse + ? lookupVehicleByVinResponse : { + vehicle: { + carId: "CARID" + }, + }, + }) + }); + const mountOptions = getMountOptions({ + route: route ? route : undefined, + router: { + navigate: jest.fn(), + }, + mainStore: { + order: { + vehicle: { + carId: "CR00069309", + category: "SUV", + imageUrl: + "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13769/13769_cc0320_032_WW8.jpg", + imageVifColor: "white", + imageVifNumber: "13769", + make: "Hyundai", + model: "Santa Fe", + style: "4 door utility", + year: 2020, + }, + vin: "5NMS3CADXLH233004", + }, + }, + }, + ); + + const apiResponses = { + cmsContent: {}, + }; + + settleAllPromises.mockImplementation(() => apiResponses); + fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + + + //Mock props + const mockMixin = { + methods: { + getCmsContent: jest.fn(), + }, + computed: { + dynamicStrings() { + return { ROUTER_LINK: "routerLink:" }; + }, + }, + }; + + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(policyVehicles,mountOptions); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + wrapper.vm.setCmsContent = jest.fn(); + wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.siteFooter.removeLoader = jest.fn(); + return { wrapper }; +} \ No newline at end of file diff --git a/src/layouts/policy-vehicles/policy-vehicles.vue b/src/layouts/policy-vehicles/policy-vehicles.vue index 73c0bcb8..a85cc583 100644 --- a/src/layouts/policy-vehicles/policy-vehicles.vue +++ b/src/layouts/policy-vehicles/policy-vehicles.vue @@ -9,7 +9,13 @@
- +
@@ -29,18 +35,25 @@ import policyVehiclesQuestion from "@/layouts/policy-vehicles/policy-vehicles-qu // Supporting files import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { settleAllPromises } from "@/helpers/layout-helper"; -import { Form,defineRule } from "vee-validate"; +import { required } from "@/helpers/validation-rules"; +import { Form, defineRule } from "vee-validate"; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { issPageValues } from "@/router/router-constants/issPage-values"; import { useMainStore } from '@/store'; import { errorMessages } from "@/constants/error-messages"; -import { required } from "@/helpers/validation-rules"; +import {vehicleSelectionOptions} from "@/constants/vehicle-selection-options"; // DEFINE VALIDATION RULES defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); export default { name: "policy-vehicles", mixins: [BaseFormMixin], + data() { + return { + selectedVehicleVin: "", + bailout: false + } + }, async beforeRouteEnter(to, from, next) { // Call APIs @@ -59,13 +72,57 @@ export default { }, methods: { - backButtonAction() { + backButtonAction() { + this.mainStore.issConfig.disabledFields.policyNumber = true; + this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route); }, - forwardButtonAction() { + async forwardButtonAction() { + if(this.selectedVehicleVin != vehicleSelectionOptions.VEHICLE_NOT_LISTED){ + const vehicleLookupResponse = await this.lookupVehicleByVin(this.selectedVehicleVin); + if (vehicleLookupResponse.error) { + this.bailout = true; + return this.navigateForward(); + } + this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, { vin: this.selectedVehicleVin }); + this.mainStore.updateVehicle(this.vehicleFromLookup); + } return this.navigateForward(); }, navigateForward() { + if(this.bailout) + this.$router.navigate( + this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT, + this.$route, + {}, + {} + ); + else if(this.selectedVehicleVin == vehicleSelectionOptions.VEHICLE_NOT_LISTED) + this.$router.navigate( + this.navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE, + this.$route, + {}, + {} + ); + else + this.$router.navigate( + this.navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE, + this.$route, + {}, + {} + ); }, + async lookupVehicleByVin(vin) { + try { + return await this.mainStore.lookupVehicleByVin(vin); + } + catch (responseError) { + return { + error: { + status: responseError.status, + }, + }; + } + }, }, computed:{ @@ -88,8 +145,8 @@ export default { }, VehiclesFromApi() { return useMainStore().pageData(issPageValues.POLICY_VEHICLES); - }, - }, + }, + }, components: { siteHeader, siteFooter, diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index cb854e26..0bf7cde1 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -21,6 +21,10 @@ const navigationScenarios = { CLICKED_FORWARD_POLICY_UNVERIFIED: "CLICKED_FORWARD_POLICY_UNVERIFIED", CLICKED_FORWARD_POLICY_VERIFIED: "CLICKED_FORWARD_POLICY_VERIFIED", + //Policy Vehicle + CLICKED_FORWARD_LISTED_VEHICLE: "CLICKED_FORWARD_LISTED_VEHICLE", + CLICKED_FORWARD_NON_LISTED_VEHICLE: "CLICKED_FORWARD_NON_LISTED_VEHICLE", + // Vehicle Damage CLICKED_FORWARD_WITH_REPAIR: 'CLICKED_FORWARD_WITH_REPAIR', @@ -52,7 +56,11 @@ const navigationScenarios = { CLICKED_FORWARD_WITH_SAFELITE: "CLICKED_FORWARD_WITH_SAFELITE", CLICKED_FORWARD_WITH_TPA_ENABLED: "CLICKED_FORWARD_WITH_TPA_ENABLED", CLICKED_FORWARD_WITH_TPA_DISABLED: "CLICKED_FORWARD_WITH_TPA_DISABLED", - CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: "CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES" + CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: "CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES", + + //Bailout + CLICKED_FORWARD_WITH_BAILOUT: "CLICKED_FORWARD_WITH_BAILOUT", + }; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 98e7294f..70ab9b0e 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -418,6 +418,27 @@ const routingTable = function(store) { } ] }, + { + issPageValue: issPageValues.POLICY_VEHICLES, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationIssPageValue: issPageValues.WELCOME_PAGE + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE, + destinationIssPageValue: issPageValues.VEHICLE_DAMAGE + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE, + destinationIssPageValue: issPageValues.VEHICLE_SELECTION + }, + { + scenario:navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT, + destinationIssPageValue: issPageValues.BAILOUT_PAGE + } + ] + }, { issPageValue: issPageValues.COVERAGE_STATEMENT, maps: [