DigitalConsumer.FixMyGlass/src/layouts/payment/payment.spec.js
CarlNation 43933480b5 CASH-60
CASH-60 remove the async await from the payment page prereqs.  Causes a promise to be returned instead of a bool.  Moved it to the router instead
2025-01-03 13:44:56 -05:00

620 lines
18 KiB
JavaScript

// Components
import payment from "@/layouts/payment/payment";
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
import { storeActions } from "@/constants/store-actions";
import { paymentMethods } from "@/constants/payment-method-constants";
// Constants
const parts = {
windshield: {
name: "windshield",
canSafeliteRecalibrate: true,
childParts: [],
color: "Green Tint",
description:
"solar, soundproofing, lane keep assist, lane departure warning system, w/adaptive cruise control",
id: "db22fd44-10dd-456f-979b-ff88cf68cca6",
partNumber: "FW04896GTYN",
partType: "WINDSHIELD",
recalibrationType: "STATIC",
requiresCapabilityQuestions: false,
requiresRecalibration: true,
salesTax: 63.86,
sellingPrice: 791.46,
},
frontWipers: {
name: "front wipers",
partNumber: "SBB16",
description: "SAFELITE BEAM BLADE 16",
partType: "FRONT WIPER",
price: 32.64,
},
rearWipers: {
name: "rear wipers",
partNumber: "SBBR12A",
description: "SAFELITE REAR BLADE 12A",
partType: "REAR WIPER",
price: 24.48,
},
rainDefense: {
name: "rain defense",
partNumber: "RAIN DEFENSE",
description: null,
partType: "RAIN DEFENSE",
price: 35.5,
},
};
const pricedParts = {
windshield: {
...parts.windshield,
kitPrice: 0,
laborAmount: 60,
salesTax: 0,
sellingPrice: 791.46,
},
frontWipers: {
...parts.frontWipers,
kitPrice: 0,
laborAmount: 20,
salesTax: 0,
sellingPrice: 32.64,
},
rearWipers: {
...parts.rearWipers,
kitPrice: 10,
laborAmount: 10,
salesTax: 0,
sellingPrice: 24.48,
},
rainDefense: {
...parts.rainDefense,
kitPrice: 20,
laborAmount: 0,
salesTax: 0,
sellingPrice: 35.5,
},
};
const taxedParts = {
windshield: {
...pricedParts.windshield,
salesTax: 63.86,
subTotal: 100,
},
frontWipers: {
...pricedParts.frontWipers,
salesTax: 2.36,
subTotal: 100,
},
rearWipers: {
...pricedParts.rearWipers,
salesTax: 6.0,
subTotal: 100,
},
rainDefense: {
...pricedParts.rainDefense,
salesTax: 1.0,
subTotal: 100,
},
};
// Setup global mocks
let mockCmsContent = {};
let mockStoreActionData = {};
async function mockDispatchStoreAction(actionName) {
return mockStoreActionData[actionName];
}
jest.mock("@/mixins/base-mixin.js", () => ({
methods: {
dispatchStoreAction: jest.fn().mockImplementation(mockDispatchStoreAction),
dispatchStoreActionWithLogging: jest.fn().mockImplementation(mockDispatchStoreAction),
getAmountDue: jest.fn().mockImplementation(() => 5),
getDisplayAmountDue: jest.fn().mockImplementation(() => "$5.00"),
},
}));
jest.mock("@/helpers/promotions-helper", () => ({
revalidatePromosAndValidateQueryStringPromo: async () => ({}),
getVapsThatNeedToBeAddedToSatisfyPromos: () => [],
}));
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: () => Promise.resolve("content"),
}));
describe("payment.vue", () => {
beforeEach(() => {
store.getters = {
order: {
vehicle: {
year: "2020",
make: "acura",
model: "mdx",
style: "4-door sedan",
carId: "dummyCarId",
category: "dummyCategory",
vin: "dummyVin",
},
serviceLocation: {
address: "add1",
address2: "add2",
city: "city",
state: "state",
zipCode: "zip",
zipCodeCtu: "zipCtu",
appointmentType: "IN_SHOP",
isVehicleProtected: true,
provider: {
providerNumber: 2,
address: {
streetAddress: "add3",
city: "city2",
state: "state2",
zipCode: "zip2",
zipCodeCtu: "zipCtu2",
},
},
techNotes: "",
},
customer: {
firstName: "first",
lastName: "last",
emailAddress: "builddigitaltest@safelite.com",
phoneNumber: "555-555-5555",
isSmsOptIn: false,
},
damage: {
isRepair: false,
numberOfChips: null,
glassToReplace: [{ location: "windshield" }],
},
lineItems: {
glassParts: [parts.windshield],
supportingItems: [],
vaps: [parts.frontWipers],
promos: [],
},
payment: {
isInsurance: false,
insuranceCoverage: {
isVerified: null,
coverageStatus: null,
coverageVerificationType: null,
},
isPia: true,
piaType: "Afterpay",
inactivePromos: [],
},
schedule: {
date: "date",
startTime: "start",
endTime: "end",
jobMinMinutes: "30",
jobMaxMinutes: "45",
},
},
applicationUser: {
loggingOption: false,
},
policy: {
currentDeductible: 1,
},
get payment() {
return this.order.payment;
},
get vehicle() {
return this.order.vehicle;
},
};
mockCmsContent = {};
mockStoreActionData = {
[storeActions.GET_SIGNATURE]: {
token: "token",
signature: "signature",
startDate: "startDate",
},
[storeActions.GET_WIPERS]: [parts.frontWipers, parts.rearWipers],
[storeActions.GET_RAIN_DEFENSE]: parts.rainDefense,
[storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA]: [
pricedParts.windshield,
pricedParts.frontWipers,
],
[storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA]: [
taxedParts.windshield,
taxedParts.frontWipers,
],
};
});
afterEach(() => {
jest.clearAllMocks();
});
describe("arePagePrerequisitesValid", () => {
test("Returns true in nominal conditions", () => {
// Arrange
// Store defaults are valid
const wrapper = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(result).toBe(true);
});
describe("Payment method cases", () => {
test("Returns false if pia options are not valid", () => {
// Arrange
store.getters.order.payment.isPia = null;
store.getters.order.payment.piaType = null;
const wrapper = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(result).toBe(false);
});
test("Returns false if pay at time of service", () => {
// Arrange
store.getters.order.payment.isPia = false;
store.getters.order.payment.piaType = null;
const wrapper = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(result).toBe(false);
});
});
});
describe("beforeRouteEnter", () => {
test("Properly initializes fields and kicks off hop", async () => {
// Arrange
const vmMock = {
setCmsContent: jest.fn(),
$refs: {
cart: {
cartItems: [],
},
},
getPiaLineItems: jest.fn(),
fetchSignatureInfo: jest.fn(),
setIFrameListener: jest.fn(),
$nextTick: (f) => {
f();
},
};
const nextF = (f) => {
f(vmMock);
};
// Act
await payment.beforeRouteEnter.call(
vmMock,
{ query: { fmgPage: "payment" } },
undefined,
nextF
);
// Assert
expect(vmMock.availableVaps).not.toBeUndefined();
expect(vmMock.lineItems).not.toBeUndefined();
expect(vmMock.setCmsContent).toBeCalled();
expect(vmMock.getPiaLineItems).toBeCalled();
expect(vmMock.fetchSignatureInfo).toBeCalled();
expect(vmMock.setIFrameListener).toBeCalled();
});
});
describe("payment type mapping", () => {
describe("getPaymentType", () => {
test("Maps AFTERPAY -> ap", () => {
// Arrange
store.getters.order.payment.piaType = paymentMethods.AFTERPAY;
const wrapper = setupMocks({});
// Act
const mapped = wrapper.vm.getPaymentType();
// Assert
expect(mapped).toBe("ap");
});
test("Maps CREDIT_CARD -> cc", () => {
// Arrange
store.getters.order.payment.piaType = paymentMethods.CREDIT_CARD;
const wrapper = setupMocks({});
// Act
const mapped = wrapper.vm.getPaymentType();
// Assert
expect(mapped).toBe("cc");
});
test("Maps PAYPAL -> pp", () => {
// Arrange
store.getters.order.payment.piaType = paymentMethods.PAYPAL;
const wrapper = setupMocks({});
// Act
const mapped = wrapper.vm.getPaymentType();
// Assert
expect(mapped).toBe("pp");
});
test("Maps other values to self", () => {
// Arrange
store.getters.order.payment.piaType = "SomeOtherText";
const wrapper = setupMocks({});
// Act
const mapped = wrapper.vm.getPaymentType();
// Assert
expect(mapped).toBe("SomeOtherText");
});
});
describe("isPaypal", () => {
test("Is responsive if initial data changes", async () => {
// Arrange
// note: begins with payment-type = afterpay
const wrapper = setupMocks({});
// Act
const preVal = wrapper.vm.isPaypal;
wrapper.vm.paymentType = "pp";
await wrapper.vm.$nextTick();
const postVal = wrapper.vm.isPaypal;
// Assert
expect(preVal).toBe(false);
expect(postVal).toBe(true);
});
});
});
describe("getPiaLineItems", () => {
test("Properly formatted output", () => {
// Arrange
const wrapper = setupMocks({});
const cartItems = [
taxedParts.windshield,
taxedParts.frontWipers,
taxedParts.rainDefense,
];
// Act
wrapper.vm.getPiaLineItems(cartItems);
const result = wrapper.vm.piaLineItems;
// Assert
expect(result).toMatch(/^[\w ]+\|[\d]+(.\d\d)?\|1(\|\|[\w ]+\|[\d]+(.\d\d)?\|1)*$/);
});
test("Includes repair supply for non-glass orders", () => {
// Arrange
store.getters.order.lineItems.glassParts = null;
const wrapper = setupMocks({});
const cartItems = [taxedParts.frontWipers, taxedParts.rainDefense];
// Act
wrapper.vm.getPiaLineItems(cartItems);
const result = wrapper.vm.piaLineItems;
// Assert
expect(result).toMatch(/Repair supplies/);
});
test("Does not include promos", () => {
// Arrange
store.getters.order.lineItems.promos = [
{
name: "PROMO",
salesTax: 10,
subTotal: 20,
},
];
const wrapper = setupMocks({});
const cartItems = [
taxedParts.windshield,
taxedParts.frontWipers,
taxedParts.rainDefense,
];
// Act
wrapper.vm.getPiaLineItems(cartItems);
const result = wrapper.vm.piaLineItems;
// Assert
expect(result).not.toMatch(/PROMO/);
});
});
describe("hop form", () => {
describe("fetchSignatureInfo", () => {
test("Sets auth fields", async () => {
// Arrange
const signature = {
token: "TOKEN",
signature: "SIGNATURE",
startDate: "STARTDATE",
};
const wrapper = setupMocks({});
wrapper.vm.submitHopForm = jest.fn();
// Act
await wrapper.vm.fetchSignatureInfo(signature);
// Assert
expect(wrapper.vm.authToken).toBe(signature.token);
expect(wrapper.vm.authSignature).toBe(signature.signature);
expect(wrapper.vm.authSignatureStart).toBe(signature.startDate);
expect(wrapper.vm.submitHopForm).toBeCalled();
});
test("If paypal, show the loading modal", async () => {
// Arrange
const signature = {
token: "TOKEN",
signature: "SIGNATURE",
startDate: "STARTDATE",
};
store.getters.order.payment.piaType = "Paypal";
const wrapper = setupMocks({});
wrapper.vm.submitHopForm = jest.fn();
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
// Act
await wrapper.vm.fetchSignatureInfo(signature);
// Assert
expect(wrapper.vm.$refs.loadingModal.showModal).toBeCalled();
});
});
describe("submitHopForm", () => {
test("Submits form", async () => {
// Arrange
const wrapper = setupMocks({});
wrapper.vm.$refs.hopForm.submit = jest.fn();
wrapper.vm.$refs.paymentFrame = null;
// Act
wrapper.vm.submitHopForm();
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.$refs.hopForm.submit).toBeCalled();
});
});
describe("handleIFrameContentWindowMessage", () => {
test("Navigates back if afterpay is closed", () => {
// Arrange
const event = {
data: "afterpayClosed",
};
const wrapper = setupMocks({});
wrapper.vm.backButtonAction = jest.fn();
// Act
wrapper.vm.handleIFrameContentWindowMessage(event);
// Assert
expect(wrapper.vm.backButtonAction).toBeCalled();
});
test("Blocks UI interaction if credit card is submitted", () => {
// Arrange
const event = {
data: "creditCardSubmit",
};
const wrapper = setupMocks({});
// Act
wrapper.vm.handleIFrameContentWindowMessage(event);
// Assert
expect(wrapper.vm.shouldBlockInteraction).toBe(true);
});
});
});
describe("UI Blocking", () => {
test("UI block appears when toggled", async () => {
// Arrange
const wrapper = setupMocks({});
// Act
wrapper.vm.setUIBlock(true);
await wrapper.vm.$nextTick();
const uiBlockElements = wrapper.findAll(".ui-block");
// Assert
expect(uiBlockElements.length).toBeGreaterThan(0);
});
test("Don't propogate clicks from UI block", async () => {
// Arrange
const wrapper = setupMocks({});
const outerDiv = wrapper.find(".container-fluid");
const clickFn = jest.fn();
outerDiv.element.addEventListener("click", clickFn);
// Act
wrapper.vm.setUIBlock(true);
await wrapper.vm.$nextTick();
const uiBlockElement = wrapper.find(".ui-block");
await uiBlockElement.trigger("click");
// Assert
expect(clickFn).not.toBeCalled();
});
});
});
function setupMocks({ customMountOptions }) {
const mountOptions = getMountOptions({
...customMountOptions,
route: { query: { fmgPage: "page-name" }, params: {} },
});
// set all mock stuff
mountOptions.global.mocks["$store"] = store;
mountOptions.mixins = [
{
methods: {
getCmsContent: jest.fn().mockImplementation((widgetName, fieldName) => {
if (mockCmsContent[widgetName] && mockCmsContent[widgetName][fieldName])
return mockCmsContent[widgetName][fieldName];
}),
setCmsContent: jest.fn(),
},
},
];
const wrapper = shallowMount(payment, mountOptions);
// act on vm
return wrapper;
}