import * as promotionsHelper from "@/helpers/promotions-helper"; import { partTypeStrings } from "@/constants/part-type-strings"; import store from "@/store"; 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: { dispatchStoreAction: jest.fn((action, { activePromos, inactivePromos }, someBool) => {}), dispatchStoreActionWithLogging: jest.fn( (action, { promoCode, addableVaps }, pageNameToLog, someBool) => { return mockReturnsForStoreActions[action]; } ), }, })); afterEach(() => { // reset store after each test store.getters.lineItems.promos = null; store.getters.payment.inactivePromos = null; // reset store action returns mockReturnsForStoreActions = {}; // reset mock method call counters baseMixin.methods.dispatchStoreAction.mockClear(); baseMixin.methods.dispatchStoreActionWithLogging.mockClear(); }); describe("promotions-helper.js", () => { describe("expected return tests", () => { describe("getPromosWithAddableVaps", () => { it("returns an empty array when promoList is null or empty", () => { // Arrange const emptyPromoList = []; const nullPromoList = null; // Act const emptyPromoListReturn = promotionsHelper.getPromosWithAddableVaps(emptyPromoList); const nullPromoListReturn = promotionsHelper.getPromosWithAddableVaps(nullPromoList); // Assert expect(emptyPromoListReturn).toEqual([]); expect(nullPromoListReturn).toEqual([]); }); it("returns an empty array when no promo with addable vaps is provided", () => { // Arrange const promoIdentifier = "identifierString"; const promoListWithAddableVapsPromo = [ { promoIdentifier: promoIdentifier, partNumber: "fakekPromoPartNumber" }, ]; // Act const promoListWithAddableVapsPromoReturn = promotionsHelper.getPromosWithAddableVaps(promoListWithAddableVapsPromo); // Assert expect(promoListWithAddableVapsPromoReturn).toEqual([]); }); it("returns an array with the provided promo when a promo with addable vaps is provided", () => { // Arrange const promoIdentifier = "identifierString"; const promoListWithAddableVapsPromo = [ { promoIdentifier: promoIdentifier, partNumber: promotionsHelper.addableVapsPromoPartNumbers[0], }, ]; // Act const promoListWithAddableVapsPromoReturn = promotionsHelper.getPromosWithAddableVaps(promoListWithAddableVapsPromo); // Assert expect(promoListWithAddableVapsPromoReturn[0].promoIdentifier).toEqual( promoIdentifier ); }); }); describe("getLineItemsThatMatchPromos", () => { it("returns an empty array when parameters or their children are null or empty", () => { // Arrange const validGuidForId = "09bd698e-97b3-4fca-a707-5cb16a93a127"; // setup const nullPromos = null; const emptyPromos = []; const promosWithNullDiscountedLineItemIds = [{ discountedLineItemIds: null }]; const promosWithEmptyDiscountedLineItemIds = [{ discountedLineItemIds: [] }]; const validPromosWithOnePromo = [{ discountedLineItemIds: [validGuidForId] }]; // scenarios const nullPromosReturn = promotionsHelper.getLineItemsThatMatchPromos( nullPromos, validAvailableLineItemsWithOneItem ); const emptyPromosReturn = promotionsHelper.getLineItemsThatMatchPromos( emptyPromos, validAvailableLineItemsWithOneItem ); const nullDiscountedLineItemsReturn = promotionsHelper.getLineItemsThatMatchPromos( promosWithNullDiscountedLineItemIds, validAvailableLineItemsWithOneItem ); const emptyDiscountedLineItemsReturn = promotionsHelper.getLineItemsThatMatchPromos( promosWithEmptyDiscountedLineItemIds, validAvailableLineItemsWithOneItem ); // Null or Empty scenarios const nullAvailableLineItemsReturn = promotionsHelper.getLineItemsThatMatchPromos( validPromosWithOnePromo, nullAvailableLineItems ); const emptyAvailableLineItemsReturn = promotionsHelper.getLineItemsThatMatchPromos( validPromosWithOnePromo, emptyAvailableLineItems ); // Assert // Null or Empty assertions expect(nullPromosReturn).toEqual([]); expect(emptyPromosReturn).toEqual([]); expect(nullDiscountedLineItemsReturn).toEqual([]); expect(emptyDiscountedLineItemsReturn).toEqual([]); // Null or Empty assertions expect(nullAvailableLineItemsReturn).toEqual([]); expect(emptyAvailableLineItemsReturn).toEqual([]); }); it("returns the matching availableLineItem when provided valid, matching data in promos", () => { const promos = [ { discountedLineItemIds: [1, 2], }, ]; const availableLineItems = [ { id: 1, name: "Item 1", }, { id: 2, name: "Item 2", }, { id: 3, name: "Item 3", }, ]; const expected = [ { id: 1, name: "Item 1", }, { id: 2, name: "Item 2", }, ]; expect( promotionsHelper.getLineItemsThatMatchPromos(promos, availableLineItems) ).toEqual(expected); }); }); describe("getAddableVapsFromAvailableLineItems", () => { it("returns empty array if availableLineItems is null or empty", () => { // Arrange const nullAvailableLineItems = null; const emptyAvailableLineItems = []; // Act const nullAvailableLineItemsReturn = promotionsHelper.getAddableVapsFromAvailableLineItems(nullAvailableLineItems); const emptyAvailableLineItemsReturn = promotionsHelper.getAddableVapsFromAvailableLineItems(emptyAvailableLineItems); // Assert expect(nullAvailableLineItemsReturn).toEqual([]); expect(emptyAvailableLineItemsReturn).toEqual([]); }); it("returns provided front wiper and rain defense items from availableLineItems", () => { // Arrange const availableLineItemsWithFrontWipersAndRainDefense = [ { partType: partTypeStrings.FRONT_WIPER }, { partType: partTypeStrings.RAIN_DEFENSE }, { partType: partTypeStrings.REAR_WIPER }, { partType: partTypeStrings.RECALIBRATION }, { partType: partTypeStrings.REPLACE_FEE }, { partType: "Windshield" }, ]; // Act const addableVapsFromAvailableLineItems = promotionsHelper.getAddableVapsFromAvailableLineItems( availableLineItemsWithFrontWipersAndRainDefense ); // Assert const frontWiperParts = addableVapsFromAvailableLineItems.filter( (lineItem) => lineItem.partType == partTypeStrings.FRONT_WIPER ); const rainDefenseParts = addableVapsFromAvailableLineItems.filter( (lineItem) => lineItem.partType == partTypeStrings.RAIN_DEFENSE ); expect(addableVapsFromAvailableLineItems.length).toEqual(2); expect(frontWiperParts.length).toEqual(1); expect(rainDefenseParts.length).toEqual(1); }); }); describe("removeVapsPromosFromPromoArray", () => { it("returns empty array if promoArray is null or empty", () => { // Arrange const nullPromoArray = null; const emptyPromoArray = []; // Act const nullPromoArrayReturn = promotionsHelper.removeVapsPromosFromPromoArray(nullPromoArray); const emptyPromoArrayReturn = promotionsHelper.removeVapsPromosFromPromoArray(emptyPromoArray); // Assert expect(nullPromoArrayReturn).toEqual([]); expect(emptyPromoArrayReturn).toEqual([]); }); it("returns list of promos without vapsPromos included in it", () => { // Arrange const fullPromoArray = [ { partNumber: promotionsHelper.promoPartNumberStrings.WIPER_DISCOUNT_PART_NUMBER, }, { partNumber: promotionsHelper.promoPartNumberStrings .RAIN_DEFENSE_DISCOUNT_PART_NUMBER, }, { partNumber: promotionsHelper.promoPartNumberStrings.GLASS_DISCOUNT_PART_NUMBER, }, { partNumber: promotionsHelper.promoPartNumberStrings .GLASS_CLEANER_DISCOUNT_PART_NUMBER, }, ]; // Act const promosWithoutVapsPromos = promotionsHelper.removeVapsPromosFromPromoArray(fullPromoArray); // Assert const glassPromoArray = promosWithoutVapsPromos.filter( (promo) => promo.partNumber == promotionsHelper.promoPartNumberStrings.GLASS_DISCOUNT_PART_NUMBER ); expect(promosWithoutVapsPromos.length).toEqual(1); expect(glassPromoArray.length).toEqual(1); }); }); describe("revalidatePromosAndValidateQueryStringPromo", () => { it("returns null responses if active and inactive promos are null in store and no new promo", async () => { // Arrange const newPromo = null; const pricedLineItems = null; const pageNameToLog = "testPage"; store.getters.order.lineItems.promos = null; store.getters.order.payment.inactivePromos = null; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(validatePromoResponse).toBeNull(); expect(revalidatePromoResponse).toBeNull(); }); it("returns null responses if active and inactive promos are empty arrays in store and no new promo", async () => { // Arrange const newPromo = null; const pricedLineItems = null; const pageNameToLog = "testPage"; store.getters.order.lineItems.promos = []; store.getters.order.payment.inactivePromos = []; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(validatePromoResponse).toBeNull(); expect(revalidatePromoResponse).toBeNull(); }); it("returns a revalidate response if store has active promos", async () => { // Arrange const newPromo = null; const pricedLineItems = null; const pageNameToLog = "testPage"; store.getters.order.lineItems.promos = ["data"]; store.getters.order.payment.inactivePromos = []; const revalidateResponse = { errors: [] }; mockReturnsForStoreActions[ storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA ] = revalidateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(validatePromoResponse).toBeNull(); expect(revalidatePromoResponse).toEqual({ errors: [] }); }); it("returns a revalidate response if store has inactive promos", async () => { // Arrange const newPromo = null; const pricedLineItems = null; const pageNameToLog = "testPage"; store.getters.order.lineItems.promos = []; store.getters.order.payment.inactivePromos = ["data"]; const revalidateResponse = { errors: [] }; mockReturnsForStoreActions[ storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA ] = revalidateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(validatePromoResponse).toBeNull(); expect(revalidatePromoResponse).toEqual(revalidateResponse); }); it("returns a validate response if a new promo is provided", async () => { // Arrange const newPromo = "testPromo"; const pricedLineItems = null; const pageNameToLog = "testPage"; const validateResponse = { orderPromos: [] }; mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = validateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(revalidatePromoResponse).toBeNull(); expect(validatePromoResponse).toEqual(validateResponse); }); it("returns a validate and revalidate response if a new promo is provided and inactive/active promos are in the store", async () => { // Arrange const newPromo = "testPromo"; const pricedLineItems = null; const pageNameToLog = "testPage"; const validateResponse = { orderPromos: [] }; const revalidateResponse = { errors: [] }; store.getters.order.lineItems.promos = ["data"]; store.getters.order.payment.inactivePromos = ["data"]; mockReturnsForStoreActions[ storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA ] = revalidateResponse; mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = validateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(revalidatePromoResponse).toEqual(revalidateResponse); expect(validatePromoResponse).toEqual(validateResponse); }); }); describe("buildToastMessagesFromRevalidateOrValidatePromoResponse", () => { it("returns an empty array if promoResponse parameter is null or an unexpected format", () => { // Arrange const nullPromoResponse = null; const unexpectedPromoResponse = { unexpectedKey: "unexpectedValue" }; // Act const nullPromoResponseReturn = promotionsHelper.buildToastMessagesFromRevalidateOrValidatePromoResponse( nullPromoResponse ); const unexpectedPromoResponseReturn = promotionsHelper.buildToastMessagesFromRevalidateOrValidatePromoResponse( unexpectedPromoResponse ); // Assert expect(nullPromoResponseReturn).toEqual([]); expect(unexpectedPromoResponseReturn).toEqual([]); }); describe("validatePromoResponse scenarios", () => { it("returns an alert for success and error scenarios", () => { // Arrange const successPromoResponse = { orderPromos: [{ promoCode: "testPromo" }] }; const errorPromoResponse = { promoCode: "errorTestPromo" }; // Act const successPromoResponseReturn = promotionsHelper.buildToastMessagesFromRevalidateOrValidatePromoResponse( successPromoResponse ); const errorPromoResponseReturn = promotionsHelper.buildToastMessagesFromRevalidateOrValidatePromoResponse( errorPromoResponse ); // Assert // This depends on "createPromoSuccessAlert" implementation, which is bad practice // but jest has trouble mocking same file dependencies expect(successPromoResponseReturn[0]).toHaveProperty("type", "alert-success"); expect(errorPromoResponseReturn[0]).toHaveProperty("type", "alert-danger"); }); it("returns only one success message for a bundle validate promo response", () => { // Arrange const bundlePromoResponse = { orderPromos: [ { promoCode: "bundlePromo/458" }, { promoCode: "bundlePromo/459" }, ], }; // Act const bundlePromoResponseReturn = promotionsHelper.buildToastMessagesFromRevalidateOrValidatePromoResponse( bundlePromoResponse ); // Assert // This depends on "createPromoSuccessAlert" implementation, which is bad practice // but jest has trouble mocking same file dependencies expect(bundlePromoResponseReturn).toHaveLength(1); }); }); describe("revalidatePromoResponse scenarios", () => { it("returns alerts for new success and new error scenario", () => { // Arrange const successAndErrorPromoResponse = { promoLineItems: [{ promoCode: "successPromo" }], errors: [{ promoCode: "errorPromo" }], }; // Act const successAndErrorPromoResponseReturn = promotionsHelper.buildToastMessagesFromRevalidateOrValidatePromoResponse( successAndErrorPromoResponse ); // Assert // This depends on "createPromoSuccessAlert" implementation, which is bad practice // but jest has trouble mocking same file dependencies const successAlert = successAndErrorPromoResponseReturn.filter((alert) => alert.messageCopy.toLowerCase().includes("successpromo") ); expect(successAlert[0]).toHaveProperty("type", "alert-success"); const errorAlert = successAndErrorPromoResponseReturn.filter((alert) => alert.messageCopy.toLowerCase().includes("errorpromo") ); expect(errorAlert[0]).toHaveProperty("type", "alert-danger"); }); it("returns only alerts for new success and new error scenario", () => { // Arrange const successAndErrorPromoResponse = { promoLineItems: [ { promoCode: "successPromo" }, { promoCode: "successPromoAlreadyActive" }, ], errors: [ { promoCode: "errorPromo" }, { promoCode: "errorPromoAlreadyInactive" }, ], }; const oldActivePromos = [{ promoCode: "successPromoAlreadyActive" }]; const oldInactivePromos = ["errorPromoAlreadyInactive"]; // Act const successAndErrorPromoResponseReturn = promotionsHelper.buildToastMessagesFromRevalidateOrValidatePromoResponse( successAndErrorPromoResponse, oldActivePromos, oldInactivePromos ); // Assert // This depends on "createPromoSuccessAlert" implementation, which is bad practice // but jest has trouble mocking same file dependencies const successAlert = successAndErrorPromoResponseReturn.filter((alert) => alert.messageCopy.toLowerCase().includes("successpromo") ); expect(successAlert[0]).toHaveProperty("type", "alert-success"); const errorAlert = successAndErrorPromoResponseReturn.filter((alert) => alert.messageCopy.toLowerCase().includes("errorpromo") ); expect(errorAlert[0]).toHaveProperty("type", "alert-danger"); }); }); }); describe("getPromosThatMatchLineItemsOnOrder", () => { it("returns an empty array when either parameter is null or empty", () => { // Arrange const nullPromos = null; const emptyPromos = []; const validPromos = [{ promoCode: "validPromo", discountedLineItemIds: [1] }]; const nullLineItemsOnOrder = null; const emptyLineItemsOnOrder = []; const validLineItemsOnOrder = [{ id: 1 }]; // Act // Bad promos const nullPromosReturn = promotionsHelper.getPromosThatMatchLineItemsOnOrder( nullPromos, validLineItemsOnOrder ); const emptyPromosReturn = promotionsHelper.getPromosThatMatchLineItemsOnOrder( emptyPromos, validLineItemsOnOrder ); // Bad lineItemsOnOrder const nullLineItemsOnOrderReturn = promotionsHelper.getPromosThatMatchLineItemsOnOrder( validPromos, nullLineItemsOnOrder ); const emptyLineItemsOnOrderReturn = promotionsHelper.getPromosThatMatchLineItemsOnOrder( validPromos, emptyLineItemsOnOrder ); // Bad both const nullBothReturn = promotionsHelper.getPromosThatMatchLineItemsOnOrder( nullPromos, nullLineItemsOnOrder ); const emptyBothReturn = promotionsHelper.getPromosThatMatchLineItemsOnOrder( emptyPromos, emptyLineItemsOnOrder ); // Assert expect(nullPromosReturn).toEqual([]); expect(emptyPromosReturn).toEqual([]); expect(nullLineItemsOnOrderReturn).toEqual([]); expect(emptyLineItemsOnOrderReturn).toEqual([]); expect(nullBothReturn).toEqual([]); expect(emptyBothReturn).toEqual([]); }); it("returns only matching promos with all discountedLineItemIds in lineItemsOnOrder", () => { // Arrange const promos = [ { promoCode: "validPromo", discountedLineItemIds: [1, 2] }, { promoCode: "invalidPromo", discountedLineItemIds: [3, 4] }, ]; const lineItemsOnOrder = [{ id: 1 }, { id: 2 }, { id: 3 }]; const expectedReturnPromos = [ { promoCode: "validPromo", discountedLineItemIds: [1, 2] }, ]; // Act const returnedItems = promotionsHelper.getPromosThatMatchLineItemsOnOrder( promos, lineItemsOnOrder ); // Assert expect(returnedItems).toEqual(expectedReturnPromos); }); it("returns a bundle promo only if BOTH bundle pieces are satisfied", () => { // Arrange const promos = [ { promoCode: "validPromo/400", discountedLineItemIds: [1, 2] }, { promoCode: "validPromo/401", discountedLineItemIds: [3, 4] }, { promoCode: "invalidPromo/500", discountedLineItemIds: [5, 6] }, { promoCode: "invalidPromo/501", discountedLineItemIds: [7, 8] }, ]; // NOTE: invalidPromo/500 is satisfied with below lineItems while /501 is not const lineItemsOnOrder = [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }, { id: 6 }, { id: 7 }, ]; const expectedReturnPromos = [ { promoCode: "validPromo/400", discountedLineItemIds: [1, 2] }, { promoCode: "validPromo/401", discountedLineItemIds: [3, 4] }, ]; // Act const returnedItems = promotionsHelper.getPromosThatMatchLineItemsOnOrder( promos, lineItemsOnOrder ); // Assert expect(returnedItems).toEqual(expectedReturnPromos); }); }); describe("getVapsThatNeedToBeAddedToSatisfyPromos", () => { it("returns an empty array when promos or availableLineItems are null or empty", () => { // Arrange const nullPromos = null; const emptyPromos = []; const validPromos = [ { promoCode: "validPromo", partNumber: promotionsHelper.addableVapsPromoPartNumbers[0], discountedLineItemIds: [1], }, ]; const nullAvailableLineItems = null; const emptyAvailableLineItems = []; const validAvailableLineItems = [{ id: 1 }]; const nullLineItemsOnOrder = null; const emptyLineItemsOnOrder = []; const validLineItemsOnOrder = { vaps: [{ id: 1 }] }; // Act // Bad promos const nullPromosReturn = promotionsHelper.getVapsThatNeedToBeAddedToSatisfyPromos( nullPromos, validAvailableLineItems, validLineItemsOnOrder ); const emptyPromosReturn = promotionsHelper.getVapsThatNeedToBeAddedToSatisfyPromos( emptyPromos, validAvailableLineItems, validLineItemsOnOrder ); // Bad availableLineItems const nullAvailableLineItemsReturn = promotionsHelper.getVapsThatNeedToBeAddedToSatisfyPromos( validPromos, nullAvailableLineItems, validLineItemsOnOrder ); const emptyAvailableLineItemsReturn = promotionsHelper.getVapsThatNeedToBeAddedToSatisfyPromos( validPromos, emptyAvailableLineItems, validLineItemsOnOrder ); // Bad all const nullAllReturn = promotionsHelper.getVapsThatNeedToBeAddedToSatisfyPromos( nullPromos, nullAvailableLineItems, nullLineItemsOnOrder ); const emptyAllReturn = promotionsHelper.getVapsThatNeedToBeAddedToSatisfyPromos( emptyPromos, emptyAvailableLineItems, emptyLineItemsOnOrder ); // Assert expect(nullPromosReturn).toEqual([]); expect(emptyPromosReturn).toEqual([]); expect(nullAvailableLineItemsReturn).toEqual([]); expect(emptyAvailableLineItemsReturn).toEqual([]); expect(nullAllReturn).toEqual([]); expect(emptyAllReturn).toEqual([]); }); it("returns vaps that need to be provided to satisfy promo only", () => { // Arrange const promos = [ { promoCode: "validPromo", partNumber: promotionsHelper.addableVapsPromoPartNumbers[0], discountedLineItemIds: [1], }, { promoCode: "invalidPromo", partNumber: "notAVapsPromo", discountedLineItemIds: [2], }, ]; const availableLineItems = [{ id: 1 }, { id: 2 }, { id: 3 }]; const lineItemsOnOrder = []; const expectedReturn = [{ id: 1 }]; // Act const actualReturn = promotionsHelper.getVapsThatNeedToBeAddedToSatisfyPromos( promos, availableLineItems, lineItemsOnOrder ); // Assert expect(actualReturn).toEqual(expectedReturn); }); it("returns no vaps if those vaps are already on the order", () => { // Arrange const promos = [ { promoCode: "validPromo", partNumber: promotionsHelper.addableVapsPromoPartNumbers[0], discountedLineItemIds: [1], }, { promoCode: "invalidPromo", partNumber: "notAVapsPromo", discountedLineItemIds: [2], }, ]; const availableLineItems = [{ id: 1 }, { id: 2 }, { id: 3 }]; const lineItemsOnOrder = { vaps: [{ id: 1 }] }; const expectedReturn = []; // Act const actualReturn = promotionsHelper.getVapsThatNeedToBeAddedToSatisfyPromos( promos, availableLineItems, lineItemsOnOrder ); // Assert expect(actualReturn).toEqual(expectedReturn); }); }); describe("removeCurrentlyActivePromoCodesFromInactivePromos", () => { it("returns an empty array if inactivePromos is null or empty, don't break if activePromoObjects is null or empty", () => { // Arrange const nullActivePromoObjects = null; const emptyActivePromoObjects = []; const validActivePromoObjects = [{ promoCode: "validPromo" }]; const nullInactivePromos = null; const emptyInactivePromos = []; // Act const nullInactivePromosReturn = promotionsHelper.removeCurrentlyActivePromoCodesFromInactivePromos( validActivePromoObjects, nullInactivePromos ); const emptyInactivePromosReturn = promotionsHelper.removeCurrentlyActivePromoCodesFromInactivePromos( validActivePromoObjects, emptyInactivePromos ); const allNullReturn = promotionsHelper.removeCurrentlyActivePromoCodesFromInactivePromos( nullActivePromoObjects, nullInactivePromos ); const allEmptyReturn = promotionsHelper.removeCurrentlyActivePromoCodesFromInactivePromos( emptyActivePromoObjects, emptyInactivePromos ); // Assert expect(nullInactivePromosReturn).toEqual([]); expect(emptyInactivePromosReturn).toEqual([]); expect(allNullReturn).toEqual([]); expect(allEmptyReturn).toEqual([]); }); it("returns inactivePromos with active promos removed", () => { // Arrange const activePromoObjects = [{ promoCode: "activePromo" }]; const inactivePromos = ["activePromo", "inactivePromo"]; const expectedReturn = ["inactivePromo"]; // Act const actualReturn = promotionsHelper.removeCurrentlyActivePromoCodesFromInactivePromos( activePromoObjects, inactivePromos ); // Assert expect(actualReturn).toEqual(expectedReturn); }); it("returns inactivePromos with active bundle promos removed", () => { // Arrange const activePromoObjects = [ { promoCode: "activeBundlePromo/400" }, { promoCode: "activeBundlePromo/401" }, ]; const inactivePromos = ["activeBundlePromo", "inactivePromo"]; const expectedReturn = ["inactivePromo"]; // Act const actualReturn = promotionsHelper.removeCurrentlyActivePromoCodesFromInactivePromos( activePromoObjects, inactivePromos ); // Assert expect(actualReturn).toEqual(expectedReturn); }); it("returns all inactivePromos when no matching activePromo is supplied", () => { // Arrange const activePromoObjects = [{ promoCode: "activePromo" }]; const inactivePromos = ["inactivePromo1", "inactivePromo2"]; // Act const actualReturn = promotionsHelper.removeCurrentlyActivePromoCodesFromInactivePromos( activePromoObjects, inactivePromos ); // Assert expect(actualReturn).toEqual(inactivePromos); }); }); describe("shouldStripPromoQueryString", () => { it("returns false when provided with a null parameter", () => { // Arrange const nullFmgPageQueryValue = null; // Act const actualReturn = promotionsHelper.shouldStripPromoQueryString(nullFmgPageQueryValue); // Assert expect(actualReturn).toBeFalsy(); }); it("returns true when provided with a parameter from 'pagesToStripPromoQueryStringFrom", () => { // Arrange const fmgPageQueryValue = promotionsHelper.pagesToStripPromoQueryStringFrom[0]; // Act const actualReturn = promotionsHelper.shouldStripPromoQueryString(fmgPageQueryValue); // Assert expect(actualReturn).toBeTruthy(); }); }); describe("getNewlyInactivatedPromos", () => { it("returns an empty array if newInactivePromos is null or empty, does not break with null oldInactivePromos", () => { // Arrange const nullNewInactivePromos = null; const emptyNewInactivePromos = []; const validNewInactivePromos = [{ promoCode: "validPromo" }]; const nullOldInactivePromos = null; const validOldInactivePromos = ["validPromo"]; // Act const nullNewInactivePromosReturn = promotionsHelper.getNewlyInactivatedPromos( validOldInactivePromos, nullNewInactivePromos ); const emptyNewInactivePromosReturn = promotionsHelper.getNewlyInactivatedPromos( validOldInactivePromos, emptyNewInactivePromos ); const nullOldInactivePromosReturn = promotionsHelper.getNewlyInactivatedPromos( nullOldInactivePromos, validNewInactivePromos ); const allNullReturn = promotionsHelper.getNewlyInactivatedPromos( nullOldInactivePromos, nullNewInactivePromos ); // Assert expect(nullNewInactivePromosReturn).toEqual([]); expect(emptyNewInactivePromosReturn).toEqual([]); expect(allNullReturn).toEqual([]); // This return was to make sure no errors occurred expect(nullOldInactivePromosReturn).not.toBeNull(); }); it("returns only inactivePromos that were not already in oldInactivePromos", () => { // Arrange const newInactivePromos = [ { promoCode: "filteredPromo" }, { promoCode: "nonFilteredPromo" }, ]; const oldInactivePromos = ["filteredPromo"]; const expectedReturn = ["nonFilteredPromo"]; // Act const actualReturn = promotionsHelper.getNewlyInactivatedPromos( oldInactivePromos, newInactivePromos ); // Assert expect(actualReturn).toEqual(expectedReturn); }); it("returns only one new inactivePromos when a new promo bundle is inactivated", () => { // Arrange const newInactivePromos = [ { promoCode: "nonFilteredPromo/400" }, { promoCode: "nonFilteredPromo/401" }, ]; const oldInactivePromos = ["filteredPromo"]; const expectedReturn = ["nonFilteredPromo"]; // Act const actualReturn = promotionsHelper.getNewlyInactivatedPromos( oldInactivePromos, newInactivePromos ); // Assert expect(actualReturn).toEqual(expectedReturn); }); }); describe("createPromoErrorAlert", () => { it("returns different messages for stacking error codes and any others", () => { // Arrange const promoCode = "testPromo"; const additionalInfo = ["testAdditionalInfo"]; const stackingErrorCode = promotionsHelper.promoErrorCodes.PROMO_STACKING_NOT_ALLOWED; const nonStackingErrorCode = "nonStackingErrorCode"; // Act const stackingReturn = promotionsHelper.createPromoErrorAlert( promoCode, stackingErrorCode, additionalInfo ); const nonStackingReturn = promotionsHelper.createPromoErrorAlert( promoCode, nonStackingErrorCode, additionalInfo ); // Assert expect(stackingReturn).not.toEqual(nonStackingReturn); }); }); describe("getPromoCodesFromPromoObjectsWithoutDuplicates", () => { it("returns an empty array when promos is null or empty", () => { // Arrange const nullPromos = null; const emptyPromos = []; // Act const nullPromosReturn = promotionsHelper.getPromoCodesFromPromoObjectsWithoutDuplicates(nullPromos); const emptyPromosReturn = promotionsHelper.getPromoCodesFromPromoObjectsWithoutDuplicates(emptyPromos); // Assert expect(nullPromosReturn).toEqual([]); expect(emptyPromosReturn).toEqual([]); }); it("returns promo codes excluding normal and bundle duplicates", () => { // Arrange const promos = [ { promoCode: "duplicatePromo" }, { promoCode: "duplicatePromo" }, { promoCode: "bundlePromo/400" }, { promoCode: "bundlePromo/401" }, ]; const expectedReturn = ["duplicatePromo", "bundlePromo"]; // Act const actualReturn = promotionsHelper.getPromoCodesFromPromoObjectsWithoutDuplicates(promos); // Assert expect(actualReturn).toEqual(expectedReturn); }); }); }); describe("expected method calls tests", () => { describe("revalidatePromosAndValidateQueryStringPromo", () => { it("should call saveActiveAndOrInactivePromos store method upon revalidation AND validation", async () => { // Arrange const newPromo = "testPromo"; const pricedLineItems = null; const pageNameToLog = "testPage"; const revalidateResponse = { errors: [] }; const validateResponse = { orderPromos: [] }; store.getters.order.lineItems.promos = ["data"]; store.getters.order.payment.inactivePromos = ["data"]; mockReturnsForStoreActions[ storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA ] = revalidateResponse; mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = validateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith( storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, expect.anything(), expect.anything() ); expect(baseMixin.methods.dispatchStoreAction).toBeCalledTimes(2); }); it("should save an inactive promo if the newPromo is invalid, not on the order, and has the right error code", async () => { // This is behavior needed to let a query string promo activate if they later // change their order and it becomes valid // Arrange const newPromo = "testPromo"; const pricedLineItems = null; const pageNameToLog = "testPage"; // Query string promos are added to inactive if it's a valid promo that doesn't currently work // No suitable item for promo is an example of this const validateResponse = { promoCode: newPromo, errorCode: promotionsHelper.promoErrorCodes.NO_SUITABLE_ITEM_FOR_PROMO, }; mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = validateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith( storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, { inactivePromos: ["testPromo"] }, expect.anything() ); }); it("should not save an inactive promo if the promo is already an active promo (read comment below)", async () => { // should NOT save an inactive promo if the newPromo is invalid, // not on the order, and has the right error code - but the promo // is already in the store as active // This is behavior needed to make sure the query string inactive logic above // doesn't result in duplicated promos // Arrange const newPromo = "testPromo"; const pricedLineItems = null; const pageNameToLog = "testPage"; store.getters.order.lineItems.promos = [{ promoCode: newPromo }]; const revalidateResponse = { errors: [] }; const validateResponse = { promoCode: newPromo, errorCode: promotionsHelper.promoErrorCodes.NO_SUITABLE_ITEM_FOR_PROMO, }; mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = validateResponse; mockReturnsForStoreActions[ storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA ] = revalidateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(baseMixin.methods.dispatchStoreAction).not.toBeCalledWith( storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, { inactivePromos: ["testPromo"] }, expect.anything() ); }); it("should not save an inactive promo if the promo is on the 'excludeFromInactivePromoErrorCodes' list", async () => { // The excludeFromInactivePromoErrorCodes list includes promos that will never be valid // so there is no value in adding them to the 'inactivePromos' in the store for future // use // Arrange const newPromo = "testPromo"; const pricedLineItems = null; const pageNameToLog = "testPage"; const validateResponse = { promoCode: newPromo, errorCode: promotionsHelper.excludeFromInactivePromoErrorCodes[0], }; mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = validateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(baseMixin.methods.dispatchStoreAction).not.toBeCalledWith( storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, expect.anything(), expect.anything() ); }); it("should not save an inactive promo if the promo is already in the store as inactive", async () => { // Arrange const newPromo = "testPromo"; const pricedLineItems = null; const pageNameToLog = "testPage"; const revalidateResponse = { errors: [] }; const validateResponse = { promoCode: newPromo, errorCode: "someError" }; store.getters.order.payment.inactivePromos = [newPromo]; mockReturnsForStoreActions[ storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA ] = revalidateResponse; mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = validateResponse; // Act const { validatePromoResponse, revalidatePromoResponse } = await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( newPromo, pricedLineItems, pageNameToLog ); // Assert expect(baseMixin.methods.dispatchStoreAction).not.toBeCalledWith( storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, { inactivePromos: [newPromo] }, expect.anything() ); }); it("should call SAVE_INACTIVE_AND_OR_ACTIVE_PROMOS with a list of strings for the inactivePromos parameter", async () => { // The store method expects a list of strings for inactivePromos, this call needs to satisfy that // Arrange store.getters.order.lineItems.promos = ["data"]; store.getters.order.payment.inactivePromos = ["data"]; const revalidateResponse = { promoLineItems: ["data"], errors: [ { id: 1, promoCode: "testPromo1" }, { id: 2, promoCode: "testPromo2" }, ], }; mockReturnsForStoreActions[ storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA ] = revalidateResponse; // Act await promotionsHelper.revalidatePromosAndValidateQueryStringPromo( null, null, null ); // Assert expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, { activePromos: expect.anything(), inactivePromos: ["testPromo1", "testPromo2"], }, false ); }); }); }); });