diff --git a/jest.config.js b/jest.config.js index 5df16a837..878990186 100644 --- a/jest.config.js +++ b/jest.config.js @@ -29,7 +29,7 @@ module.exports = { testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], coverageThreshold: { global: { - statements: 76, + statements: 78, }, }, // Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 81ef8f052..17dc27ec2 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -2766,6 +2766,702 @@ describe("Actions", () => { testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true); }); }); + describe("saveActiveAndOrInactivePromos", () => { + it("should save empty arrays to promos and inactivePromos when provided with empty or null parameters", () => { + // Arrange + const context = state; + context.commit = jest.fn(); + + const emptyActivePromos = []; + const emptyInactivePromos = []; + const nullActivePromos = []; + const nullInactivePromos = []; + + // Act + actions.saveActiveAndOrInactivePromos(context, { + activePromos: emptyActivePromos, + inactivePromos: emptyInactivePromos, + }); + actions.saveActiveAndOrInactivePromos(context, { + activePromos: nullActivePromos, + inactivePromos: nullInactivePromos, + }); + // Assert + expect(context.commit).toHaveBeenNthCalledWith(1, storeMutations.UPDATE_PROMOS, []); + expect(context.commit).toHaveBeenNthCalledWith( + 2, + storeMutations.UPDATE_INACTIVE_PROMOS, + [] + ); + expect(context.commit).toHaveBeenNthCalledWith(3, storeMutations.UPDATE_PROMOS, []); + expect(context.commit).toHaveBeenNthCalledWith( + 4, + storeMutations.UPDATE_INACTIVE_PROMOS, + [] + ); + }); + it("should save both active and inactivePromos when method is supplied with both active and inactive", () => { + // Arrange + const context = state; + context.commit = jest.fn(); + + const activePromos = [{ promoCode: "activePromo" }]; + const inactivePromos = ["inactivePromo"]; + + // Act + actions.saveActiveAndOrInactivePromos(context, { + activePromos: activePromos, + inactivePromos: inactivePromos, + }); + + // Assert + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PROMOS, activePromos); + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_INACTIVE_PROMOS, + inactivePromos + ); + }); + it("should remove any inactivePromos that are already active when supplied with both active and inactive", () => { + // Arrange + const context = state; + context.commit = jest.fn(); + + const activePromos = [{ promoCode: "duplicatePromo" }]; + const inactivePromos = ["duplicatePromo", "uniquePromo"]; + + const expectedInactivePromos = ["uniquePromo"]; + + // Act + actions.saveActiveAndOrInactivePromos(context, { + activePromos: activePromos, + inactivePromos: inactivePromos, + }); + + // Assert + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_INACTIVE_PROMOS, + expectedInactivePromos + ); + }); + it("should save active promos from store and inactive promos from method call when only inactivePromos is provided", () => { + // Arrange + const context = state; + context.commit = jest.fn(); + + const activePromos = [{ promoCode: "storedPromo" }]; + const inactivePromos = ["inactivePromo"]; + context["getters"] = { lineItems: { promos: activePromos } }; + + // Act + actions.saveActiveAndOrInactivePromos(context, { inactivePromos: inactivePromos }); + + // Assert + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PROMOS, activePromos); + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_INACTIVE_PROMOS, + inactivePromos + ); + }); + it("should save active promos but remove duplicates from store and inactive promos from method call when only inactivePromos is provided", () => { + // If only inactivePromos is supplied, it will remove duplicates from active promos in the store + // Arrange + const context = state; + context.commit = jest.fn(); + + const activePromos = [{ promoCode: "storedPromo" }, { promoCode: "duplicatePromo" }]; + const inactivePromos = ["duplicatePromo"]; + context["getters"] = { lineItems: { promos: activePromos } }; + + const expectedSavedActivePromos = [{ promoCode: "storedPromo" }]; + + // Act + actions.saveActiveAndOrInactivePromos(context, { inactivePromos: inactivePromos }); + + // Assert + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_PROMOS, + expectedSavedActivePromos + ); + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_INACTIVE_PROMOS, + inactivePromos + ); + }); + it("should save inactivePromos from the store and provided activePromos when only activePromos is provided", () => { + // Arrange + const context = state; + context.commit = jest.fn(); + + const activePromos = [{ promoCode: "activePromo" }]; + const inactivePromos = ["inactivePromo"]; + context["getters"] = { payment: { inactivePromos: inactivePromos } }; + + // Act + actions.saveActiveAndOrInactivePromos(context, { activePromos: activePromos }); + + // Assert + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PROMOS, activePromos); + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_INACTIVE_PROMOS, + inactivePromos + ); + }); + it("should save inactivePromos without duplicates from activePromos from the store and provided activePromos when only activePromos is provided", () => { + // Arrange + const context = state; + context.commit = jest.fn(); + + const activePromos = [{ promoCode: "activePromo" }, { promoCode: "duplicatePromo" }]; + const inactivePromos = ["inactivePromo", "duplicatePromo"]; + context["getters"] = { payment: { inactivePromos: inactivePromos } }; + + const expectedInactivePromos = ["inactivePromo"]; + + // Act + actions.saveActiveAndOrInactivePromos(context, { activePromos: activePromos }); + + // Assert + expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PROMOS, activePromos); + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_INACTIVE_PROMOS, + expectedInactivePromos + ); + }); + }); + describe("validateOrderPromoAndSaveServerData", () => { + it("should add GUIDs if not there to provided addableVaps before sending the http call", async () => { + // Arrange + const context = state; + const promoCode = "testPromo"; + const lineItemsToUse = { vaps: [1], promos: [2] }; + const addableVaps = [{ partNumber: "addableVap" }]; + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + }, + referralSequenceNumber: "test", + lineItems: { + serverData: "test", + }, + }, + }; + + globalMethods.callHttpClient = jest.fn().mockResolvedValue({ + data: {}, + }); + + crypto.randomUUID = jest.fn(() => "GUID"); + + // Act + actions.validateOrderPromoAndSaveServerData(context, { + payload: { + promoCode: promoCode, + lineItemsToUse: lineItemsToUse, + addableVaps: addableVaps, + }, + pageNameToLog: "test", + }); + + const firstCallArgs = globalMethods.callHttpClient.mock.calls[0]; + + // Assert + expect(firstCallArgs[0].payload.addableVaps[0].id).toEqual("GUID"); + }); + it("should use lineItems from the store if not provided in the call", async () => { + // Arrange + const context = state; + const promoCode = "testPromo"; + const lineItemsToUse = null; + const addableVaps = [{ partNumber: "addableVap" }]; + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + }, + referralSequenceNumber: "test", + lineItems: { + vaps: [1], + promos: [2], + serverData: "test", + }, + }, + }; + + globalMethods.callHttpClient = jest.fn().mockResolvedValue({ + data: {}, + }); + + crypto.randomUUID = jest.fn(() => "GUID"); + + const expectedLineItemsOnOrder = [1, 2]; + + // Act + actions.validateOrderPromoAndSaveServerData(context, { + payload: { + promoCode: promoCode, + lineItemsToUse: lineItemsToUse, + addableVaps: addableVaps, + }, + pageNameToLog: "test", + }); + const firstCallArgs = globalMethods.callHttpClient.mock.calls[0]; + + // Assert + expect(firstCallArgs[0].payload.order.lineItemsOnOrder).toEqual( + expectedLineItemsOnOrder + ); + }); + it("should not blow up if an error comes back from the http call", async () => { + // Arrange + const context = state; + const promoCode = "testPromo"; + const lineItemsToUse = null; + const addableVaps = [{ partNumber: "addableVap" }]; + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + }, + referralSequenceNumber: "test", + lineItems: { + vaps: [1], + promos: [2], + serverData: "test", + }, + }, + }; + + globalMethods.callHttpClient = jest.fn(() => + Promise.reject(new Error("Error message")) + ); + + crypto.randomUUID = jest.fn(() => "GUID"); + + // Act + try { + await actions.validateOrderPromoAndSaveServerData(context, { + payload: { + promoCode: promoCode, + lineItemsToUse: lineItemsToUse, + addableVaps: addableVaps, + }, + pageNameToLog: "test", + }); + } catch (error) { + // Assert + fail("Unhandled error occurred"); + } + }); + it("should always save serverData if any is received from the http call", async () => { + // Arrange + const context = state; + const promoCode = "testPromo"; + const lineItemsToUse = null; + const addableVaps = [{ partNumber: "addableVap" }]; + context.commit = jest.fn(() => {}); + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + }, + referralSequenceNumber: "test", + lineItems: { + vaps: [1], + promos: [2], + serverData: "test", + }, + }, + }; + + globalMethods.callHttpClient = jest.fn().mockResolvedValue({ + data: { serverData: "serverData" }, + }); + + crypto.randomUUID = jest.fn(() => "GUID"); + + // Act + await actions.validateOrderPromoAndSaveServerData(context, { + payload: { + promoCode: promoCode, + lineItemsToUse: lineItemsToUse, + addableVaps: addableVaps, + }, + pageNameToLog: "test", + }); + + // Assert + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, + expect.anything() + ); + }); + }); + describe("revalidateOrderPromosAndSaveServerData", () => { + it("should add GUIDs if not there to provided vaps before sending the http call", async () => { + // Arrange + const context = state; + context.commit = jest.fn(() => {}); + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + inactivePromos: ["inactiveTest"], + }, + referralSequenceNumber: "test", + lineItems: { + serverData: "test", + promos: [{ promoCode: "test" }], + vaps: [{ partNumber: "testVap" }], + }, + }, + }; + + globalMethods.callHttpClient = jest.fn().mockResolvedValue({ + data: { lineItemsServerData: "testData" }, + }); + + crypto.randomUUID = jest.fn(() => "GUID"); + + // Act + actions.revalidateOrderPromosAndSaveServerData(context, { + payload: {}, + pageNameToLog: "test", + }); + + const firstCallArgs = globalMethods.callHttpClient.mock.calls[0]; + + // Assert + const vapsLineItem = firstCallArgs[0].payload.order.lineItemsOnOrder.filter( + (lineItem) => { + return lineItem.partNumber == "testVap"; + } + ); + expect(vapsLineItem[0].id).toEqual("GUID"); + }); + it("uses provided parameters in favor of store values", async () => { + // Arrange + const context = state; + context.commit = jest.fn(() => {}); + + const activePromosToUse = [{ promoCode: "providedPromo" }]; + const inactivePromosToUse = ["providedInactivePromo"]; + const vapsProvided = [{ id: 123 }]; + const lineItemsToUse = { vaps: vapsProvided }; + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + inactivePromos: ["inactiveTest"], + }, + referralSequenceNumber: "test", + lineItems: { + serverData: "test", + promos: [{ promoCode: "test" }], + vaps: [{ partNumber: "testVap" }], + }, + }, + }; + + globalMethods.callHttpClient = jest.fn().mockResolvedValue({ + data: { lineItemsServerData: "testData" }, + }); + + crypto.randomUUID = jest.fn(() => "GUID"); + + // Act + actions.revalidateOrderPromosAndSaveServerData(context, { + payload: { + activePromosToUse: activePromosToUse, + inactivePromosToUse: inactivePromosToUse, + lineItemsToUse: lineItemsToUse, + }, + pageNameToLog: "test", + }); + + const firstCallArgs = globalMethods.callHttpClient.mock.calls[0]; + const expectedInactivePromos = ["providedInactivePromo"]; + const expectedLineItemsOnOrder = [...vapsProvided, ...activePromosToUse]; + + // Assert + expect(firstCallArgs[0].payload.inactivePromos).toEqual(expectedInactivePromos); + expect(firstCallArgs[0].payload.order.lineItemsOnOrder).toEqual( + expectedLineItemsOnOrder + ); + }); + it("can build a valid payload with store data only", async () => { + // Arrange + const context = state; + context.commit = jest.fn(() => {}); + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + inactivePromos: ["inactiveTest"], + }, + referralSequenceNumber: "test", + lineItems: { + serverData: "test", + promos: [{ promoCode: "test" }], + vaps: [{ partNumber: "testVap", id: "providedId" }], + }, + }, + }; + + globalMethods.callHttpClient = jest.fn().mockResolvedValue({ + data: { lineItemsServerData: "testData" }, + }); + + crypto.randomUUID = jest.fn(() => "GUID"); + + // Act + actions.revalidateOrderPromosAndSaveServerData(context, { + payload: {}, + pageNameToLog: "test", + }); + + const expectedLineItemsOnOrder = [ + ...context.getters.order.lineItems.vaps, + ...context.getters.order.lineItems.promos, + ]; + const firstCallArgs = globalMethods.callHttpClient.mock.calls[0]; + // Assert + expect(firstCallArgs[0].payload.inactivePromos).toEqual( + context.getters.order.payment.inactivePromos + ); + expect(firstCallArgs[0].payload.order.lineItemsOnOrder).toEqual( + expectedLineItemsOnOrder + ); + }); + it("removes any promos from inactivePromos that are already active before sending the request", async () => { + // Arrange + const context = state; + context.commit = jest.fn(() => {}); + + const activePromosToUse = [{ promoCode: "providedPromoDuplicate" }]; + const inactivePromosToUse = ["providedPromoDuplicate"]; + const vapsProvided = [{ id: 123 }]; + const lineItemsToUse = { vaps: vapsProvided }; + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + }, + referralSequenceNumber: "test", + lineItems: { + serverData: "test", + }, + }, + }; + + globalMethods.callHttpClient = jest.fn().mockResolvedValue({ + data: { lineItemsServerData: "testData" }, + }); + + crypto.randomUUID = jest.fn(() => "GUID"); + + // Act + actions.revalidateOrderPromosAndSaveServerData(context, { + payload: { + activePromosToUse: activePromosToUse, + inactivePromosToUse: inactivePromosToUse, + lineItemsToUse: lineItemsToUse, + }, + pageNameToLog: "test", + }); + + const firstCallArgs = globalMethods.callHttpClient.mock.calls[0]; + // Assert + expect(firstCallArgs[0].payload.inactivePromos).toEqual([]); + }); + it("saves serverData to the store", async () => { + // Arrange + const context = state; + context.commit = jest.fn(() => {}); + + const activePromosToUse = [{ promoCode: "providedPromoDuplicate" }]; + const inactivePromosToUse = ["providedPromoDuplicate"]; + const vapsProvided = [{ id: 123 }]; + const lineItemsToUse = { vaps: vapsProvided }; + + context["getters"] = { + order: { + serviceLocation: { + appointmentType: "test", + state: "test", + zipCodeCtu: "test", + }, + vehicle: { + carId: "test", + year: "test", + }, + referralCorrelationId: "test", + eon: "test", + damage: { + isRepair: true, + glassToReplace: null, + }, + payment: { + parentAccountNumber: "test", + }, + referralSequenceNumber: "test", + lineItems: { + serverData: "test", + }, + }, + }; + + globalMethods.callHttpClient = jest.fn().mockResolvedValue({ + data: { lineItemsServerData: "testData" }, + }); + + crypto.randomUUID = jest.fn(() => "GUID"); + + // Act + await actions.revalidateOrderPromosAndSaveServerData(context, { + payload: { + activePromosToUse: activePromosToUse, + inactivePromosToUse: inactivePromosToUse, + lineItemsToUse: lineItemsToUse, + }, + pageNameToLog: "test", + }); + + // Assert + expect(context.commit).toBeCalledWith( + storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, + expect.anything() + ); + }); + }); }); describe("Getters", () => {