import { mount, flushPromises } from "@vue/test-utils"; import saveProgressPopupQuestion from "./save-progress-popup-question"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { storeActions } from "@/constants/store-actions"; import { saveQuote } from "@/helpers/heritage-integration/order-helper.js"; jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({ saveQuote: jest.fn().mockResolvedValue(undefined), })); jest.mock("@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper", () => ({ ...jest.requireActual("@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper"), getSaveProgressSmsConsentConfig: jest.fn().mockReturnValue({ copy: { transactional: "Sign me up for updates about my upcoming service.", marketing: "Sign me up for promotional and product offers.", }, value: { transactional: false, marketing: false }, }), })); jest.mock("@/digital-components/modal/modal", () => ({ methods: { closeModal: jest.fn(), resetButtonStyle: jest.fn(), }, })); describe("save-progress-popup-question ", () => { describe("when closeModal is run ", () => { test("the modal should close ", () => { // Arrange const { wrapper } = setupMocks({ props: { modalWidgetName: "testModal", }, }); // Act wrapper.vm.closeModal(); // Assert expect(wrapper.vm.modal).not.toBeNull(); }); }); describe("contact method tabs", () => { test("should default to the email tab", () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); expect(wrapper.vm.isPhoneTabSelected).toBe(false); }); test("should use tab labels from phone and email specific CMS widgets", () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, cmsContent: { SaveProgressPopupWidget_PhoneSpecific: { HeadlineText: "PHONE" }, SaveProgressPopupWidget_EmailSpecific: { HeadlineText: "EMAIL" }, }, }); expect(wrapper.vm.contactTabs).toEqual([ { label: "PHONE", value: "PhoneAnswer" }, { label: "EMAIL", value: "EmailAnswer" }, ]); }); test("should use disclaimer BodyText from the selected tab widget", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, cmsContent: { SaveProgressPopupWidget_PhoneSpecific: { BodyText: "Phone disclaimer" }, SaveProgressPopupWidget_EmailSpecific: { BodyText: "Email disclaimer" }, }, }); expect(wrapper.vm.modalDisclaimerText).toBe("Email disclaimer"); wrapper.vm.selectContactMethod("PhoneAnswer"); await wrapper.vm.$nextTick(); expect(wrapper.vm.modalDisclaimerText).toBe("Phone disclaimer"); }); test("should use phone question CMS widget on the phone tab", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); wrapper.vm.selectContactMethod("PhoneAnswer"); await wrapper.vm.$nextTick(); expect(wrapper.vm.phoneQuestionWidgetName).toBe("SaveProgressPopupPhoneQuestionWidget"); }); test("should show email content when the email tab is selected", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); expect(wrapper.vm.contactMethod).toBe("EmailAnswer"); expect(wrapper.vm.isPhoneTabSelected).toBe(false); expect(wrapper.vm.emailQuestionWidgetName).toBe("SaveProgressPopupEmailQuestionWidget"); }); test("should show phone content when the phone tab is selected", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); wrapper.vm.selectContactMethod("PhoneAnswer"); await wrapper.vm.$nextTick(); expect(wrapper.vm.contactMethod).toBe("PhoneAnswer"); expect(wrapper.vm.isPhoneTabSelected).toBe(true); expect(wrapper.vm.userInput).toBe(""); }); test("should reset sms consent when switching tabs", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); wrapper.vm.smsConsent = { transactional: true, marketing: true }; wrapper.vm.showConsentErrors = true; wrapper.vm.selectContactMethod("PhoneAnswer"); await wrapper.vm.$nextTick(); expect(wrapper.vm.smsConsent).toEqual({ transactional: false, marketing: false }); expect(wrapper.vm.showConsentErrors).toBe(false); }); }); describe("validatePhoneAndSave", () => { test("should show consent errors when phone is valid but no consent is selected", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); wrapper.vm.selectContactMethod("PhoneAnswer"); wrapper.vm.modal.validate = jest.fn().mockResolvedValue({ valid: true }); const resetSpy = jest.spyOn(wrapper.vm, "resetPhoneSendButtonStyle"); const scrollSpy = jest .spyOn(wrapper.vm, "scrollConsentIntoView") .mockResolvedValue(undefined); await wrapper.vm.validatePhoneAndSave(); expect(wrapper.vm.showConsentErrors).toBe(true); expect(scrollSpy).toHaveBeenCalled(); expect(resetSpy).toHaveBeenCalled(); }); test("should scroll consent checkboxes into view", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); const mockScrollIntoView = jest.fn(); const consentEl = document.createElement("fieldset"); consentEl.className = "save-progress-popup-sms-consent"; consentEl.scrollIntoView = mockScrollIntoView; wrapper.element.appendChild(consentEl); await wrapper.vm.scrollConsentIntoView(); expect(mockScrollIntoView).toHaveBeenCalledWith({ behavior: "smooth", block: "nearest", }); }); test("should reset the send button loader when phone validation fails", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); wrapper.vm.selectContactMethod("PhoneAnswer"); wrapper.vm.modal.validate = jest.fn().mockResolvedValue({ valid: false }); const resetSpy = jest.spyOn(wrapper.vm, "resetPhoneSendButtonStyle"); await wrapper.vm.validatePhoneAndSave(); expect(wrapper.vm.showConsentErrors).toBe(false); expect(resetSpy).toHaveBeenCalled(); }); test("should save when phone and consent are valid", async () => { const dispatchStoreAction = jest.fn().mockResolvedValue(undefined); const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", pageName: "quote", }, }); await flushPromises(); wrapper.vm.dispatchStoreAction = dispatchStoreAction; wrapper.vm.selectContactMethod("PhoneAnswer"); wrapper.vm.userInput = "555-123-4567"; wrapper.vm.smsConsent = { transactional: true, marketing: false }; wrapper.vm.modal.validate = jest.fn().mockResolvedValue({ valid: true }); const resetSpy = jest.spyOn(wrapper.vm, "resetPhoneSendButtonStyle"); await wrapper.vm.validatePhoneAndSave(); expect(wrapper.vm.showConsentErrors).toBe(false); expect(wrapper.vm.isProgressSaved).toBe(true); expect(resetSpy).toHaveBeenCalled(); }); }); describe("footer button suppression", () => { test("should suppress the modal footer button on the phone tab", async () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); wrapper.vm.selectContactMethod("PhoneAnswer"); await wrapper.vm.$nextTick(); expect(wrapper.vm.isFooterButtonSuppressed).toBe(true); }); test("should show the modal footer button on the email tab before save", () => { const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", }, }); expect(wrapper.vm.isFooterButtonSuppressed).toBe(false); }); test("should suppress the modal footer button after a successful email save", async () => { const dispatchStoreAction = jest.fn().mockResolvedValue(undefined); const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", pageName: "quote", }, }); wrapper.vm.dispatchStoreAction = dispatchStoreAction; wrapper.vm.userInput = "test@example.com"; await wrapper.vm.saveProgress(); expect(wrapper.vm.isFooterButtonSuppressed).toBe(true); }); test("should reset the modal footer button loader before suppressing it after save", async () => { const dispatchStoreAction = jest.fn().mockResolvedValue(undefined); const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", pageName: "quote", }, }); wrapper.vm.dispatchStoreAction = dispatchStoreAction; wrapper.vm.userInput = "test@example.com"; wrapper.vm.modal.resetButtonStyle = jest.fn(); await wrapper.vm.saveProgress(); expect(wrapper.vm.modal.resetButtonStyle).toHaveBeenCalled(); }); }); describe("saveProgress", () => { test("should save phone number and sms consent when phone tab is selected", async () => { const dispatchStoreAction = jest.fn().mockResolvedValue(undefined); const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", pageName: "quote", }, }); wrapper.vm.dispatchStoreAction = dispatchStoreAction; wrapper.vm.selectContactMethod("PhoneAnswer"); wrapper.vm.userInput = "555-123-4567"; wrapper.vm.smsConsent = { transactional: true, marketing: false }; await wrapper.vm.saveProgress(); expect(dispatchStoreAction).toHaveBeenCalledWith( storeActions.SAVE_PHONE_NUMBER, "5551234567", false ); expect(dispatchStoreAction).not.toHaveBeenCalledWith( storeActions.SAVE_EMAIL, expect.anything(), false ); expect(dispatchStoreAction).toHaveBeenCalledWith( storeActions.SAVE_IS_SMS_OPT_IN, true, false ); expect(saveQuote).toHaveBeenCalledWith({ pageNameToLog: "quote" }); expect(wrapper.vm.isProgressSaved).toBe(true); expect(wrapper.vm.savedContactMethod).toBe("PhoneAnswer"); }); test("should save email when email tab is selected", async () => { const dispatchStoreAction = jest.fn().mockResolvedValue(undefined); const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", pageName: "quote", }, }); wrapper.vm.dispatchStoreAction = dispatchStoreAction; wrapper.vm.userInput = "test@example.com"; await wrapper.vm.saveProgress(); expect(dispatchStoreAction).toHaveBeenCalledWith( storeActions.SAVE_EMAIL, "test@example.com", false ); expect(dispatchStoreAction).not.toHaveBeenCalledWith( storeActions.SAVE_PHONE_NUMBER, expect.anything(), false ); expect(saveQuote).toHaveBeenCalledWith({ pageNameToLog: "quote" }); expect(wrapper.vm.savedContactMethod).toBe("EmailAnswer"); }); test("should not allow switching tabs after a successful phone save", async () => { const dispatchStoreAction = jest.fn().mockResolvedValue(undefined); const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", pageName: "quote", }, }); wrapper.vm.dispatchStoreAction = dispatchStoreAction; wrapper.vm.selectContactMethod("PhoneAnswer"); wrapper.vm.userInput = "555-123-4567"; wrapper.vm.smsConsent = { transactional: true, marketing: false }; await wrapper.vm.saveProgress(); wrapper.vm.selectContactMethod("EmailAnswer"); await wrapper.vm.$nextTick(); expect(wrapper.vm.contactMethod).toBe("PhoneAnswer"); expect(wrapper.vm.isContactMethodTabDisabled("EmailAnswer")).toBe(true); expect(wrapper.vm.isContactMethodTabDisabled("PhoneAnswer")).toBe(false); }); test("should not allow switching tabs after a successful email save", async () => { const dispatchStoreAction = jest.fn().mockResolvedValue(undefined); const { wrapper } = setupMocks({ props: { modalWidgetName: "SaveProgressPopupWidget", pageName: "quote", }, }); wrapper.vm.dispatchStoreAction = dispatchStoreAction; wrapper.vm.userInput = "test@example.com"; await wrapper.vm.saveProgress(); wrapper.vm.selectContactMethod("PhoneAnswer"); await wrapper.vm.$nextTick(); expect(wrapper.vm.contactMethod).toBe("EmailAnswer"); expect(wrapper.vm.isContactMethodTabDisabled("PhoneAnswer")).toBe(true); expect(wrapper.vm.isContactMethodTabDisabled("EmailAnswer")).toBe(false); }); }); }); function setupMocks({ options, props, cmsContent = {} }) { const mountOptions = getMountOptions({ ...options, }); const mockBaseMixin = { methods: { getCmsContent: jest.fn( (widgetName, fieldName) => cmsContent[widgetName]?.[fieldName] ?? "" ), dispatchStoreAction: jest.fn(), }, }; if (props) mountOptions.propsData = props; mountOptions.global.mixins = [mockBaseMixin]; const wrapper = mount(saveProgressPopupQuestion, mountOptions); return { wrapper }; }