CSR-886: unit tests for Schedule page

This commit is contained in:
Adam Caouette 2023-08-14 10:57:10 -04:00
parent ed3d25ee48
commit a8154dc8c6
5 changed files with 576 additions and 161 deletions

View file

@ -17,7 +17,6 @@ module.exports = {
"!src/ux-components/text-link/**/*.vue",
"!src/layouts/vin-lookup/**/*.vue", //Temporary for Quote page testing
"!src/common-components/funnel-header/menu-modal/**/*.vue",
"!src/layouts/schedule/*.vue", // Temp test exclusion while in development
"!src/layouts/schedule/helpers/schedule-helper.js", // Temp test exclusion while in development
"!src/layouts/review/*.vue", // Temp test exclusion while in development
// END

View file

@ -681,7 +681,6 @@ function setupMocks({
},
],
router: {
navigate: jest.fn(),
navigate: jest.fn(),
navigateWithSaving: jest.fn(),
navigateWithoutSaving: jest.fn(),

View file

@ -1,15 +1,77 @@
// Components
import schedule from "@/layouts/schedule/schedule.vue";
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { applicationConfig } from "@/constants/application-config";
import { storeActions } from "@/constants/store-actions";
import schedule from "@/layouts/schedule/schedule.vue";
import store from "@/store";
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
import router from "@/router";
import { nextTick } from "vue";
import baseMixin from "../../mixins/base-mixin";
jest.mock("@/store", () => ({
commit: jest.fn(),
dispatch: jest.fn(),
// Mock basemixin
jest.mock("@/mixins/base-mixin.js", () => ({
methods: {
dispatchStoreAction: jest.fn().mockImplementation((storeAction) => {
if (storeAction === "getShopTimeSlots") {
return {
data: {
estimatedServiceMinutesMinimum: 90,
estimatedServiceMinutesMaximum: 120,
days: [
{
date: "2023-12-01",
timeSlots: [
{
id: "06747-01820-S-B*20424*7 AM",
startTime: "07:00",
endTime: "08:00",
offerPremium: false,
},
],
},
],
},
};
}
if (storeAction === "getMobilePremiumFee") {
return Promise.resolve({
data: {
partNumber: "EARLY BIRD",
description: null,
partType: "EARLY BIRD",
laborAmount: 0,
sellingPrice: 14.99,
kitPrice: 0,
},
});
}
if (storeAction === "priceOrderItemsAndSaveServerData") {
return Promise.resolve([
{
partNumber: "EARLY BIRD",
description: null,
partType: "EARLY BIRD",
laborAmount: 0,
sellingPrice: 14.99,
kitPrice: 0,
},
]);
}
if (storeAction === "saveSupportingItemsSuppressingStateResetting") {
return Promise.resolve([
{
partNumber: "EARLY BIRD",
description: null,
partType: "EARLY BIRD",
laborAmount: 0,
sellingPrice: 14.99,
kitPrice: 0,
},
]);
}
}),
},
}));
// Mock fetchCmsContentForPage
@ -18,50 +80,415 @@ jest.mock("@/helpers/cms-content-helper", () => ({
splitCopyOnCMSPlaceHolder: jest.fn(() => ["A", "B"]),
}));
jest.mock(
"@/store",
() => {
return {};
},
{ virtual: true }
);
store.getters = {
order: {
schedule: {
date: "2020-01-01",
beforeEach(() => {
jest.restoreAllMocks();
jest.clearAllMocks();
store.getters = {
order: {
schedule: {
date: "2019-01-01",
startTime: "09:00",
endTime: "10:00",
routeCode: "000"
},
lineItems: {
glassParts: [
{
partNumber: "ABC123",
},
],
supportingItems: [],
},
serviceLocation: {
appointmentType: "Inshop",
zipCode: "12345",
zipCodeCtu: "01234",
provider: {
providerNumber: "123",
},
},
damage: {
isRepair: false,
},
referralNumber: "1234567",
},
payment: {
isInsurance: true,
},
lineItems: {
glassParts: [],
supportingItems: [],
},
serviceLocation: {
appointmentType: "Inshop",
},
},
lineItems: {
glassParts: [],
supportingItems: [],
},
};
};
});
afterEach(() => {
store.getters = {};
jest.restoreAllMocks();
jest.clearAllMocks();
});
describe("schedule.vue", () => {
test("Should navigateWithoutSaving", async () => {
//Arrange
const { wrapper } = setupMocks({
customMountOptions: {
router: {
navigateWithSaving: jest.fn(),
},
route: { schedule },
},
describe("schedule.vue...", () => {
describe("initial load", () => {
test("should pass arePagePrerequisitesValid with a mobile order and no providerNumber", () => {
//Arrange
const { wrapper } = setupMocks({});
store.getters.order.serviceLocation.appointmentType = "Mobile";
store.getters.order.serviceLocation.provider = null;
//Act
const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test("should pass arePagePrerequisitesValid with a inshop order and providerNumber", () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test("should fail arePagePrerequisitesValid with a replace with no glass parts", async () => {
//Arrange
const { wrapper } = setupMocks({});
store.getters.order.lineItems.glassParts = [];
//Act
const arePagePrerequisitesValid2 = await wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid2).toBe(false);
});
test("should fail arePagePrerequisitesValid without isInsurance", () => {
//Arrange
const { wrapper } = setupMocks({});
store.getters.payment.isInsurance = null;
//Act
const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(false);
});
test("should return newShopTimeSlots when getAvailableDatesMethod is called", async () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
//Act
const newShopTimeSlots = await wrapper.vm.getAvailableDatesMethod(
"2023-01-01",
"2023-01-31"
);
//Assert
expect(newShopTimeSlots).toStrictEqual({
days: [
{
date: "2023-12-01",
timeSlots: [
{
endTime: "08:00",
id: "06747-01820-S-B*20424*7 AM",
offerPremium: false,
startTime: "07:00",
},
],
},
],
estimatedServiceMinutesMinimum: 90,
estimatedServiceMinutesMaximum: 120,
});
});
test("should call API service in day ranges of 34 or less when getAvailableDatesMethod is called with large date ranges", async () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
//Act
await wrapper.vm.getAvailableDates.call(
wrapper.vm,
"2023-01-01",
"2023-03-31",
"Inshop",
"123"
);
//Assert
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledTimes(3);
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
"getShopTimeSlots",
expect.anything(),
expect.anything()
);
});
describe("beforeRouteEnter function... ", () => {
test("should call next() and call all functions within next", async () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
wrapper.vm.updateFooterButtonText = jest.fn();
const nextFunction = jest.fn((c) => {
c(wrapper.vm);
});
//Act
await schedule.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "schedule" } },
undefined,
nextFunction
);
//Assert
expect(nextFunction).toHaveBeenCalled();
expect(wrapper.vm.setCmsContent).toHaveBeenCalledWith("content");
expect(wrapper.vm.$refs.datePicker.initializeComponent).toHaveBeenCalledWith(
expect.objectContaining({
calendarViewDirection: "future",
})
);
expect(wrapper.vm.$refs.locationAlerts.initializeComponent).toHaveBeenCalled();
expect(wrapper.vm.selectableDatesData).toStrictEqual(
expect.objectContaining({
days: expect.any(Array),
estimatedServiceMinutesMaximum: expect.any(Number),
estimatedServiceMinutesMinimum: expect.any(Number)
})
);
expect(wrapper.vm.mobilePremiumAppointmentFee).toStrictEqual(
expect.objectContaining({
partNumber: expect.any(String)
})
);
expect(wrapper.vm.updateFooterButtonText).toHaveBeenCalled();
});
});
describe("computed properties...", () => {
test("timeSlotsForSelectedDate should return timeslots if selected date is available", () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [{
"date": "2022-11-11",
"timeSlots": [
{
"id": "1820I-01820-M-I*20425*AM",
"startTime": "08:00",
"endTime": "12:00",
"offerPremium": true
},
{
"id": "1820I-01820-M-I*20425*PM",
"startTime": "12:00",
"endTime": "17:00",
"offerPremium": false
}
]
}],
};
wrapper.setData({
selectedDate: "2022-11-11"
});
//Act
const testValue = wrapper.vm.timeSlotsForSelectedDate;
//Assert
expect(testValue).toStrictEqual(
expect.objectContaining({
"date": "2022-11-11"
})
);
});
test("timeSlotsForSelectedDate should be null if no date has been selected", () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [{
"date": "2022-11-11",
"timeSlots": [
{
"id": "1820I-01820-M-I*20425*AM",
"startTime": "08:00",
"endTime": "12:00",
"offerPremium": true
},
{
"id": "1820I-01820-M-I*20425*PM",
"startTime": "12:00",
"endTime": "17:00",
"offerPremium": false
}
]
}],
};
wrapper.setData({
selectedDate: undefined
});
//Act
const testValue = wrapper.vm.timeSlotsForSelectedDate;
//Assert
expect(testValue).toBe(null)
});
});
});
describe("schedule page methods...", () => {
test("getServiceZipCtuCodeFromStore should return zipCodeCtu", () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
//Act
const testValue = wrapper.vm.getServiceZipCtuCodeFromStore();
//Assert
expect(testValue).toStrictEqual(
"01234"
);
});
test("openInshopTimeSlotsModal should trigger openModal method", () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
//Act
wrapper.vm.openInshopTimeSlotsModal();
//Assert
expect(wrapper.vm.$refs.timeSlotModalQuestion.openModal).toBeCalled();
});
test("getSelectedRouteCode should return schedule routeCode", () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
//Act
const testValue = wrapper.vm.getSelectedRouteCode();
//Assert
expect(testValue).toStrictEqual(
"000"
);
});
test("timeSlotModalClosed should null any selected date when there's no route code", () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
wrapper.setData({
selectedDate: "1980-05-05"
});
wrapper.setData({
selectedTimeSlot: {
date: "2019-01-01",
startTime: "09:00",
endTime: "10:00",
routeCode: null
}
});
//Act
wrapper.vm.timeSlotModalClosed();
//Assert
expect(wrapper.vm.selectedDate).toBe(null);
});
test("getDisplayTextForMilitaryTime should return the correctly formatted string", () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
const timeInput1 = "15:00";
const timeInput2 = "15:30";
//Act
const testOutput1 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput1);
const testOutput2 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput2);
const testOutput3 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput1, true);
const testOutput4 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput2, true);
//Assert
expect(testOutput1).toBe("3:00 PM");
expect(testOutput2).toBe("3:30 PM");
expect(testOutput3).toBe("3 PM");
expect(testOutput4).toBe("3:30 PM");
});
test("getDisplayTextForMilitaryTime should return the correctly formatted string", () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.selectableDatesData = {
days: [],
};
wrapper.vm.$router.navigateWithoutSaving = jest.fn();
wrapper.vm.$route = "testRoute";
//Act
wrapper.vm.backButtonAction();
//Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith("CLICKED_BACK", "testRoute");
});
});
test("forwardButtonAction should call route method navigateWithoutSaving", async () => {
//Arrange
const { wrapper } = setupMocks({});
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
wrapper.vm.$router.navigateWithSaving = jest.fn(() => {
return {};
});
//Act
await wrapper.vm.forwardButtonAction();
@ -69,137 +496,125 @@ describe("schedule.vue", () => {
//Assert
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
});
test("should pass arePagePrerequisitesValid with a mobile order and no providerNumber", () => {
test("for mobile appts, updateSupportingItems should call store action to save supporting items", async () => {
//Arrange
store.getters.order.serviceLocation.appointmentType = "Mobile";
store.getters.lineItems.supportingItems = [{
"partNumber": "EARLY BIRD",
"description": null,
"partType": "EARLY BIRD",
"laborAmount": 0,
"sellingPrice": 0,
"kitPrice": 0
}];
const { wrapper } = setupMocks({});
store.getters = {
order: {
schedule: {
date: "2020-01-01",
},
serviceLocation: {
zipCode: "12345",
zipCodeCtu: "value",
appointmentType: "Mobile",
},
damage: {
isRepair: true,
},
referralNumber: "1234567",
},
payment: {
isInsurance: true,
},
lineItems: {
supportingItems: [],
},
};
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
wrapper.vm.mobilePremiumAppointmentFee = 14.99;
wrapper.setData({
selectedTimeSlot: {
date: "2019-01-01",
startTime: "09:00",
endTime: "10:00",
routeCode: null,
isPremiumAppointment: true
}
});
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Act
await wrapper.vm.updateSupportingItems();
//Assert
expect(wrapper.vm.dispatchStoreAction).toBeCalledWith(
"saveSupportingItemsSuppressingStateResetting",
expect.arrayContaining([
expect.objectContaining({
partType: "EARLY BIRD"
})
]),
expect.anything()
);
expect(arePagePrerequisitesValid).toBe(true);
});
test("should pass arePagePrerequisitesValid with a inshop order and providerNumber", () => {
test("for Inshop appts, updateSupportingItems should call store action to save supporting items WITHOUT the EARLY BIRD supporting item", async () => {
//Arrange
store.getters.order.serviceLocation.appointmentType = "Inshop";
store.getters.lineItems.supportingItems = [{
"partNumber": "EARLY BIRD",
"description": null,
"partType": "EARLY BIRD",
"laborAmount": 0,
"sellingPrice": 0,
"kitPrice": 0
}];
const { wrapper } = setupMocks({});
store.getters = {
order: {
schedule: {
date: "2020-01-01",
},
serviceLocation: {
zipCode: "12345",
zipCodeCtu: "value",
appointmentType: "Inshop",
provider: {
providerNumber: "5",
},
},
damage: {
isRepair: true,
},
referralNumber: "1234567",
},
payment: {
isInsurance: true,
},
lineItems: {
supportingItems: [],
},
};
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
wrapper.vm.mobilePremiumAppointmentFee = 14.99;
wrapper.setData({
selectedTimeSlot: {
date: "2019-01-01",
startTime: "09:00",
endTime: "10:00",
routeCode: null,
isPremiumAppointment: true
}
});
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Act
await wrapper.vm.updateSupportingItems();
//Assert
expect(wrapper.vm.dispatchStoreAction).toBeCalledWith(
"saveSupportingItemsSuppressingStateResetting",
expect.not.arrayContaining([
expect.objectContaining({
partType: "EARLY BIRD"
})
]),
expect.anything()
);
expect(arePagePrerequisitesValid).toBe(true);
});
test("should fail arePagePrerequisitesValid with a replace with no glass parts", () => {
test("if no EARLY BIRD supporting item, then updateSupportingItems should NOT call store action", async () => {
//Arrange
store.getters.order.serviceLocation.appointmentType = "Mobile";
store.getters.lineItems.supportingItems = [];
const { wrapper } = setupMocks({});
store.getters = {
order: {
schedule: {
date: "2020-01-01",
},
serviceLocation: {
zipCode: "12345",
zipCodeCtu: "value",
appointmentType: "Inshop",
provider: {
providerNumber: "5",
},
},
damage: {
isRepair: false,
},
referralNumber: "1234567",
},
payment: {
isInsurance: true,
},
lineItems: {
supportingItems: [],
glassParts: [],
},
};
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
wrapper.vm.mobilePremiumAppointmentFee = 14.99;
wrapper.setData({
selectedTimeSlot: {
date: "2019-01-01",
startTime: "09:00",
endTime: "10:00",
routeCode: null,
isPremiumAppointment: false
}
});
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Act
await wrapper.vm.updateSupportingItems();
//Assert
expect(wrapper.vm.dispatchStoreAction).not.toBeCalled();
expect(arePagePrerequisitesValid).toBe(false);
});
test("should fail arePagePrerequisitesValid without isInsurance", () => {
//Arrange
const { wrapper } = setupMocks({});
store.getters = {
order: {
schedule: {
date: "2020-01-01",
},
serviceLocation: {
zipCode: "12345",
zipCodeCtu: "value",
appointmentType: "Inshop",
provider: {
providerNumber: "5",
},
},
damage: {
isRepair: true,
},
referralNumber: "1234567",
},
payment: {
isInsurance: null,
},
lineItems: {
supportingItems: [],
glassParts: [],
},
};
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
expect(arePagePrerequisitesValid).toBe(false);
});
});
const mockCmsContent = {};
@ -210,6 +625,7 @@ function setupMocks({ customMountOptions }) {
});
mountOptions.global.mocks["$store"] = store;
mountOptions.global.mocks["$router"] = router;
mountOptions["attachTo"] = document.body;
mountOptions.mixins = [
{
@ -223,6 +639,12 @@ function setupMocks({ customMountOptions }) {
];
const wrapper = shallowMount(schedule, mountOptions);
wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.$refs.datePicker.initializeComponent = jest.fn();
wrapper.vm.$refs.locationAlerts.initializeComponent = jest.fn();
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.timeSlotModalQuestion.openModal = jest.fn();
return { wrapper };
}

View file

View file

@ -320,6 +320,7 @@ export default {
);
return newShopTimeSlots;
},
getAvailableDates,
getServiceZipCtuCodeFromStore() {
return store.getters.order.serviceLocation.zipCodeCtu;
},
@ -338,12 +339,6 @@ export default {
getSupportingItems() {
return store.getters.lineItems.supportingItems;
},
isMobilePremiumFeeOnOrderInVuex() {
const supportingItemsFromVuex = store.getters.lineItems.supportingItems;
return !!supportingItemsFromVuex.filter(
(lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE
).length;
},
timeSlotModalClosed() {
// Clear the selectedDate if no timeSlot has been selected
if (this.selectedTimeSlot.routeCode == null) {