DigitalConsumer.FixMyGlass/src/helpers/promotions-helper.spec.js
Scott Kiener f0534f2718 Promo Unit tests - promotions-helper.js
Also made promotions-helper.js functions null safe
2024-01-17 09:55:03 -05:00

1215 lines
53 KiB
JavaScript

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";
// <promos> setup
const nullPromos = null;
const emptyPromos = [];
const promosWithNullDiscountedLineItemIds = [{ discountedLineItemIds: null }];
const promosWithEmptyDiscountedLineItemIds = [{ discountedLineItemIds: [] }];
const validPromosWithOnePromo = [{ discountedLineItemIds: [validGuidForId] }];
// <availableLineItems setup
const nullAvailableLineItems = null;
const emptyAvailableLineItems = [];
const validAvailableLineItemsWithOneItem = [{ id: validGuidForId }];
// Act
// Null or Empty <promos> 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 <availableLineItems> scenarios
const nullAvailableLineItemsReturn = promotionsHelper.getLineItemsThatMatchPromos(
validPromosWithOnePromo,
nullAvailableLineItems
);
const emptyAvailableLineItemsReturn = promotionsHelper.getLineItemsThatMatchPromos(
validPromosWithOnePromo,
emptyAvailableLineItems
);
// Assert
// Null or Empty <promos> assertions
expect(nullPromosReturn).toEqual([]);
expect(emptyPromosReturn).toEqual([]);
expect(nullDiscountedLineItemsReturn).toEqual([]);
expect(emptyDiscountedLineItemsReturn).toEqual([]);
// Null or Empty <availableLineItems> 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
);
});
});
});
});