diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 4f4214120..07632f5e5 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -24,14 +24,13 @@ export function getMountOptions(mockData) { mocks.logEvent = jest.fn(); mocks.pushExperimentsToDataLayer = jest.fn(); mocks.prependActionToMethod = jest.fn(); - mocks.dispatchStoreAction = jest.fn(); mocks.dispatchStoreAction.mockImplementation((actionName) => { let actionFilterResult = mockData.actionList.filter( (x) => x.actionName == actionName ); - if (actionFilterResult.length > 0 && actionFilterResult.length === 1) { + if (actionFilterResult.length === 1) { return Promise.resolve({ data: actionFilterResult[0].data, }); diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js new file mode 100644 index 000000000..885cacf50 --- /dev/null +++ b/src/layouts/address-lookup/address-lookup.spec.js @@ -0,0 +1,505 @@ +// Components +import addressLookup from "@/layouts/address-lookup/address-lookup.vue"; +import funnelHeader from "@/common-components/funnel-header/funnel-header"; +import funnelFooter from "@/common-components/funnel-footer/funnel-footer"; +import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner"; +import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; +import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions"; +import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions"; +import router from "@/router"; + +// Supporting Files +import { settleAllPromises } from "@/helpers/layout-helper.js"; +import baseMixin from "@/mixins/base-mixin"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { mount, flushPromises, shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { maska } from 'maska'; +import { nextTick } from "vue"; +import { storeActions } from "@/constants/store-actions"; +import { storeMutations } from "@/constants/store-mutations"; +import store from "@/store"; +import { validate } from "vee-validate"; +import { isGlassAvailableForCarId } from "@/helpers/damage-helper.js" +import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; +import { EXPECTATION_FAILED } from "http-status-codes"; + +// 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(), +// })); + +jest.mock("@/helpers/damage-helper", () => ({ + isGlassAvailableForCarId: jest.fn().mockImplementation(() => true), + getDamageString: jest.fn() +})); + +jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({ + navigateAfterSaveToHeritageFunnel: jest.fn() +})); + + +// const questionText = "Question Text"; +// const mockMixin = { +// methods: { +// getCmsContent: jest.fn().mockImplementation(() => { +// return questionText; +// }) +// } +// } + +describe("address-lookup.vue", () => { + describe("registration and service zips", () => { + describe("if registration zip is serviceable", () => { + test("if registration address is provided => update service address on successful continue", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup,{ + isZipServiceable: true + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION); + }); + }); + + describe("if registration zip is not serviceable", () => { + test("if registration address is provided and user clicks continue => show non-serviceable zip alert", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup, { + isZipServiceable: false + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(false); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.displayNonServiceableZipAlert).toBe(true); + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(true); + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true); + }); + + test("if registration address is provided user clicks continue => show service zip field on continue click", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup, { + isZipServiceable: false + } + ); + + expect(wrapper.vm.showServiceZipField).toBeFalsy(); + expect(wrapper.findComponent({ ref: "serviceZip" }).exists()).toBe(false); + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.showServiceZipField).toBe(true); + expect(wrapper.findComponent({ ref: "serviceZip" }).isVisible()).toBe(true); + }); + + test("if registration address, service zip are provided, and user clicks continue => don't update service address", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup, { + isZipServiceable: false + } + ); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION); + }); + + test("if registration address, service zip are provided, and user clicks continue => both zips are saved and are different", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup, {}); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + baseMixin.methods.dispatchStoreAction = jest.fn(); + baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => { + let data = {}; + if (actionName == storeActions.VALIDATE_ZIP) { + if (value == "43215") { + data = { + isServiceable: false + }; + } + else { + data = { + isServiceable: true + } + } + } + else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) { + data = { + isStatePermissible: true, + vinVehicles: [{ + vin: "TEST_VIN", + vehicle: { + carId: "CARID" + } + }] + } + } + + return Promise.resolve({ data }); + }) + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + await wrapper.vm.forwardButtonAction(); + await wrapper.setData({ + serviceZipCode: "12345" + }) + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(store.getters.order.serviceLocation.zipCode).not.toEqual(store.getters.vehicle.registration.zipCode); + expect(store.getters.vehicle.registration.zipCode).toEqual("43215"); + expect(store.getters.order.serviceLocation.zipCode).toEqual("12345"); + }); + }); + }); + + describe.skip("initialization", () => { + test("Page header is initialized with api data", async (done) => { + //Arrange + const pageHeaderWidgetHeaderText = "Select Damage"; + const { wrapper, apiPromise } = setupMocks({ + pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText, + }); + + //Act + addressLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "address-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + //Assert + apiPromise.finally(() => { + expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith( + pageHeaderWidgetHeaderText + ); + done(); + }); + }); + + test("Customer Questions component is initialized with api data", async (done) => { + //Arrange + const StreetAddressQuestionWidget = { QuestionText: "test" }; + const CityQuestionWidget = { QuestionText: "test" }; + const StateQuestionWidget = { QuestionText: "test" }; + const ZipQuestionWidget = { QuestionText: "test" }; + const FirstNameQuestionWidget = { QuestionText: "test" }; + const LastNameQuestionWidget = { QuestionText: "test" }; + const EmailAddressQuestionWidget = { QuestionText: "test" }; + const AlertVerificationWarningWidget = { HeaderText: "test", BodyText: "test" }; + const AlertNoMatchWarningWidget = { HeaderText: "test", BodyText: "test" }; + + const widgets = [ + StreetAddressQuestionWidget, + CityQuestionWidget, + StateQuestionWidget, + ZipQuestionWidget, + AlertVerificationWarningWidget, + AlertNoMatchWarningWidget, + FirstNameQuestionWidget, + LastNameQuestionWidget, + EmailAddressQuestionWidget, + ]; + + const { wrapper, apiPromise } = setupMocks({ + cmsContent: widgets, + }); + + //Act + addressLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "address-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + //Assert + apiPromise.finally(() => { + expect(customerQuestions.methods.initializeComponent).toHaveBeenCalledWith( + widgets + ); + done(); + }); + }); + }); +}); + +function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressResponse }) { + store.commit(storeMutations.RESET_STATE); + console.log(isZipServiceable) + const wrapper = shallowMount(addressLookup, getMountOptions({ + ...mountOptions, + actionList: [ + { + actionName: storeActions.VALIDATE_ZIP, + data: { + isServiceable: isZipServiceable + } + }, + { + actionName: storeActions.LOOKUP_VIN_BY_ADDRESS, + data: lookupVinbyAddressResponse ? lookupVinbyAddressResponse : { + isStatePermissible: true, + vinVehicles: [{ + vin: "TEST_VIN", + vehicle: { + carId: "CARID" + } + }] + } + } + ], + router: { + navigate: jest.fn(), + navigateAfterSave: jest.fn() + }, + })); + + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); + wrapper.vm.$refs.loadingModal.showModal = jest.fn(); + + // jest.mock("@/store", () => ({ + // commit: jest.fn(), + // dispatch: jest.fn(), + // getters: { + // vehicle: { + // carId: "CARID" + // } + // }, + // })); + + return { wrapper }; +} + +// function setupMocks({ +// pageHeaderWidgetHeaderText = {}, +// mountOptionsMockData = { +// router: { +// navigate: jest.fn(), +// }, +// store: { +// getters: { +// vehicle: {}, +// }, +// }, +// }, +// }) { +// //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", +// }, +// StreetAddressQuestionWidget: { +// QuestionText: +// "test" +// }, +// CityQuestionWidget: { +// QuestionText: +// "test" +// }, +// StateQuestionWidget: { +// QuestionText: +// "test" +// }, +// ZipQuestionWidget: { +// QuestionText: +// "test" +// }, +// FirstNameQuestionWidget: { +// QuestionText: +// "test" +// }, +// LastNameQuestionWidget: { +// QuestionText: +// "test" +// }, +// EmailAddressQuestionWidget: { +// QuestionText: +// "test" +// }, +// AlertVerificationWarningWidget: { +// HeaderText: +// "test", +// BodyText: +// "test", +// }, +// AlertNoMatchWarningWidget: { +// HeaderText: +// "test", +// BodyText: +// "test", +// }, + +// }, +// }; + +// const apiPromise = Promise.resolve(apiResponses); + +// settleAllPromises.mockImplementation(() => apiPromise); +// fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + +// //Mock damage initialize methods +// funnelHeader.methods = { +// initializeComponent: jest.fn(), +// }; + +// vehicleBanner.methods = { +// initializeComponent: jest.fn(), +// }; + +// funnelSubHeader.methods = { +// initializeComponent: jest.fn(), +// }; + +// funnelFooter.methods = { +// initializeComponent: jest.fn(), +// }; + +// customerQuestions.methods = { +// initializeComponent: jest.fn(), +// }; + +// addressQuestions.methods = { +// initializeComponent: jest.fn(), +// setupAddressLookup: jest.fn(), +// }; + +// const mountOptions = getMountOptions(mountOptionsMockData); +// mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods + +// mountOptions.global.directives = { +// maska: maska +// }; + +// const wrapper = mount(addressLookup, mountOptions); + +// const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" }); +// funnelHeaderWrapper.vm.initializeComponent = +// funnelHeader.methods.initializeComponent; + +// const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" }); +// vehicleBannerWrapper.vm.initializeComponent = +// vehicleBanner.methods.initializeComponent; + +// const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" }); +// funnelSubHeaderWrapper.vm.initializeComponent = +// funnelSubHeader.methods.initializeComponent; + +// const funnelFooterWrapper = wrapper.findComponent({ name: "funnelFooter" }); +// funnelFooterWrapper.vm.initializeComponent = +// funnelFooter.methods.initializeComponent; + +// const customerQuestionsWrapper = wrapper.findComponent({ name: "customerQuestions" }); +// customerQuestionsWrapper.vm.initializeComponent = +// customerQuestions.methods.initializeComponent; + +// const addressQuestionsWrapper = wrapper.findComponent({ name: "addressQuestions" }); +// addressQuestionsWrapper.vm.initializeComponent = +// addressQuestions.methods.initializeComponent; +// addressQuestionsWrapper.vm.setupAddressLookup = +// addressQuestions.methods.setupAddressLookup; + +// return { wrapper, apiPromise }; +// } \ No newline at end of file diff --git a/src/layouts/address-lookup/address-lookup.spec.js1 b/src/layouts/address-lookup/address-lookup.spec.js1 deleted file mode 100644 index 4443100c3..000000000 --- a/src/layouts/address-lookup/address-lookup.spec.js1 +++ /dev/null @@ -1,244 +0,0 @@ -// Components -import addressLookup from "@/layouts/address-lookup/address-lookup.vue"; -import funnelHeader from "@/common-components/funnel-header/funnel-header"; -import funnelFooter from "@/common-components/funnel-footer/funnel-footer"; -import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner"; -import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; -import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions"; -import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions"; - -// Supporting Files -import { settleAllPromises } from "@/helpers/layout-helper.js"; -import baseMixin from "@/mixins/base-mixin"; -import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; -import { mount, flushPromises } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import { maska } from 'maska'; -import { nextTick } from "vue"; -import { storeActions } from "@/constants/store-actions"; -import { storeMutations } from "@/constants/store-mutations"; -import store from "@/store"; -import { validate } from "vee-validate"; - -// 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(), -})); - -describe("address-lookup.vue", () => { - test("Page header is initialized with api data", async (done) => { - //Arrange - const pageHeaderWidgetHeaderText = "Select Damage"; - const { wrapper, apiPromise } = setupMocks({ - pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText, - }); - - //Act - addressLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "address-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - //Assert - apiPromise.finally(() => { - expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith( - pageHeaderWidgetHeaderText - ); - done(); - }); - }); - - test("Customer Questions component is initialized with api data", async (done) => { - //Arrange - const StreetAddressQuestionWidget = { QuestionText: "test" }; - const CityQuestionWidget = { QuestionText: "test" }; - const StateQuestionWidget = { QuestionText: "test" }; - const ZipQuestionWidget = { QuestionText: "test" }; - const FirstNameQuestionWidget = { QuestionText: "test" }; - const LastNameQuestionWidget = { QuestionText: "test" }; - const EmailAddressQuestionWidget = { QuestionText: "test" }; - const AlertVerificationWarningWidget = { HeaderText: "test", BodyText: "test" }; - const AlertNoMatchWarningWidget = { HeaderText: "test", BodyText: "test" }; - - const widgets = [ - StreetAddressQuestionWidget, - CityQuestionWidget, - StateQuestionWidget, - ZipQuestionWidget, - AlertVerificationWarningWidget, - AlertNoMatchWarningWidget, - FirstNameQuestionWidget, - LastNameQuestionWidget, - EmailAddressQuestionWidget, - ]; - - const { wrapper, apiPromise } = setupMocks({ - cmsContent: widgets, - }); - - //Act - addressLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "address-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - //Assert - apiPromise.finally(() => { - expect(customerQuestions.methods.initializeComponent).toHaveBeenCalledWith( - widgets - ); - done(); - }); - }); - - }); - - - - function setupMocks({ - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = { - router: { - navigate: jest.fn(), - }, - store: { - getters: { - vehicle: {}, - }, - }, - }, - }) { - //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", - }, - StreetAddressQuestionWidget: { - QuestionText: - "test" - }, - CityQuestionWidget: { - QuestionText: - "test" - }, - StateQuestionWidget: { - QuestionText: - "test" - }, - ZipQuestionWidget: { - QuestionText: - "test" - }, - FirstNameQuestionWidget: { - QuestionText: - "test" - }, - LastNameQuestionWidget: { - QuestionText: - "test" - }, - EmailAddressQuestionWidget: { - QuestionText: - "test" - }, - AlertVerificationWarningWidget: { - HeaderText: - "test", - BodyText: - "test", - }, - AlertNoMatchWarningWidget: { - HeaderText: - "test", - BodyText: - "test", - }, - - }, - }; - - const apiPromise = Promise.resolve(apiResponses); - - settleAllPromises.mockImplementation(() => apiPromise); - fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - - //Mock damage initialize methods - funnelHeader.methods = { - initializeComponent: jest.fn(), - }; - - vehicleBanner.methods = { - initializeComponent: jest.fn(), - }; - - funnelSubHeader.methods = { - initializeComponent: jest.fn(), - }; - - funnelFooter.methods = { - initializeComponent: jest.fn(), - }; - - customerQuestions.methods = { - initializeComponent: jest.fn(), - }; - - addressQuestions.methods = { - initializeComponent: jest.fn(), - setupAddressLookup: jest.fn(), - }; - - const mountOptions = getMountOptions(mountOptionsMockData); - mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods - - mountOptions.global.directives = { - maska: maska - }; - - const wrapper = mount(addressLookup, mountOptions); - - const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" }); - funnelHeaderWrapper.vm.initializeComponent = - funnelHeader.methods.initializeComponent; - - const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" }); - vehicleBannerWrapper.vm.initializeComponent = - vehicleBanner.methods.initializeComponent; - - const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" }); - funnelSubHeaderWrapper.vm.initializeComponent = - funnelSubHeader.methods.initializeComponent; - - const funnelFooterWrapper = wrapper.findComponent({ name: "funnelFooter" }); - funnelFooterWrapper.vm.initializeComponent = - funnelFooter.methods.initializeComponent; - - const customerQuestionsWrapper = wrapper.findComponent({ name: "customerQuestions" }); - customerQuestionsWrapper.vm.initializeComponent = - customerQuestions.methods.initializeComponent; - - const addressQuestionsWrapper = wrapper.findComponent({ name: "addressQuestions" }); - addressQuestionsWrapper.vm.initializeComponent = - addressQuestions.methods.initializeComponent; - addressQuestionsWrapper.vm.setupAddressLookup = - addressQuestions.methods.setupAddressLookup; - - return { wrapper, apiPromise }; - } \ No newline at end of file diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index f29e3d21a..02946177e 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -1,67 +1,101 @@