// Components import serviceZip from "@/layouts/service-zip/service-zip"; // Supporting Files import { shallowMount } from "@vue/test-utils"; import { getMountOptions } from "@/helpers/unit-test-helper"; import baseMixin from "@/mixins/base-mixin"; import store from "@/store"; import router from "@/router"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; import vinPagesMixin from "@/mixins/vin-pages-mixin"; import { experimentSettings } from "../../constants/experiments"; // Constants // Setup global mocks let mockCmsContent = { AlertNonServiceableZipWidget: { HeadlineText: "Test", }, }; 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, }, isServiceable: true, }, 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 }, }; } const applicationUser = { experiments: [], }; function applyMockStoreDataToGetters() { store.getters = { experimentSettings: mockExperimentSettings, applicationUser: applicationUser, order: mockStoreData, damage: mockStoreData.damage, payment: mockStoreData.payment, policy: mockStoreData.policy, externalParameterServiceZip: mockStoreData.externalParameterServiceZip, emailOrSms: mockStoreData.customer.emailAddress, 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().mockImplementation(mockDispatchStoreAction), 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(), })); router.navigateWithoutSaving = jest.fn(); router.navigateWithSaving = jest.fn(); // Tests describe("service-zip.vue", () => { beforeEach(() => { resetMockStoreData(); jest.clearAllMocks(); }); describe("Pre-existing fields", () => { test("No existing fields -> serviceZip & emailAdress undefined", () => { // Arrange // no changes to store applyMockStoreDataToGetters(); // Act const wrapper = setupMocks({}); // Assert expect(wrapper.vm.serviceZipCode).toBeFalsy(); expect(wrapper.vm.emailAddress).toBeFalsy(); }); test("Fields in store -> autofilled to data", () => { // Arrange mockStoreData.serviceLocation.zipCode = "11111"; mockStoreData.customer.emailAddress = "builddigitaltest@safelite.com"; applyMockStoreDataToGetters(); // Act const wrapper = setupMocks({}); // Assert expect(wrapper.vm.serviceZipCode).toEqual("11111"); expect(wrapper.vm.emailOrSms).toEqual("builddigitaltest@safelite.com"); }); test("Zip in querystring -> pushed to data", () => { // Arrange // no changes to store applyMockStoreDataToGetters(); // Act const wrapper = setupMocks({ customZipQuery: "11111", }); // Assert expect(wrapper.vm.serviceZipCode).toEqual("11111"); }); }); describe("Navigation", () => { describe("Back Nav", () => { test("If skipvin eligable, go back to vehicle-damage", async () => { // Arrange mockStoreData.damage.isRepair = true; mockStoreData.damage.numberOfChips = 1; mockStoreData.damage.glassToReplace = null; mockStoreData.lineItems.glassParts = null; applyMockStoreDataToGetters(); // Act const wrapper = setupMocks({}); await wrapper.vm.backButtonAction(); // Assert expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith( navigationScenarios.CLICKED_BACK_WITH_SKIP_VIN, wrapper.vm.$route ); }); test("If not skipvin eligable, go back to estimate", async () => { // Arrange // no changes to store applyMockStoreDataToGetters(); // Act const wrapper = setupMocks({}); await wrapper.vm.backButtonAction(); // Assert expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith( navigationScenarios.CLICKED_BACK, wrapper.vm.$route ); }); }); describe("Forward Nav", () => { test("Repair skips questions flow", async () => { // Arrange mockStoreData.damage.isRepair = true; mockStoreData.damage.numberOfChips = 1; mockStoreData.damage.glassToReplace = null; mockStoreData.lineItems.glassParts = null; applyMockStoreDataToGetters(); // Act const wrapper = setupMocks({}); wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); jest.spyOn(wrapper.vm, "navigateForwardWithSingleCarMatch").mockImplementation(); await wrapper.vm.forwardButtonAction(); // Assert expect(wrapper.vm.$router.navigateWithSaving).toBeCalledWith( navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS, wrapper.vm.$route ); expect(wrapper.vm.navigateForwardWithSingleCarMatch).not.toBeCalled(); }); test("Non-repair enters questions flow", async () => { // Arrange mockStoreData.damage.isRepair = false; applyMockStoreDataToGetters(); // Act const wrapper = setupMocks({}); wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); jest.spyOn(wrapper.vm, "navigateForwardWithSingleCarMatch").mockImplementation(); await wrapper.vm.forwardButtonAction(); // Assert expect(wrapper.vm.$router.navigateWithSaving).not.toBeCalled(); expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalled(); }); }); }); describe("Alerts", () => { test("Invalid zip alert shown if indicated by endpoint", async () => { // Arrange // no changes to store applyMockStoreDataToGetters(); const invalidZipResponse = { state: "OH", zipCodeCtu: "TESTCTU", isValid: false, isServiceable: true, }; // Act const wrapper = setupMocks({ customZipDataResponse: invalidZipResponse }); wrapper.vm.$refs.navbar.removeLoader = jest.fn(); await wrapper.vm.forwardButtonAction(); // Assert expect(wrapper.vm.displayInvalidZipAlert).toBe(true); }); test("Non-serviceable zip alert shown if indicated by endpoint", async () => { // Arrange // no changes to store applyMockStoreDataToGetters(); const invalidZipResponse = { state: "OH", zipCodeCtu: "TESTCTU", isValid: true, isServiceable: false, }; // Act const wrapper = setupMocks({ customZipDataResponse: invalidZipResponse }); wrapper.vm.$refs.navbar.removeLoader = jest.fn(); await wrapper.vm.forwardButtonAction(); // Assert expect(wrapper.vm.displayNonServiceableZipAlert).toBe(true); }); test("Alerts cleared when valid zip is submitted", async () => { // Arrange // no changes to store applyMockStoreDataToGetters(); // Act const wrapper = setupMocks({}); wrapper.vm.displayInvalidZipAlert = true; wrapper.vm.displayNonServiceableZipAlert = true; wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); jest.spyOn(wrapper.vm, "navigateForwardWithSingleCarMatch").mockImplementation(); await wrapper.vm.forwardButtonAction(); // Assert expect(wrapper.vm.displayInvalidZipAlert).toBe(false); expect(wrapper.vm.displayNonServiceableZipAlert).toBe(false); }); test("should hide the AlertNoService when displayNoServiceAlert is false", async () => { // Arrange // no changes to store applyMockStoreDataToGetters(); const wrapper = setupMocks({}); wrapper.vm.serviceZipCode = "12345"; wrapper.vm.displayNoServiceAlert = false; await wrapper.vm.forwardButtonAction(); // Check if the AlertNoService component is rendered expect(wrapper.vm.displayNoServiceAlert).toBe(false); }); }); }); describe("service-zip.vue", () => { test("should call forwardButtonAction if isExternalParameter is true and form is valid", async () => { // Set up the store with isExternalParameter as true store.getters.externalParameterState = { isExternalParameter: true }; // Set up the component const wrapper = setupMocks({}); wrapper.vm.forwardButtonAction = jest.fn(); const nextFunction = jest.fn((c) => { c(wrapper.vm); }); // Mock the isFormValid method baseMixin.methods.isFormValid = jest.fn().mockReturnValue(true); // Call the method that contains the if-else logic await serviceZip.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "service-zip" } }, undefined, nextFunction ); expect(nextFunction).toHaveBeenCalled(); expect(wrapper.vm.forwardButtonAction).toHaveBeenCalled(); }); test("should not call forwardButtonAction if isExternalParameter is true and form is invalid", async () => { // Set up the store with isExternalParameter as true store.getters.externalParameterState = { isExternalParameter: true }; // Set up the component const wrapper = setupMocks({}); wrapper.vm.forwardButtonAction = jest.fn(); const nextFunction = jest.fn((c) => { c(wrapper.vm); }); // Mock the isFormValid method baseMixin.methods.isFormValid = jest.fn().mockImplementation(() => { return false; }); // Call the method that contains the if-else logic await serviceZip.beforeRouteEnter.call( wrapper.vm, { query: { fmgPage: "service-zip" } }, undefined, nextFunction ); expect(wrapper.vm.forwardButtonAction).not.toHaveBeenCalled(); }); }); function setupMocks({ customMountOptions, customZipQuery, customZipDataResponse }) { const route = { query: { fmgPage: "service-zip" }, params: {} }; if (customZipQuery) { route.query.zipcode = customZipQuery; } baseMixin.methods.ResetExternalParamsAndHideModal = jest.fn(); const mountOptions = getMountOptions({ ...customMountOptions, route: route, }); mountOptions.global.mocks["$store"] = store; mountOptions.global.mocks["$router"] = router; mountOptions.mixins = [ { methods: { getCmsContent: jest.fn().mockImplementation((widgetName, fieldName) => { if (mockCmsContent[widgetName] && mockCmsContent[widgetName][fieldName]) return mockCmsContent[widgetName][fieldName]; }), setCmsContent: jest.fn(), navigateForwardWithSingleCarMatch: jest.fn(), getAndSaveBillToAccountNumber: jest.fn(), getZipCodeData: jest.fn().mockImplementation(() => { if (customZipDataResponse) { return customZipDataResponse; } else { return { state: "OH", zipCodeCtu: "TESTCTU", isValid: true, isServiceable: true, }; } }), }, }, ]; const wrapper = shallowMount(serviceZip, mountOptions); wrapper.vm.findClosestApplicableShops = jest.fn().mockImplementation(() => { return Promise.resolve({ data: { providers: [ { id: 1, name: "Shop 1" }, { id: 2, name: "Shop 2" }, ], }, }); }); return wrapper; }