diff --git a/jest.config.js b/jest.config.js index 052e1c47b..ce4aa3ad6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -27,7 +27,6 @@ module.exports = { "!src/layouts/insurance/*.vue", // Temp test exclusion while in development "!src/layouts/insurance-company/*.vue", // Temp test exclusion while in development "!src/layouts/insurance-company/insurance-company-question/*.vue", // Temp test exclusion while in development - "!src/layouts/return-user/*.vue", // Temp test exclusion while in development // END ], // ! means exclude from coverage. testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], diff --git a/src/layouts/return-user/return-user.spec.js b/src/layouts/return-user/return-user.spec.js new file mode 100644 index 000000000..dc631ce62 --- /dev/null +++ b/src/layouts/return-user/return-user.spec.js @@ -0,0 +1,312 @@ +// Components +import returnUser from "@/layouts/return-user/return-user.vue"; + +// Supporting Files +import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; +import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper"; +import baseMixin from "@/mixins/base-mixin.js"; +import { dispatchStoreAction } from "@/mixins/base-mixin.js"; +import store from "@/store"; +import router from "@/router"; +import navbar from "@/fmg-components/nav-bar/nav-bar"; +import { Form } from "vee-validate"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; +import { settleAllPromises } from "@/helpers/layout-helper"; +import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; +import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; +import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; + +import { experimentSettings } from "../../constants/experiments"; +import { storeActions } from "@/constants/store-actions"; +import buttonMain from "@/ux-components/button-main/button-main"; + +// Constants + +// Setup global mocks +let mockStoreActionData = {}; + +let mockStoreData = {}; +let mockExperimentSettings = { + experiments: [ + { + universeName: "ConceptFunnel", + settings: { + SuppressVinCapture: false, + }, + }, + ], +}; + +function resetMockStoreData() { + mockStoreData = { + vehicle: { + year: "2000", + make: "TestMake", + model: "TestModel", + style: "TestStyle", + carId: "TestID", + vin: null, + registration: { + licensePlate: null, + }, + }, + serviceLocation: { + address: null, + address2: null, + city: null, + state: null, + zipCode: null, + zipCodeCtu: null, + appointmentType: null, + isVehicleProtected: null, + provider: { + providerNumber: null, + address: { + streetAddress: null, + city: null, + state: null, + zipCode: null, + zipCodeCtu: null, + }, + }, + techNotes: null, + }, + customer: { + firstName: null, + lastName: null, + emailAddress: null, + phoneNumber: null, + isSmsOptIn: null, + }, + damage: { + isRepair: false, + numberOfChips: null, + glassToReplace: [{ glassLocation: "Windshield", glassName: "windshield" }], + partQuestionAnswers: null, + moldingQuestionAnswers: null, + capabilityQuestionAnswers: null, + dateOfLoss: null, + damageCause: null, + }, + lineItems: { + glassParts: [ + { + canSafeliteRecalibrate: true, + childParts: [ + { + kitPrice: 0, + laborAmount: 23.55, + partNumber: "GGG FW4896", + salesTax: 1.77, + sellingPrice: 0, + }, + ], + color: "Green Tint", + description: + "solar, soundproofing, lane keep assist, lane departure warning system, w/adaptive cruise control", + id: "db22fd44-10dd-456f-979b-ff88cf68cca6", + kitPrice: 0, + laborAmount: 60, + partNumber: "FW04896GTYN", + partType: "WINDSHIELD", + recalibrationType: "STATIC", + requiresCapabilityQuestions: false, + requiresRecalibration: true, + salesTax: 63.86, + sellingPrice: 791.46, + }, + ], + supportingItems: null, + vaps: null, + serverData: null, + promos: null, + }, + payment: { + isInsurance: null, + insuranceCoverage: { + isVerified: null, + coverageStatus: null, + coverageType: null, + coverageVerificationType: null, + }, + parentAccountNumber: 0, + billToAccountNumber: null, + isPia: null, + piaType: null, + inactivePromos: null, + paypalToken: null, + nextGenSettledAmount: 0, + ccToken: { + subscriptionId: null, + expMonth: null, + expYear: null, + cardType: null, + billToPostalCode: null, + billToFirstName: null, + billToLastName: null, + referenceNumber: null, + authCode: null, + transactionId: null, + transReferenceNumber: null, + lastFour: null, + }, + }, + policy: { + currentDeductible: 0, + policyNumber: null, + isItac: false, + additionalAuthFlag: null, + isNoComp: false, + insuranceCompanyName: null, + }, + schedule: { + date: null, + startTime: null, + endTime: null, + routeCode: null, + jobMaxMinutes: null, + jobMinMinutes: null, + }, + externalParameterServiceZip: { + zipCode: null, + emailAddress: null, + }, + externalParameterState: { isExternalParameter: false }, + }; +} + +function applyMockStoreDataToGetters() { + store.getters = { + vehicle: mockStoreData.vehicle, + }; + store.state.order = mockStoreData; + store.state.applicationUser.experiments = mockExperimentSettings; +} + +async function mockDispatchStoreAction(actionName) { + return mockStoreActionData[actionName]; +} + +jest.mock("@/mixins/base-mixin.js", () => ({ + methods: { + dispatchStoreAction: jest.fn(), + dispatchStoreActionWithLogging: jest.fn().mockImplementation(mockDispatchStoreAction), + }, +})); + +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: () => Promise.resolve("content"), +})); + +jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({ + saveSession: jest.fn(), +})); + +jest.mock("@/helpers/heritage-integration/cookie-helper", () => ({ + deleteFunnelCookie: jest.fn(), + getFunnelCookie: jest.fn(), +})); + +router.navigateWithoutSaving = jest.fn(); +router.navigateWithSaving = jest.fn(); + +// Tests +describe("return-user.vue", () => { + beforeEach(() => { + resetMockStoreData(); + jest.clearAllMocks(); + }); + + describe("Test prerequisites are valid and child components are rendered", () => { + test("expect pagePrerequisites are valid to be called", () => { + // Arrange + const wrapper = setupMocks({}); + + applyMockStoreDataToGetters(); + + // Act + const pagePrerequisitesSpy = jest.spyOn(wrapper.vm, "arePagePrerequisitesValid"); + + wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(pagePrerequisitesSpy).toBeCalled(); + expect(getFunnelCookie).toHaveBeenCalled(); + }); + + test("renders child components", () => { + const wrapper = setupMocks({}); + + expect(wrapper.findComponent(funnelHeader).exists()).toBe(true); + expect(wrapper.findComponent(funnelSubHeader).exists()).toBe(true); + expect(wrapper.findComponent(navbar).exists()).toBe(true); + }); + }); + + describe("Navigation", () => { + test("Check forwardButtonAction is working", async () => { + // Arrange + const wrapper = setupMocks({}); + // Act + + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith( + navigationScenarios.CLICKED_FORWARD, + wrapper.vm.$route + ); + }); + test("expect functions in startOver to be called", async () => { + //Arrange + const wrapper = setupMocks({}); + + // Act + const dispatchStoreActionSpy = jest.spyOn(wrapper.vm, "dispatchStoreAction"); + + await wrapper.vm.$nextTick(); + await wrapper.vm.startOver(); + + // Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith( + navigationScenarios.CLICKED_FORWARD, + wrapper.vm.$route + ); + + expect(dispatchStoreActionSpy).toHaveBeenCalledWith(storeActions.RESET_STATE); + expect(deleteFunnelCookie).toHaveBeenCalled(); + }); + }); +}); + +function setupMocks({ customMountOptions }) { + const route = { query: { fmgPage: "return-user" }, params: {} }; + + baseMixin.methods.ResetExternalParamsAndHideModal = jest.fn(); + + const mountOptions = getMountOptions({ + ...customMountOptions, + route: route, + }); + + mountOptions.global.mocks["$store"] = store; + mountOptions.global.mocks["$router"] = router; + baseMixin.methods.isFormValid = jest.fn().mockReturnValue(true); + mountOptions["attachTo"] = document.body; + + const wrapper = shallowMount(returnUser, mountOptions, { + stubs: { + Form, + funnelHeader, + funnelSubHeader, + navbar, + loadingModal: true, + buttonMain, + }, + }); + + return wrapper; +}