diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index ee0eee749..003d28b0d 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -33,7 +33,8 @@ class="small mt-4" v-model="lineItems" :availableVaps="availableVaps" - pageName="payment-method" + :taxPromos="taxPromos" + :pageName="payment - method" modalWidgetName="PromoModalWidget" />
@@ -309,6 +310,7 @@ export default { return { lineItems: [], availableVaps: [], + taxPromos: true, paymentMethodInternalModel: this.getPaymentMethodFromStore(), inactivePromos: this.getInactivePromosFromStore(), }; diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js b/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js index 16d170e82..1dcc2ac70 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js @@ -1,5 +1,25 @@ import { mount, shallowMount } from "@vue/test-utils"; import promoModalQuestion from "./promo-modal-question"; +import { storeActions } from "@/constants/store-actions"; +import baseMixin from "@/mixins/base-mixin.js"; + +let mockReturnsForStoreActions = {}; + +jest.mock("@/mixins/base-mixin", () => ({ + ...jest.requireActual("@/mixins/base-mixin"), + methods: { + dispatchStoreActionWithLogging: jest.fn( + (action, { promoCode, addableVaps }, pageNameToLog, someBool) => { + return mockReturnsForStoreActions[action]; + } + ), + }, +})); + +afterEach(() => { + // reset store action returns + mockReturnsForStoreActions = {}; +}); jest.mock("@/digital-components/textbox-question/textbox-question", () => ({ getCmsContent: jest.fn((widgetName, cmsFieldName) => { @@ -79,4 +99,127 @@ describe("promo-modal-question.vue", () => { // Assert expect(wrapper.emitted("update:modelValue")).toEqual([[lineItems]]); }); + it("focuses on the input element when focusOnPromoInput is called", async () => { + // Arrange + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + attachTo: document.body, + }); + const focusMock = jest.fn(); + const inputMock = { focus: focusMock }; + + // Mock document.getElementById to return the inputMock + jest.spyOn(document, "getElementById").mockReturnValue(inputMock); + + //Act + + wrapper.vm.focusOnPromoInput(); + await wrapper.vm.$nextTick(); + + //Assert + expect(focusMock).toHaveBeenCalled(); + }); + it("returns a validate response on applying promo", async () => { + // Arrange + const newPromo = "testPromo"; + const pageNameToLog = "testPage"; + const validateResponse = { orderPromos: [] }; + const addableVaps = []; + mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = + validateResponse; + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + attachTo: document.body, + }); + // Act + + wrapper.vm.getPromoCodeData(); + + const promoValidationResponse = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA, + { + newPromo, + lineItems, + addableVaps, + }, + pageNameToLog, + false + ); + + // Assert + expect(promoValidationResponse).toEqual(validateResponse); + }); + test("If promocode is valid return taxed lineItems", async () => { + //Arrange + const taxedlineItems = {}; + + mockReturnsForStoreActions[storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA] = + taxedlineItems; + + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + let promoCode = "1wiper0"; + const pricedLineItemsToTax = []; + + pricedLineItemsToTax.push(promoCode); + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + + attachTo: document.body, + }); + wrapper.vm.addPromoCode(); + + const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, + { + billToAccountNumber: "87291", + providerNumber: 2, + appointmentType: "IN_SHOP", + serviceLocationCity: "city", + serviceLocationState: "state", + serviceLocationZipCode: "12345", + pricedLineItems: pricedLineItemsToTax, + }, + + "payment-method", + + false + ); + + // Assert + + expect(taxedLineItems).toEqual(taxedlineItems); + }); }); diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue index a68ff4dbe..ede99df1a 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue @@ -101,6 +101,7 @@ export default { modalWidgetName: String, availableVaps: Object, pageName: String, + taxPromos: Boolean, }, computed: { promoLinkText() { @@ -258,7 +259,7 @@ export default { ); if (promoCodeData.isValid) { - if (this.pageName == "payment-method") { + if (this.taxPromos) { const pricedLineItemsToTax = []; pricedLineItemsToTax.push(...promoCodeData.promoCode); const taxedLineItems = diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index fc9b4c4eb..4a0814acd 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -4,6 +4,8 @@ import { applicationConfig } from "@/constants/application-config"; import { storeActions } from "@/constants/store-actions"; import quote from "@/layouts/quote/quote.vue"; import store from "@/store"; +import promotionsHelper from "@/helpers/promotions-helper"; +import baseMixin from "@/mixins/base-mixin.js"; import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper"; import { nextTick } from "vue"; @@ -133,8 +135,6 @@ describe("quote.vue", () => { }; }); - wrapper.vm.pricedGlassParts = []; - //Act await wrapper.vm.forwardButtonAction(); @@ -250,9 +250,8 @@ describe("quote.vue", () => { ); //Assert - expect(wrapper.vm.pricedGlassParts !== null).toBe(true); - expect(wrapper.vm.supportingItems !== null).toBe(true); expect(wrapper.vm.availableLineItems !== null).toBe(true); + expect(wrapper.vm.availableVaps !== null).toBe(true); // This should have its own test //expect(vm.isInsuranceSelected !== null).toBe(true); }); @@ -510,6 +509,31 @@ describe("quote.vue", () => { //Assert expect(wrapper.vm.isInsuranceSelected).toBe(true); }); + test("On forward button action save promos", async () => { + //Arrange + store.getters.payment = { + insuranceCoverage: {}, + isInsurance: false, + }; + store.getters.order = { + lineItems: [], + payment: { + parentAccountNumber: 167132, + }, + }; + const { wrapper } = setupMocks({ + customMountOptions: { + router: { + navigateWithSaving: jest.fn(), + }, + route: { quote }, + }, + }); + + wrapper.vm.forwardButtonAction(); + + expect(wrapper.vm.lineItems.promos !== null).toBe(true); + }); }); function setupMocks({ customMountOptions }) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index ff552ee82..257d953e7 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -98,8 +98,6 @@ import { revalidatePromosAndValidateQueryStringPromo, buildToastMessagesFromRevalidateOrValidatePromoResponse, createPromoSuccessAlert, - createPromoErrorAlert, - getNewlyInactivatedPromos, } from "@/helpers/promotions-helper"; import { queryStrings } from "@/constants/query-strings"; import { getQuerystringParameter } from "@/helpers/querystring-helper"; @@ -151,7 +149,8 @@ export default { ]; const resultMap = await settleAllPromises(promiseResultMap); - const nullSafeGlassParts = store.getters.order.lineItems.glassParts ?? []; + const lineItems = store.getters.order.lineItems; + const nullSafeGlassParts = lineItems.glassParts ?? []; const availableLineItems = [ resultMap.rainDefense, ...resultMap.supportingItems, @@ -189,7 +188,6 @@ export default { "quote" ); - const lineItems = store.getters.order.lineItems; lineItems.promos = lineItems.promos ?? []; lineItems.vaps = lineItems.vaps ?? []; // End of promo logic @@ -197,8 +195,6 @@ export default { // Call the "next" function to complete the transition to this page. next((vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.pricedGlassParts = nullSafeGlassParts; - vm.supportingItems = resultMap.supportingItems; vm.availableLineItems = pricingResults; vm.availableVaps = availableVaps; vm.lineItems = lineItems; @@ -227,12 +223,9 @@ export default { data() { return { isInsuranceSelected: null, - selectedVaps: null, availableLineItems: null, - supportingItems: null, - pricedGlassParts: null, - lineItems: [], availableVaps: [], + lineItems: [], }; }, computed: { @@ -282,30 +275,7 @@ export default { } }, vapsItemsSelectedAction(vapsItemsSelected) { - this.selectedVaps = vapsItemsSelected; - }, - async revalidatePromos() { - this.$refs.loadingModal.showModal(); - const revalidatePromoResponse = await baseMixin.methods.dispatchStoreActionWithLogging( - storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA, - { - activePromosToUse: this.lineItems.promos, - inactivePromosToUse: this.$store.getters.order.payment.inactivePromos, - lineItemsToUse: this.lineItems, - }, - "quote", - false - ); - // Handle error alerts here, success alerts are handled in the watcher - if (revalidatePromoResponse.errors.length) { - getNewlyInactivatedPromos( - this.inactivePromos, - revalidatePromoResponse.errors - ).forEach((promoCode) => { - const errorAlert = createPromoErrorAlert(promoCode); - this.$refs.funnelHeader.pushGlobalAlert(errorAlert, errorAlert.shouldAutoFade); - }); - } + this.lineItems.vaps = vapsItemsSelected; }, backButtonAction() { vehicleQuestionsMixin.methods.navigateBack(this); @@ -329,18 +299,18 @@ export default { this.$store.getters.order.payment.parentAccountNumber != applicationConfig.CASH_PARENT_ACCOUNT_NUMBER ) { - this.supportingItems = this.filterOutFees(this.supportingItems); + this.lineItems.supportingItems = this.filterOutFees(this.lineItems.supportingItems); } - if (this.pricedGlassParts.length > 0) { + if (this.lineItems.glassParts?.length > 0) { this.dispatchStoreAction( this.storeActions.SAVE_GLASS_PARTS_SUPPRESSING_STATE_RESETTING, - this.pricedGlassParts, + this.lineItems.glassParts, false ); } - this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false); + this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.lineItems.vaps, false); this.dispatchStoreAction( storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, { @@ -385,11 +355,6 @@ export default { ); const alert = createPromoSuccessAlert(newlyActivatedPromoCodes[0].promoCode); this.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade); - } else if ( - oldValue.promos.length == newValue.promos.length && - oldValue.vaps.length != newValue.vaps.length - ) { - this.revalidatePromos(); } }, deep: true, diff --git a/src/layouts/quote/service-package-question/service-package-question.spec.js b/src/layouts/quote/service-package-question/service-package-question.spec.js index c156ef34c..8163c6324 100644 --- a/src/layouts/quote/service-package-question/service-package-question.spec.js +++ b/src/layouts/quote/service-package-question/service-package-question.spec.js @@ -256,6 +256,57 @@ describe("service-package-question.vue", () => { // Assert expect(wrapper.vm.selectedPackageName).toBe("TierThree"); }); + it("should select default package if promos are added", async () => { + //Arrange + mockProps.activePromos != null; + const wrapper = setupMocks({ + mountOptionsMockData: { + store: { + getters: { + order: { + damage: { + isRepair: false, + glassToReplace: [{ glassLocation: "Windshield" }], + }, + }, + lineItems: { + vaps: [], + }, + hasAnyNonWindshieldGlassParts: false, + payment: { + isInsurance: false, + }, + }, + }, + }, + }); + + //Act + wrapper.setProps({ + activePromos: [ + { + discountedLineItemIds: [ + { + 0: "428ec73c-38e4-4e14-8703-a987b0391898", + 1: "79db94d7-163c-4408-a1ec-f83e58c11992", + }, + ], + partType: "PROMO_DISCOUNT", + promoCode: "1WIPER0", + partNumber: "WIPER DISCOUNT", + laborAmount: 0, + sellingPrice: -10, + kitPrice: 0, + salesTax: null, + }, + ], + }); + const selectDefaultPackageMock = jest.spyOn(wrapper.vm, "selectDefaultPackage"); + await nextTick(); + + //Assert + expect(selectDefaultPackageMock).toHaveBeenCalled(); + }); }); describe("service-package-question.vue, matching business rules for package display", () => { // mock scenarios in figma: