import { shallowMount, mount } from "@vue/test-utils"; import servicePackageQuestion from "./service-package-question"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { expectedModifiedAnswers, mockProcessedCmsContent, inputQuestionWidgetAnswers, } from "./service-package-question-test-helper"; import { containsLineItemWithPartType, findLineItemsWithPartType, } from "@/helpers/service-package-helper"; import { experimentSettings } from "@/constants/experiments"; import baseMixin from "@/mixins/base-mixin.js"; import { partTypeStrings } from "@/constants/part-type-strings"; import { nextTick } from "vue"; import { packageNames } from "../../../constants/package-names"; jest.mock("@/store", () => ({ commit: jest.fn(), dispatch: jest.fn(), getters: { applicationUser: { loggingOption: false, }, }, })); const mockExperimentSettings = experimentSettings; jest.mock("@/mixins/experiment-mixin.js", () => ({ methods: { getSettingValue(settingName) { return false; }, hasSetting(settingName) { return false; }, hasSettingEqualTo(settingName, settingValue) { return false; }, }, })); describe("service-package-question.vue", () => { beforeEach(async () => { processedCmsContent = inputQuestionWidgetAnswers; mockMixin = { methods: { getCmsContent: jest.fn((widgetName, cmsFieldName) => { return processedCmsContent[widgetName][cmsFieldName]; }), }, }; mockProps = { modelValue: "initialValue", isInsuranceSelected: false, insuranceCmsWidgetName: "InsuranceServicePackageQuestionWidget", cashCmsWidgetName: "CashServicePackageQuestionWidget", availableLineItems: [ { partNumber: "001", Description: "Windshield with Recal", partType: "Windshield", Quantity: "1", BasePartNumber: "001", Color: "Green", CanSafeliteRecalibrate: true, price: 350.22, }, { partNumber: "RAIN REPEL", description: null, partType: "RAIN REPEL", price: 35.5, }, { partNumber: "PRM RCL CSH PKG", description: null, partType: "QUOTE PAGE DISCOUNT", price: -70, }, ], lineItems: { supportingItems: [ { description: null, id: "b0c68683-da85-46ba-bc86-2642bd9d5fdb", kitPrice: 0, laborAmount: 0, partNumber: "RECYCLE FEE", partType: "REPLACE FEE", salesTax: null, sellingPrice: 0, }, { description: null, id: "5f205a07-3c08-4244-9935-76d63a7bcd19", kitPrice: 0, laborAmount: 395, partNumber: "RECAL STATIC", partType: "RECALIBRATION", salesTax: null, sellingPrice: 0, }, { description: null, kitPrice: 0, laborAmount: 0, partNumber: "PRM RCL CSH PKG", partType: "QUOTE PAGE DISCOUNT", salesTax: null, sellingPrice: -70, }, ], }, availableQuotePageDiscounts: [ { packageLevel: packageNames.TIER_THREE, item: { description: null, kitPrice: 0, laborAmount: 0, partNumber: "PRM RCL CSH PKG", partType: "QUOTE PAGE DISCOUNT", salesTax: null, sellingPrice: -70, }, }, ], activePromos: [], }; const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); }); it("should emit relevant VAPS items in an array", async () => { // Arrange const wrapper = setupMocks({}); // Act wrapper.componentVM.selectedPackageName = "TierThree"; await nextTick(); // Assert expect(wrapper.emitted()["vapsItemsSelected"][0][0]).toEqual([ { description: null, partNumber: "RAIN REPEL", partType: "RAIN REPEL", price: 35.5, }, ]); }); it("should return price when there is discount", () => { const wrapper = setupMocks({}); const price = wrapper.vm.getDiscountPrice(packageNames.TIER_THREE); expect(Math.abs(price)).toEqual(70); }); it("isDiscountOnOrder returns true if it contains quote package discount lineItems", () => { // Arrange const wrapper = setupMocks({}); // Assert expect(wrapper.vm.isDiscountOnOrder).toBe(true); }); it("should have the correct insurance pricing text when insurance is selected", () => { // Arrange mockProps.isInsuranceSelected = true; const wrapper = setupMocks({}); // Act // Assert expect( wrapper.vm.servicePackageAnswers[0].buttonAuxillaryCopy.includes("As little as") ).toBe(true); }); it("should show service package discount when insurance is not selected", () => { // Arrange mockProps.isInsuranceSelected = false; const wrapper = setupMocks({}); // Act // Assert expect( wrapper.vm.servicePackageAnswers[0].additionalButtonData.Text.includes( "Special: Save $" ) ).toBe(true); }); it("should return [] from nullSafeAvailableLineItems and not error out if availableLineItems is null", () => { // Arrange mockProps.availableLineItems = null; const wrapper = setupMocks({}); // Act // Assert expect(wrapper.vm.nullSafeAvailableLineItems).toEqual([]); }); it("should return a null servicePackageAnswers if the cmsContent is falsy", () => { // Arrange mockMixin = { methods: { getCmsContent: jest.fn((widgetName, cmsFieldName) => { return null; }), }, }; const wrapper = setupMocks({}); // Assert expect(wrapper.vm.servicePackageAnswers).toBe(null); }); it("should treat an undefined 'getCustomValueFromString' as a false value and not error out", () => { // Arrange const packageNameKey = "badCustomValue"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Windshield" }], }, }, hasAnyNonWindshieldGlassParts: false, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer should not be created expect(wrapper.vm.servicePackageAnswers.length).toBe(2); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should not select a default package if isInsurance is null", async () => { // Note, only the first WSREPAIR item has a 0 for laborAmount, this is enough to not try and select a default package const wrapper = setupMocks({}); // Act wrapper.setProps({ availableLineItems: null }); await nextTick(); // Assert expect(wrapper.vm.selectedPackageName).toBe(null); }); it("should select a default package if isInsurance is NOT null", async () => { const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Windshield" }], }, }, lineItems: { vaps: [], }, hasAnyNonWindshieldGlassParts: false, payment: { isInsurance: false, }, }, }, }, }); // Act wrapper.setProps({ availableLineItems: null }); await nextTick(); // Assert expect(wrapper.vm.selectedPackageName).toBe("TierOne"); }); it("should select TierThree default package if Rain Repel is on order", async () => { // This tests the business intent that when returning to the page, the selected package is the lowest package that contains all VAPs on the order. // In this case Rain Repel is only in Premium so Tier Three should be defaulted to const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { lineItems: { glassParts: [ { partNumber: "FW02627GBYNOEE", description: "solar, 3rd visor band", color: "Green Tint, Blue Shade", partType: "WINDSHIELD", canSafeliteRecalibrate: false, requiresRecalibration: false, requiresCapabilityQuestions: false, recalibrationType: null, childParts: null, laborAmount: 5.0, }, ], vaps: [ { partNumber: "RAIN REPEL", partType: "RAIN REPEL", }, ], supportingItems: [ { partNumber: "SUPPLIES-REPAIR", description: null, partType: "REPAIR FEE", laborAmount: 5.0, }, { partNumber: "WSREPAIR", description: null, partType: "REPAIR FEE", laborAmount: 5.0, }, { partNumber: "WSREPAIR", description: null, partType: "REPAIR FEE", laborAmount: 5.0, }, { partNumber: "WSREPAIR", description: null, partType: "REPAIR FEE", laborAmount: 5.0, }, ], }, order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Windshield" }], }, }, payment: { isInsurance: false, }, }, }, }, }); // Act wrapper.setProps({ availableLineItems: null }); await nextTick(); // Assert expect(wrapper.vm.selectedPackageName).toBe("TierThree"); }); it("should select default package if promos are added", async () => { //Arrange mockProps.activePromos != null; const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Windshield" }], }, }, lineItems: { vaps: [], }, hasAnyNonWindshieldGlassParts: false, payment: { isInsurance: false, }, }, }, }, }); //Act wrapper.setProps({ activePromos: [ { discountedLineItemIds: [ { 0: "428ec73c-38e4-4e14-8703-a987b0391898", 1: "79db94d7-163c-4408-a1ec-f83e58c11992", }, ], partType: "PROMO_DISCOUNT", promoCode: "1WIPER0", partNumber: "WIPER DISCOUNT", laborAmount: 0, sellingPrice: -10, kitPrice: 0, salesTax: null, }, ], }); wrapper.vm.selectDefaultPackage = jest.fn(); const selectDefaultPackageMock = jest.spyOn(wrapper.vm, "selectDefaultPackage"); await nextTick(); //Assert expect(selectDefaultPackageMock).toHaveBeenCalled(); }); }); describe("service-package-question.vue, matching business rules for package display", () => { // mock scenarios in figma: // https://www.figma.com/file/Spt9hBtGj8r8PFFGNIN3G5/New-Funnel?node-id=100%3A11383 beforeEach(async () => { processedCmsContent = inputQuestionWidgetAnswers; mockMixin = { methods: { getCmsContent: jest.fn((widgetName, cmsFieldName) => { return processedCmsContent[widgetName][cmsFieldName]; }), }, }; mockProps = { modelValue: "initialValue", isInsuranceSelected: false, insuranceCmsWidgetName: "InsuranceServicePackageQuestionWidget", cashCmsWidgetName: "CashServicePackageQuestionWidget", availableLineItems: [ { partNumber: "001", Description: "Windshield with Recal", partType: "Windshield", Quantity: "1", BasePartNumber: "001", Color: "Green", CanSafeliteRecalibrate: true, price: 350.22, }, { partNumber: "RAIN REPEL", description: null, partType: "RAIN REPEL", price: 35.5, }, ], activePromos: [], }; }); it("should match the 05_01_CSR_Quote_Standard_Repair mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: true, glassToReplace: [], }, }, hasAnyNonWindshieldGlassParts: false, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierTwo ); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[2], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should match the 05_01_CSR_Quote_Recal mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_Recal"; mockProps.availableLineItems.push(recalLineItem); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); mockProps.isRecalibrationOnOrder = true; mockProps.shouldHideRecalibration = false; mockProps.showRecalInServicePackages = true; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Windshield" }], }, }, hasAnyNonWindshieldGlassParts: false, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierTwo ); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[2], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should match the 05_01_CSR_Quote_RearGlass mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_RearGlass"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); mockProps.availableLineItems.push(rearWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Rear" }], }, }, hasAnyNonWindshieldGlassParts: true, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierTwo ); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[2], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should match the 05_01_CSR_Quote_RearGlass+NonWindshield mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_RearGlass+NonWindshield"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); mockProps.availableLineItems.push(rearWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [ { glassLocation: "Rear" }, { glassLocation: "Driver" }, ], }, }, hasAnyNonWindshieldGlassParts: true, }, }, }, }); //console.log(wrapper.vm.servicePackageAnswers); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierTwo ); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[2], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should match the 05_01_CSR_Quote_RearGlass+Windshield mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_RearGlass+Windshield"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); mockProps.availableLineItems.push(rearWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [ { glassLocation: "Rear" }, { glassLocation: "Windshield" }, ], }, }, hasAnyNonWindshieldGlassParts: true, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierTwo ); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[2], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should match the 05_01_CSR_Quote_RearGlassNoFrontFit mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_RearGlassNoFrontFit"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(rearWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Rear" }], }, }, hasAnyNonWindshieldGlassParts: true, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierTwo ); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[2], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should match the 05_01_CSR_Quote_Windshield+SideGlass mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_Windshield+SideGlass"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); mockProps.availableLineItems.push(rearWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [ { glassLocation: "Driver" }, { glassLocation: "Windshield" }, ], }, }, hasAnyNonWindshieldGlassParts: true, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierTwo ); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[2], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should match the 05_01_CSR_Quote_SideGlass mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_SideGlass"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); mockProps.availableLineItems.push(rearWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Driver" }], }, }, hasAnyNonWindshieldGlassParts: true, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer should not be created expect(wrapper.vm.servicePackageAnswers.length).toBe(2); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should match the 05_01_CSR_Quote_NoWiperFit mock", () => { // Arrange const packageNameKey = "05_01_CSR_Quote_NoWiperFit"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Windshield" }], }, }, hasAnyNonWindshieldGlassParts: false, }, }, }, }); // Assert // economy answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); // standard answer should not be created expect(wrapper.vm.servicePackageAnswers.length).toBe(2); // premium answer runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierThree ); }); it("should use experiment package names when ServicePackageNameTest is active", () => { const getExperimentPackageLabelSpy = jest .spyOn(servicePackageQuestion.methods, "getExperimentPackageLabel") .mockImplementation((tierName) => { const experimentPackageNames = { [packageNames.TIER_ONE]: "Essential", [packageNames.TIER_TWO]: "Plus", [packageNames.TIER_THREE]: "Full Service", }; return experimentPackageNames[tierName] ?? null; }); const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: true, glassToReplace: [], }, }, hasAnyNonWindshieldGlassParts: false, }, }, }, }); expect(wrapper.vm.servicePackageAnswers[0].buttonLabel).toBe("Essential"); expect(wrapper.vm.servicePackageAnswers[1].buttonLabel).toBe("Plus"); expect(wrapper.vm.servicePackageAnswers[2].buttonLabel).toBe("Full Service"); getExperimentPackageLabelSpy.mockRestore(); }); it("should use CMS package names when ServicePackageNameTest is not active", () => { const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); mockProps.availableLineItems.push(driverFrontWiperLineItem); mockProps.availableLineItems.push(passengerFrontWiperLineItem); const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { order: { damage: { isRepair: true, glassToReplace: [], }, }, hasAnyNonWindshieldGlassParts: false, }, }, }, }); runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[0], expectedModifiedAnswers[packageNameKey].tierOne ); runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[1], expectedModifiedAnswers[packageNameKey].tierTwo ); runPackageAnswerExpectStatements( wrapper.vm.servicePackageAnswers[2], expectedModifiedAnswers[packageNameKey].tierThree ); }); }); function runPackageAnswerExpectStatements(servicePackageAnswer, expectedOutput) { expect(servicePackageAnswer.buttonLabel).toBe(expectedOutput.buttonLabel); expect(servicePackageAnswer.buttonLabelSubCopy).toBe(expectedOutput.buttonLabelSubCopy); expect(servicePackageAnswer.buttonBodyCopy).toBe(expectedOutput.buttonBodyCopy); expect(servicePackageAnswer.buttonFooterCopy).toBe(expectedOutput.buttonFooterCopy); } function setupMocks({ mountOptionsMockData, props = mockProps }) { var mountOptionsMockDataDefault = { store: { getters: { order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Windshield" }], }, }, hasAnyNonWindshieldGlassParts: false, payment: { isInsurance: null, }, }, }, }; mountOptionsMockData = Object.assign(mountOptionsMockDataDefault, mountOptionsMockData); const mountOptions = getMountOptions(mountOptionsMockData); // Modify/augment default mount options mountOptions.global.mixins = [mockMixin]; mountOptions.propsData = props; const wrapper = shallowMount(servicePackageQuestion, mountOptions); return wrapper; } /////////////// // Constants // /////////////// let processedCmsContent; let mockMixin; let mockProps; let recalLineItem = { partNumber: "RECAL STATIC", Description: "Recalibration", partType: "recalibration", Quantity: "1", price: 150.0, }; let driverFrontWiperLineItem = { partNumber: "SBB16", description: "SAFELITE BEAM BLADE 16", partType: "FRONT WIPER", price: 32.64, }; let passengerFrontWiperLineItem = { partNumber: "SBB26", description: "SAFELITE BEAM BLADE 26", partType: "FRONT WIPER", price: 53.04, }; let rearWiperLineItem = { partNumber: "SBBR12A", description: "SAFELITE REAR BLADE 12A", partType: "REAR WIPER", price: 24.48, };