diff --git a/src/constants/cart-item-type.js b/src/constants/cart-item-type.js new file mode 100644 index 00000000..c1a322c9 --- /dev/null +++ b/src/constants/cart-item-type.js @@ -0,0 +1,11 @@ +const cartItemType = Object.freeze({ + // FRONT_WIPERS: 'FRONT WIPERS', + // REAR_WIPERS: 'REAR WIPERS', + // RAIN_DEFENSE: 'RAIN DEFENSE', + RECYCLE_FEE: 'RECYCLE FEE', + // REPLACE_FEE: 'REPLACE FEE', + MOBILE_FEE: 'MOBILE FEE', + VAP: 'VAP' +}); + +export default cartItemType; diff --git a/src/iss-components/cart-dropdown/__snapshots__/cart-dropdown.spec.js.snap b/src/iss-components/cart-dropdown/__snapshots__/cart-dropdown.spec.js.snap index 5baa028a..9ade738d 100644 --- a/src/iss-components/cart-dropdown/__snapshots__/cart-dropdown.spec.js.snap +++ b/src/iss-components/cart-dropdown/__snapshots__/cart-dropdown.spec.js.snap @@ -2,6 +2,11 @@ exports[`cart-dropdown component initial data rendered as expected 1`] = ` Object { + "cartItemType": Object { + "MOBILE_FEE": "MOBILE FEE", + "RECYCLE_FEE": "RECYCLE FEE", + "VAP": "VAP", + }, "isExpanded": false, "widget": Object { "amountDue": "AmountDueTextWidget", diff --git a/src/iss-components/cart-dropdown/cart-dropdown.spec.js b/src/iss-components/cart-dropdown/cart-dropdown.spec.js index 9462cdc6..69be39a8 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.spec.js +++ b/src/iss-components/cart-dropdown/cart-dropdown.spec.js @@ -46,6 +46,14 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, propsData return { wrapper }; } +beforeEach(() => { + const store = useMainStore(); + const defaultState = getDefaultState(); + Object.keys(defaultState).forEach((key) => { + store[key] = defaultState[key]; + }); +}); + describe('cart-dropdown component', () => { test('initial data rendered as expected', () => { // Arrange @@ -433,13 +441,57 @@ describe('cart-dropdown component', () => { }); }); describe('subTotal', () => { - test('when not no comp and not itac, includes deductible price', () => { + const supportingItemPartNumber = 'supporter'; + const glassPartNumber = 'glass part'; + const otherPartNumber = 'other'; + const vapPartNumber = 'vap'; + const mobileFeePartNumber = 'mobile'; + const supportingItems = [{ partNumber: supportingItemPartNumber }]; + const glassParts = [{ partNumber: glassPartNumber }]; + const otherParts = [{ partNumber: otherPartNumber }]; + const vaps = [{ partNumber: vapPartNumber }]; + const mobileFee = { partNumber: mobileFeePartNumber }; + const includesPartNumber = (lineItems, partNumber) => lineItems.some((item) => item?.partNumber === partNumber); + const deductiblePrice = 100; + const supportingAndGlassAndOtherPrice = 30; + const feesAndVapsPrice = 50; + const allLineItemsPrice = 70; + getPriceOfLineItems.mockImplementation((lineItems) => { + const allPartNumbers = [ + supportingItemPartNumber, + glassPartNumber, + otherPartNumber, + mobileFeePartNumber, + vapPartNumber + ]; + if (allPartNumbers.every((partNumber) => includesPartNumber(lineItems, partNumber))) { + return allLineItemsPrice; + } + const supportingAndGlassAndOtherPartNumbers = [ + supportingItemPartNumber, + glassPartNumber, + otherPartNumber + ]; + if (supportingAndGlassAndOtherPartNumbers.every((partNumber) => includesPartNumber(lineItems, partNumber))) { + return supportingAndGlassAndOtherPrice; + } + if (includesPartNumber(lineItems, mobileFeePartNumber) && includesPartNumber(lineItems, vapPartNumber)) { + return feesAndVapsPrice; + } + return 1; + }); + const lineItems = { + supportingItems, + glassParts, + otherParts, + vaps, + mobileFee + }; + test('when not no comp and not itac, includes deductible price plus fee and vap price', () => { // Arrange - const deductiblePrice = 872; - const baseServicePrice = 43; - getPriceOfLineItems.mockImplementation(() => baseServicePrice); const storeData = { order: { + lineItems, policy: { noCoverage: false, isITAC: false @@ -448,20 +500,19 @@ describe('cart-dropdown component', () => { } }; const { wrapper } = getMountedComponent(storeData); + const expected = deductiblePrice + feesAndVapsPrice; // Act const result = wrapper.vm.subTotal; // Assert - expect(result).toBe(deductiblePrice); + expect(result).toBe(expected); }); - test('when no comp, includes base service price', () => { + test('when no comp, returns all line items price', () => { // Arrange - const deductiblePrice = 872; - const baseServicePrice = 43; - getPriceOfLineItems.mockImplementation(() => baseServicePrice); const storeData = { order: { + lineItems, policy: { noCoverage: true, isITAC: false @@ -470,20 +521,19 @@ describe('cart-dropdown component', () => { } }; const { wrapper } = getMountedComponent(storeData); + const expected = allLineItemsPrice; // Act const result = wrapper.vm.subTotal; // Assert - expect(result).toBe(baseServicePrice); + expect(result).toBe(expected); }); - test('when ITAC, includes base service price', () => { + test('when ITAC, returns all line items price', () => { // Arrange - const deductiblePrice = 872; - const baseServicePrice = 43; - getPriceOfLineItems.mockImplementation(() => baseServicePrice); const storeData = { order: { + lineItems, policy: { noCoverage: false, isITAC: true @@ -492,121 +542,28 @@ describe('cart-dropdown component', () => { } }; const { wrapper } = getMountedComponent(storeData); + const expected = allLineItemsPrice; // Act const result = wrapper.vm.subTotal; // Assert - expect(result).toBe(baseServicePrice); - }); - test('when nonServicePackageCartItems non empty, sums appropriately', () => { - // Arrange - const deductiblePrice = 0; - const subTotal = 34; - getPriceOfLineItems.mockImplementation(() => subTotal); - const storeData = { - order: { - policy: { - noCoverage: false, - isITAC: false - }, - currentDeductible: deductiblePrice, - lineItems: { - vaps: [ - { - partType: partTypeStrings.FRONT_WIPER - }, - { - partType: partTypeStrings.REAR_WIPER - } - ] - } - } - }; - const { wrapper } = getMountedComponent(storeData); - const expectedPrice = 68; - - // Act - const result = wrapper.vm.subTotal; - - // Assert - expect(result).toBe(expectedPrice); - }); - test('when deductible included, sums all prices appropriately', () => { - // Arrange - const deductiblePrice = 54; - const subTotal = 34; - getPriceOfLineItems.mockImplementation(() => subTotal); - const storeData = { - order: { - policy: { - noCoverage: false, - isITAC: false - }, - currentDeductible: deductiblePrice, - lineItems: { - vaps: [ - { - partType: partTypeStrings.FRONT_WIPER - }, - { - partType: partTypeStrings.REAR_WIPER - } - ] - } - } - }; - const { wrapper } = getMountedComponent(storeData); - const expectedPrice = 122; - - // Act - const result = wrapper.vm.subTotal; - - // Assert - expect(result).toBe(expectedPrice); - }); - test('when base service price included, sums all prices appropriately', () => { - // Arrange - const deductiblePrice = 54; - const subTotal = 34; - getPriceOfLineItems.mockImplementation(() => subTotal); - const storeData = { - order: { - policy: { - noCoverage: true, - isITAC: false - }, - currentDeductible: deductiblePrice, - lineItems: { - vaps: [ - { - partType: partTypeStrings.FRONT_WIPER - }, - { - partType: partTypeStrings.REAR_WIPER - } - ] - } - } - }; - const { wrapper } = getMountedComponent(storeData); - const expectedPrice = 102; - - // Act - const result = wrapper.vm.subTotal; - - // Assert - expect(result).toBe(expectedPrice); + expect(result).toBe(expected); }); }); describe('salesTax', () => { test('salesTax is treated as 0 when line items are null', () => { // Arrange - const storeData = getDefaultState(); - storeData.order.lineItems.glassParts = null; - storeData.order.lineItems.otherParts = null; - storeData.order.lineItems.supportingItems = null; - storeData.order.lineItems.vaps = null; + const storeData = { + order: { + lineItems: { + glassParts: null, + otherParts: null, + supportingItems: null, + vaps: null + } + } + }; const { wrapper } = getMountedComponent(storeData); @@ -619,20 +576,24 @@ describe('cart-dropdown component', () => { test("salesTax is treated as 0 when null or undefined is set as the line item's sales tax.", () => { // Arrange - const storeData = getDefaultState(); - storeData.order.lineItems.glassParts = [ - { partType: 'mock', salesTax: null }, - { partType: 'mock', salesTax: undefined } - ]; - storeData.order.lineItems.supportingItems = [ - { partType: 'mock', salesTax: null }, - { partType: 'mock', salesTax: undefined } - ]; - storeData.order.lineItems.vaps = [ - { partType: 'mock', salesTax: null }, - { partType: 'mock', salesTax: undefined } - ]; - + const storeData = { + order: { + lineItems: { + glassParts: [ + { partType: 'mock', salesTax: null }, + { partType: 'mock', salesTax: undefined } + ], + supportingItems: [ + { partType: 'mock', salesTax: null }, + { partType: 'mock', salesTax: undefined } + ], + vaps: [ + { partType: 'mock', salesTax: null }, + { partType: 'mock', salesTax: undefined } + ] + } + } + }; const { wrapper } = getMountedComponent(storeData); // Act @@ -641,19 +602,29 @@ describe('cart-dropdown component', () => { // Assert expect(result).toBe(0); }); - test('Returns 0 as sales tax when coverage is unverified and order does not contain vaps.', () => { // Arrange - const storeData = getDefaultState(); - storeData.order.lineItems.glassParts = [ - { partType: 'mock', salesTax: 10 } - ]; - storeData.order.lineItems.supportingItems = [ - { partNumber: partNumberStrings.RECYCLE_FEE, partType: 'mock', salesTax: 10, sellingPrice: 39.99 } - ]; - storeData.order.lineItems.vaps = []; - storeData.order.payment.insuranceCoverage.isVerified = false; - + const storeData = { + order: { + lineItems: { + glassParts: [{ partType: 'mock', salesTax: 10 }], + supportingItems: [ + { + partNumber: partNumberStrings.RECYCLE_FEE, + partType: 'mock', + salesTax: 10, + sellingPrice: 39.99 + } + ], + vaps: [] + }, + payment: { + insuranceCoverage: { + isVerified: false + } + } + } + }; const { wrapper } = getMountedComponent(storeData); // Act @@ -665,7 +636,7 @@ describe('cart-dropdown component', () => { test('Returns sum of vaps sales tax when coverage is unverified and order has vaps.', () => { // Arrange - const storeData = getDefaultState(); + const storeData = useMainStore().$state; storeData.order.lineItems.glassParts = [ { partType: 'mock', salesTax: 10 } ]; @@ -686,7 +657,7 @@ describe('cart-dropdown component', () => { test('Returns Recycle Fee tax when coverage is Verified-Deductible, replace service, and no vaps.', () => { // Arrange - const storeData = getDefaultState(); + const storeData = useMainStore().$state; storeData.order.currentDeductible = 250; storeData.order.lineItems.glassParts = [ { partType: 'mock', salesTax: 10, sellingPrice: 150 } @@ -708,7 +679,7 @@ describe('cart-dropdown component', () => { test('Returns sum of vaps + recycle fee sales tax when Verified-Deductible, replace service, and has vaps.', () => { // Arrange - const storeData = getDefaultState(); + const storeData = useMainStore().$state; storeData.order.currentDeductible = 250; storeData.order.lineItems.glassParts = [ { partType: 'mock', salesTax: 10, sellingPrice: 100 } @@ -737,7 +708,7 @@ describe('cart-dropdown component', () => { test('Returns sum of sales tax when Verified-ITAC.', () => { // Arrange - const storeData = getDefaultState(); + const storeData = useMainStore().$state; storeData.order.currentDeductible = 0; storeData.order.lineItems.glassParts = [ { partType: 'mock', salesTax: 10, sellingPrice: 100 } @@ -765,7 +736,7 @@ describe('cart-dropdown component', () => { test('Returns sum of sales tax when Verified-NoComp.', () => { // Arrange - const storeData = getDefaultState(); + const storeData = useMainStore().$state; storeData.order.currentDeductible = 0; storeData.order.lineItems.glassParts = [ { partType: 'mock', salesTax: 10, sellingPrice: 100 } @@ -792,18 +763,10 @@ describe('cart-dropdown component', () => { }); }); describe('availableLineItems', () => { - test('returns expected when glassParts null', async () => { + test('returns expected when all null', () => { // Arrange - const storeData = { - order: { - lineItems: { - glassParts: null, - supportingItems: [] - } - } - }; - const propsData = { availableVaps: [] }; - const { wrapper } = getMountedComponent(storeData, {}, propsData); + const propsData = { availableVaps: null }; + const { wrapper } = getMountedComponent({}, {}, propsData); // Act const result = wrapper.vm.availableLineItems; @@ -811,58 +774,106 @@ describe('cart-dropdown component', () => { // Assert expect(result).toStrictEqual([]); }); - test('returns expected when supportingItems null', async () => { + test('returns expected when glassParts not null', async () => { // Arrange + const glassParts = [{ partNumber: 'glass' }]; const storeData = { order: { - lineItems: { - glassParts: [], - supportingItems: null - } + lineItems: { glassParts } } }; - const propsData = { availableVaps: [] }; + const propsData = { availableVaps: null }; const { wrapper } = getMountedComponent(storeData, {}, propsData); + const expected = glassParts; // Act const result = wrapper.vm.availableLineItems; // Assert - expect(result).toStrictEqual([]); + expect(result).toStrictEqual(expected); + }); + test('returns expected when supportingItems not null', async () => { + // Arrange + const supportingItems = [{ partNumber: 'support' }]; + const storeData = { + order: { + lineItems: { supportingItems } + } + }; + const propsData = { availableVaps: null }; + const { wrapper } = getMountedComponent(storeData, {}, propsData); + const expected = supportingItems; + + // Act + const result = wrapper.vm.availableLineItems; + + // Assert + expect(result).toStrictEqual(expected); + }); + test('returns expected when otherParts not null', () => { + // Arrange + const otherParts = [{ partNumber: 'other' }]; + const storeData = { + order: { + lineItems: { otherParts } + } + }; + const propsData = { availableVaps: null }; + const { wrapper } = getMountedComponent(storeData, {}, propsData); + const expected = otherParts; + + // Act + const result = wrapper.vm.availableLineItems; + + // Assert + expect(result).toStrictEqual(expected); + }); + test('returns expected when mobileFee not null', () => { + // Arrange + const mobileFee = { partNumber: 'mobile' }; + const storeData = { + order: { + lineItems: { mobileFee } + } + }; + const propsData = { availableVaps: null }; + const { wrapper } = getMountedComponent(storeData, {}, propsData); + const expected = [mobileFee]; + + // Act + const result = wrapper.vm.availableLineItems; + + // Assert + expect(result).toStrictEqual(expected); }); test('returns expected when availableVaps null', async () => { // Arrange - const storeData = { - order: { - lineItems: { - glassParts: [], - supportingItems: [] - } - } - }; - const propsData = { - availableVaps: undefined - }; - const { wrapper } = getMountedComponent(storeData, {}, propsData); + const availableVaps = [{ partNumber: 'vaps1' }]; + const propsData = { availableVaps }; + const { wrapper } = getMountedComponent({}, {}, propsData); + const expected = availableVaps; // Act const result = wrapper.vm.availableLineItems; // Assert - expect(result).toStrictEqual([]); + expect(result).toStrictEqual(expected); }); - test('returns expected when glassParts, supportingItems, and availableVaps have content', async () => { + test('returns expected when glassParts, supportingItems, otherParts, mobileFee, and availableVaps have content', async () => { // Arrange const part1 = { partType: 'apple' }; const part2 = { partType: 'banana' }; const part3 = { partType: 'orange' }; const part4 = { partType: 'grape' }; const part5 = { partType: 'raspberry' }; + const mobileFee = { partType: 'mobile' }; const storeData = { order: { lineItems: { glassParts: [part1], - supportingItems: [part2, part3] + supportingItems: [part2, part3], + otherParts: [], + mobileFee } } }; @@ -870,13 +881,24 @@ describe('cart-dropdown component', () => { availableVaps: [part4, part5] }; const { wrapper } = getMountedComponent(storeData, {}, propsData); - const expected = [part1, part2, part3, part4, part5]; + const sortByPartType = (a, b) => { + const typeA = a.partType.toUpperCase(); + const typeB = b.partType.toUpperCase(); + if (typeA < typeB) { + return -1; + } + if (typeA > typeB) { + return 1; + } + return 0; + }; + const expected = [part1, part2, part3, part4, part5, mobileFee]; // Act const result = wrapper.vm.availableLineItems; // Assert - expect(result).toStrictEqual(expected); + expect(result.sort(sortByPartType)).toStrictEqual(expected.sort(sortByPartType)); }); }); describe('servicePackageCartItems', () => { @@ -1616,10 +1638,10 @@ describe('cart-dropdown component', () => { const rearPrice = 101; const frontPrice = 9; getPriceOfLineItems.mockImplementation((lineItems) => { - if (lineItems.some((item) => item.partType === partTypeStrings.FRONT_WIPER)) { + if (lineItems.some((item) => item?.partType === partTypeStrings.FRONT_WIPER)) { return frontPrice; } - if (lineItems.some((item) => item.partType === partTypeStrings.REAR_WIPER)) { + if (lineItems.some((item) => item?.partType === partTypeStrings.REAR_WIPER)) { return rearPrice; } return 1; @@ -1648,7 +1670,7 @@ describe('cart-dropdown component', () => { // Arrange const frontPrice = 9; getPriceOfLineItems.mockImplementation((lineItems) => { - if (lineItems.some((item) => item.partType === partTypeStrings.FRONT_WIPER)) { + if (lineItems.some((item) => item?.partType === partTypeStrings.FRONT_WIPER)) { return frontPrice; } return 1; @@ -1677,10 +1699,15 @@ describe('cart-dropdown component', () => { describe('getDisplayed', () => { test('returns "Verifying coverage" when not no comp, not itac, and deductible null', () => { // Arrange - const storeData = getDefaultState(); - storeData.order.policy.noCoverage = false; - storeData.order.policy.isITAC = false; - storeData.order.currentDeductible = null; + const storeData = { + order: { + policy: { + noCoverage: false, + isITAC: false + }, + currentDeductible: null + } + }; const { wrapper } = getMountedComponent(storeData); const amount = 123; @@ -1693,10 +1720,15 @@ describe('cart-dropdown component', () => { }); test('returns "Verifying coverage" when not no comp, not itac, and coverage status PENDING', () => { // Arrange - const storeData = getDefaultState(); - storeData.order.policy.noCoverage = false; - storeData.order.policy.isITAC = false; - storeData.order.currentDeductible = 321; + const storeData = { + order: { + policy: { + noCoverage: false, + isITAC: false + }, + currentDeductible: 321 + } + }; const { wrapper } = getMountedComponent(storeData); const amount = 123; diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index facca69f..94a73f3c 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -81,7 +81,7 @@ class="px-5 py-1 non-packaged-cart-item">