// Components import vehicleDamage from "@/layouts/vehicle-damage/vehicle-damage.vue"; import sideDoorOptions from "@/layouts/vehicle-damage/side-door-options/side-door-options"; import damageLocationQuestion from "@/layouts/vehicle-damage/damage-location-question/damage-location-question"; import windshieldOptions from "@/layouts/vehicle-damage/windshield-options/windshield-options"; import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question"; // Supporting Files import { settleAllPromises } from "@/helpers/layout-helper.js"; import baseMixin from "@/mixins/base-mixin"; 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 { storeActions } from "@/constants/store-actions"; import store from "@/store"; import { validate } from "vee-validate"; import { damageLocationsSelected } from "@/constants/damage-locations-selected.js"; import { routerParams } from "@/router/router-constants/router-params"; import * as cookieHelper from "@/helpers/heritage-integration/cookie-helper"; // 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(), })); // Mock getFunnelCookie jest.mock("@/helpers/heritage-integration/cookie-helper", () => ({ getFunnelCookie: jest.fn(), })); // Mock Store jest.mock("@/store", () => ({ commit: jest.fn(), dispatch: jest.fn(), getters: { vehicle: { carId: "C00000000", image: "test.jpg", payment: { insuranceCoverage: { isVerified: false, }, }, }, eventBusItem: jest.fn(), damage: { glassToReplace: [], }, }, })); describe("vehicle-damage.vue", () => { describe("navigation", () => { test("BackButtonAction triggers a router.navigateWithoutSaving change", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); wrapper.vm.backButtonAction(); //Assert expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); }); test("Replace several pieces of glass on ForwardButtonAction triggers a router.navigate and saves selections to store", async () => { //Arrange const partsData = { partsOrQuestions: [ { glassName: "Single", glassLocation: "Windshield", parts: null, partQuestions: [ { questionSequence: 1, questionText: "Is your vehicle equipped with a heated steering wheel?", answers: [ { answerText: "Yes", nextQuestionSequence: null, answerResult: "FW04957", }, { answerText: "No", nextQuestionSequence: 2, answerResult: "", }, ], }, { questionSequence: 2, questionText: "Is your vehicle equipped with a remote start?", answers: [ { answerText: "Yes", nextQuestionSequence: null, answerResult: "FW04181", }, { answerText: "No", nextQuestionSequence: null, answerResult: "FW04179", }, ], }, ], }, ], }; const { wrapper } = setupMocks({ pageHeaderWidgetHeaderText: "", mountOptionsMockData: { router: { navigate: jest.fn(), navigateWithSaving: jest.fn() }, actionList: [ { actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData }, ], store: { getters: { vehicle: {}, payment: { insuranceCoverage: { isVerified: false } }, }, }, }, }); wrapper.setData({ selectedDamageLocations: ["Windshield", "SideDoor", "RearWindow"], selectedWindshieldOptions: { selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: ["Single"], selectedWindshieldDamageType: "Replace", }, sideDoorOptionsData: { selectedDoorSides: ["DriverSide", "PassengerSide"], selectedDriverSideReplaceOptions: ["Back"], selectedPassengerSideReplaceOptions: ["Quarter"], }, selectedRearReplaceOptions: "Stationary", }); const expectedGlassToReplace = [ { glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" }, { glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }, ]; //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); await wrapper.vm.forwardButtonAction(); //Assert expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace); expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith( storeActions.GET_DAMAGE_OPTIONS, { carId: "C00000000" } ); }); test("Windshield replace with multiple parts on ForwardButtonAction triggers a router.navigate and saves selections to store", async () => { //Arrange const partsData = { partsOrQuestions: [ { glassLocation: "Windshield", glassName: "Single", partQuestions: null, parts: [ { color: "Green Tint, Green Shade", description: "rain sensor, solar", partNumber: "FW02728GGYN", requiresCapabilityQuestions: false, requiresRecalibration: false, }, { color: "Green Tint, Green Shade", description: "rain sensor, solar, hydrophobic coating", partNumber: "FW02760GGYN", requiresCapabilityQuestions: false, requiresRecalibration: false, }, ], }, { glassName: "Stationary", glassLocation: "Rear", parts: [ { partNumber: "DB09626GTYN", description: "heated glass, solar, antenna", color: "Green Tint", requiresRecalibration: false, requiresCapabilityQuestions: false, childParts: null, }, { partNumber: "DB09821GTYN", description: "heated glass, solar, antenna, onstar", color: "Green Tint", requiresRecalibration: false, requiresCapabilityQuestions: false, childParts: null, }, ], partQuestions: null, }, ], }; const { wrapper } = setupMocks({ pageHeaderWidgetHeaderText: "", mountOptionsMockData: { router: { navigate: jest.fn(), navigateWithSaving: jest.fn() }, actionList: [ { actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData }, ], store: { getters: { vehicle: {}, payment: { insuranceCoverage: { isVerified: false } }, }, }, }, }); wrapper.vm.selectedDamageLocations = ["Windshield"]; wrapper.vm.selectedWindshieldOptions = { selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: ["Single"], selectedWindshieldDamageType: "Replace", }; const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }]; //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); await wrapper.vm.forwardButtonAction(); //Assert expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace); expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith( storeActions.GET_DAMAGE_OPTIONS, { carId: "C00000000" } ); }); }); describe("alert", () => { test("when displayVehicleChangeAlert router params is true, the alert: 'vehicleChangeAlert' should be rendered", () => { // Arrange & Act const { wrapper } = setupMocks({ mountOptionsMockData: { route: { params: { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true, }, }, }, }); // Assert expect(wrapper.findComponent({ ref: "vehicleChangeAlert" }).exists()).toBe(true); }); test("when displayVehicleChangeAlert router params is false, the alert: 'vehicleChangeAlert' should not be rendered", () => { // Arrange & Act const { wrapper } = setupMocks({ mountOptionsMockData: { route: { params: { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false, }, }, }, }); // Assert expect(wrapper.findComponent({ ref: "vehicleChangeAlert" }).exists()).toBe(false); }); test("when displayVehicleChangeAlert router params is undefined, the alert: 'vehicleChangeAlert' should not be rendered", () => { // Arrange & Act const { wrapper } = setupMocks({ mountOptionsMockData: { route: { params: { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: undefined, }, }, }, }); // Assert expect(wrapper.findComponent({ ref: "vehicleChangeAlert" }).exists()).toBe(false); }); }); describe("glass selections and corresponding variables", () => { test("isWindshieldDamageLocation is true when windshield is selected", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); wrapper.vm.selectedDamageLocations = ["Windshield"]; //Assert expect(wrapper.vm.isWindshieldDamageLocation).toEqual(true); }); test("isSideDoorDamageLocation is true Side door is selected", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); wrapper.vm.selectedDamageLocations = ["Sidedoor"]; //Assert expect(wrapper.vm.isSideDoorDamageLocation).toEqual(true); }); test("isRearWindowDamageLocation is true if Rear Window damage is selected", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); wrapper.vm.selectedDamageLocations = ["RearWindow"]; //Assert expect(wrapper.vm.isRearWindowDamageLocation).toEqual(true); }); test("isWindshieldRepair is true if windshield repair is selected", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); wrapper.vm.selectedDamageLocations = ["Windshield"]; wrapper.vm.selectedWindshieldOptions = { selectedWindshieldDamageType: "Repair" }; //Assert expect(wrapper.vm.isWindshieldRepair).toEqual(true); }); test("isWindshieldRepair is false if windshield damage is not selected", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); wrapper.vm.selectedDamageLocations = ["SideDoor"]; wrapper.vm.selectedWindshieldOptions = { selectedWindshieldDamageType: "Repair" }; //Assert expect(wrapper.vm.isWindshieldRepair).toEqual(false); }); test("isDriverSideReplace is true if side door driver is selected", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); wrapper.vm.selectedDamageLocations = ["Sidedoor"]; wrapper.vm.sideDoorOptionsData = { selectedDoorSides: ["DriverSide"] }; //Assert expect(wrapper.vm.isDriverSideReplace).toEqual(true); }); test("isPassengerSideReplace is true if side door passenger selected", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); wrapper.vm.selectedDamageLocations = ["Sidedoor"]; wrapper.vm.sideDoorOptionsData = { selectedDoorSides: ["PassengerSide"] }; //Assert expect(wrapper.vm.isPassengerSideReplace).toEqual(true); }); }); describe("state validations", () => { test("CarId set, arePagePrerequisitesValid should be true ", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); await nextTick(); //Assert expect(arePagePrerequisitesValid).toBe(true); }); }); describe("input validations", () => { // THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE // BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST test("when validation rules are set they should validate correctly", async () => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); const testNull = validate("", "replace-options-required"); const testString = validate("sldfj", "replace-options-required"); //Assert testNull.then(function (data) { expect(data.valid).toEqual(false); }); testString.then(function (data) { expect(data.valid).toEqual(true); }); }); }); describe("get glass options from store", () => { const damageLocations = [ ["Windshield", [damageLocationsSelected.WINDSHIELD]], ["Driver", [damageLocationsSelected.SIDEDOOR]], ["Passenger", [damageLocationsSelected.SIDEDOOR]], ["Rear", [damageLocationsSelected.REARWINDOW]], ]; test.each(damageLocations)( "getDamageLocationsFromStore for %s returns expected %s", async (damageLocation, expectedGlass) => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation }] }, isRepair: true, }; var glassSelections = wrapper.vm.getDamageLocationsFromStore(); //Assert expect(glassSelections).toEqual(expectedGlass); } ); const storeWindshieldOptions = [ [ 1, false, "Windshield", "Single", { selectedWindshieldDamageType: damageLocationsSelected.REPLACE, selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.SINGLE], }, ], [ 2, false, "Windshield", "Driver", { selectedWindshieldDamageType: damageLocationsSelected.REPLACE, selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.DRIVER], }, ], [ 3, false, "Windshield", "Passenger", { selectedWindshieldDamageType: damageLocationsSelected.REPLACE, selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.PASSENGER], }, ], [ 4, true, "", "", { selectedWindshieldDamageType: damageLocationsSelected.REPAIR, selectedWindshieldChipCount: 2, selectedWindshieldReplaceOptions: [], }, ], ]; test.each(storeWindshieldOptions)( "getWindshieldOptionsFromStore test #%s", async (testNum, isRepair, damageLocation, damageName, expectedWindshieldOptions) => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }], isRepair: isRepair, numberOfChips: 2, }, }; var windshieldSelections = wrapper.vm.getWindshieldOptionsFromStore(); //Assert expect(windshieldSelections).toEqual(expectedWindshieldOptions); } ); const driverDoorSides = [ ["Driver", "Front", [damageLocationsSelected.FRONT]], ["Driver", "Back", [damageLocationsSelected.BACK]], ["Driver", "Vent", [damageLocationsSelected.VENT]], ["Driver", "Quarter", [damageLocationsSelected.QUARTER]], ]; test.each(driverDoorSides)( "getDriverSideReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }], }, isRepair: true, }; var glassSelections = wrapper.vm.getDriverSideReplaceOptionsFromStore(); //Assert expect(glassSelections).toEqual(expectedGlass); } ); const passengerDoorSides = [ ["Passenger", "Front", [damageLocationsSelected.FRONT]], ["Passenger", "Back", [damageLocationsSelected.BACK]], ["Passenger", "Vent", [damageLocationsSelected.VENT]], ["Passenger", "Quarter", [damageLocationsSelected.QUARTER]], ]; test.each(passengerDoorSides)( "getPassengerSideReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }], }, isRepair: true, }; var glassSelections = wrapper.vm.getPassengerSideReplaceOptionsFromStore(); //Assert expect(glassSelections).toEqual(expectedGlass); } ); const rearReplaceOptions = [ ["Rear", "Stationary", damageLocationsSelected.STATIONARY], ["Rear", "Slider", damageLocationsSelected.SLIDER], ]; test.each(rearReplaceOptions)( "getRearReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { //Arrange const { wrapper } = setupMocks({}); //Act vehicleDamage.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm) ); store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }], }, isRepair: true, }; var glassSelections = wrapper.vm.getRearReplaceOptionsFromStore(); //Assert expect(glassSelections).toEqual(expectedGlass); } ); }); describe("hide back button", () => { test("if claim registration is delayed => should hide back button", () => { // Arrange const { wrapper } = setupMocks({ funnelCookie: { HasDelayedClaimRegistration: true, }, }); // Assert expect(wrapper.vm.shouldHideBackButton).toBe(true); }); test("if claim is verified => should hide back button", () => { // Arrange const { wrapper } = setupMocks({ mountOptionsMockData: { router: { navigate: jest.fn() }, actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: {} }], store: { getters: { vehicle: {}, payment: { insuranceCoverage: { isVerified: true } }, }, }, }, }); // Assert expect(wrapper.vm.shouldHideBackButton).toBe(true); }); test("if claim isn't verified yet => allow user to go back", () => { // Arrange const { wrapper } = setupMocks({}); // Assert expect(wrapper.vm.shouldHideBackButton).toBeFalsy(); }); }); }); function setupMocks({ pageHeaderWidgetHeaderText, mountOptionsMockData, funnelCookie = {} }) { var pageHeaderWidgetHeaderTextDefault = {}; var mountOptionsMockDataDefault = { router: { navigate: jest.fn(), navigateWithoutSaving: jest.fn(), navigateWithSaving: jest.fn(), }, route: { params: { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false, }, }, store: { getters: { vehicle: {}, payment: { insuranceCoverage: { isVerified: false, }, }, }, }, }; // Combine parameters with default values pageHeaderWidgetHeaderText = Object.assign( pageHeaderWidgetHeaderTextDefault, pageHeaderWidgetHeaderText ); mountOptionsMockData = Object.assign(mountOptionsMockDataDefault, mountOptionsMockData); //Mock api responses baseMixin.methods.dispatchStoreAction = jest.fn(); const apiResponses = { cmsContent: { FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, VehicleBannerWidget: { GenericVehicleImage: "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", }, FunnelHeaderWidget: { LogoImage: "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", }, }, damageOptions: { driverSideOptions: { availableReplacementOptions: ["Front", "Back", "Side"], }, passengerSideOptions: { availableReplacementOptions: ["Front", "Back", "Side"], }, windshieldOptions: { availableReplacementOptions: ["Single", "Driver", "Passenger"], }, backGlassOptions: { availableReplacementOptions: ["Front", "Back", "Side"], }, }, }; const apiPromise = Promise.resolve(apiResponses); settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); cookieHelper.getFunnelCookie = jest .spyOn(cookieHelper, "getFunnelCookie") .mockReturnValue(funnelCookie); //Mock damage initialize methods damageLocationQuestion.methods = { initializeComponent: jest.fn(), }; sideDoorOptions.methods = { initializeComponent: jest.fn(), }; windshieldOptions.methods = { initializeComponent: jest.fn(), }; replaceOptionsQuestion.methods = { initializeComponent: jest.fn(), updateSelectedValues: jest.fn(), }; const mountOptions = getMountOptions(mountOptionsMockData); mountOptions["attachTo"] = document.body; // append wrapper to document.body to test DOM methods const wrapper = shallowMount(vehicleDamage, mountOptions); const sideDoorOptionsWrapper = wrapper.findComponent({ name: "sideDoorOptions" }); sideDoorOptionsWrapper.vm.initializeComponent = sideDoorOptions.methods.initializeComponent; const windshieldOptionsWrapper = wrapper.findComponent({ name: "windshieldOptions" }); windshieldOptionsWrapper.vm.initializeComponent = windshieldOptions.methods.initializeComponent; const backGlassOptionsWrapper = wrapper.findComponent({ name: "replaceOptionsQuestion" }); backGlassOptionsWrapper.vm.initializeComponent = replaceOptionsQuestion.methods.initializeComponent; const damageLocationQuestionWrapper = wrapper.findComponent({ name: "damageLocationQuestion" }); damageLocationQuestionWrapper.vm.initializeComponent = damageLocationQuestion.methods.initializeComponent; wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; return { wrapper, apiPromise }; }