From ef55856d028dd6dd2218f46f221b53e93d640dc1 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Wed, 27 Mar 2024 12:52:26 -0400 Subject: [PATCH] Adding most tests --- .../__snapshots__/cart-dropdown.spec.js.snap | 1 + .../cart-dropdown/cart-dropdown.spec.js | 499 +++++++++++++++++- .../cart-dropdown/cart-dropdown.vue | 67 ++- 3 files changed, 529 insertions(+), 38 deletions(-) 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 af4e64e3..f836ed20 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 @@ -17,6 +17,7 @@ Object { "salesTax": "SalesTaxWidget", "servicePackage": "ServicePackageTitle", "subtotal": "SubtotalWidget", + "vapsItemDescriptions": "VapsItemDescriptions", }, } `; diff --git a/src/iss-components/cart-dropdown/cart-dropdown.spec.js b/src/iss-components/cart-dropdown/cart-dropdown.spec.js index 0d2e5d3e..6515d11b 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.spec.js +++ b/src/iss-components/cart-dropdown/cart-dropdown.spec.js @@ -8,6 +8,7 @@ import { useMainStore } from '@/store'; import coverageStatuses from '@/constants/coverage-statuses'; import { formatAmountInDollars } from '@/helpers/text-helper.js'; import partTypeStrings from '@/constants/part-type-strings'; +import { getHighestFullySatisfiedTier, getPackageContents } from '@/helpers/service-package-helper.js'; const VERIFYING_COVERAGE = 'Verifying coverage'; @@ -15,7 +16,12 @@ jest.mock('@/helpers/text-helper', () => ({ formatAmountInDollars: jest.fn() })); -function getMountedComponent(mainInitialState = {}, initialData = {}, propsData = {}) { +jest.mock('@/helpers/service-package-helper', () => ({ + getHighestFullySatisfiedTier: jest.fn(), + getPackageContents: jest.fn() +})); + +function getMountedComponent(mainInitialState = {}, initialData = {}, propsData = {}, mockMixin = {}) { const mountOptions = getMountOptions({ router: { navigate: jest.fn() @@ -34,8 +40,6 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, propsData mountOptions.propsData = propsData; const wrapper = shallowMount(cartDropdown, mountOptions); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {}); - wrapper.vm.setCmsContent = jest.fn(); return { wrapper }; } @@ -122,6 +126,19 @@ describe('cart-dropdown component', () => { // Assert expect(cartBasePrice.exists()).toBeTruthy(); }); + test('service package', () => { + // Arrange + const reference = '#cart-service-package'; + const isExpanded = true; + const initialData = { isExpanded }; + const { wrapper } = getMountedComponent({}, {}, initialData); + + // Act + const servicePackage = wrapper.find(reference); + + // Assert + expect(servicePackage.exists()).toBeTruthy(); + }); test('cart footer', () => { // Arrange const reference = '#cart-footer'; @@ -499,6 +516,470 @@ describe('cart-dropdown component', () => { describe('salesTax', () => { // TODO when method implemented }); + describe('availableLineItems', () => { + test('returns expected when glassParts null', async () => { + // Arrange + const storeData = { + order: { + lineItems: { + glassParts: null, + supportingItems: [] + } + } + }; + const propsData = { availableVaps: [] }; + const { wrapper } = getMountedComponent(storeData, {}, propsData); + + // Act + const result = wrapper.vm.availableLineItems; + + // Assert + expect(result).toStrictEqual([]); + }); + test('returns expected when supportingItems null', async () => { + // Arrange + const storeData = { + order: { + lineItems: { + glassParts: [], + supportingItems: null + } + } + }; + const propsData = { availableVaps: [] }; + const { wrapper } = getMountedComponent(storeData, {}, propsData); + + // Act + const result = wrapper.vm.availableLineItems; + + // Assert + expect(result).toStrictEqual([]); + }); + test('returns expected when availableVaps null', async () => { + // Arrange + const storeData = { + order: { + lineItems: { + glassParts: [], + supportingItems: [] + } + } + }; + const propsData = { + availableVaps: undefined + }; + const { wrapper } = getMountedComponent(storeData, {}, propsData); + + // Act + const result = wrapper.vm.availableLineItems; + + // Assert + expect(result).toStrictEqual([]); + }); + test('returns expected when glassParts, supportingItems, 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 storeData = { + order: { + lineItems: { + glassParts: [part1], + supportingItems: [part2, part3] + } + } + }; + const propsData = { + availableVaps: [part4, part5] + }; + const { wrapper } = getMountedComponent(storeData, {}, propsData); + const expected = [part1, part2, part3, part4, part5]; + + // Act + const result = wrapper.vm.availableLineItems; + + // Assert + expect(result).toStrictEqual(expected); + }); + }); + describe('servicePackageCartItems', () => { + test.each([ + [undefined], [null], [[]] + ])('returns empty list when package contents %p', (packageContents) => { + // Arrange + getPackageContents.mockImplementationOnce(() => packageContents); + const { wrapper } = getMountedComponent(); + const expected = []; + + // Act + const result = wrapper.vm.servicePackageCartItems; + + // Assert + expect(result).toStrictEqual(expected); + }); + test('returns front wiper when front wiper included in types', () => { + // Arrange + const packageContents = [partTypeStrings.FRONT_WIPER]; + getPackageContents.mockImplementationOnce(() => packageContents); + + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const expectedName = 'some name'; + const vapsItemDescriptions = [ + { + Name: partTypeStrings.FRONT_WIPER, + Text: expectedName + } + ]; + const mockMixin = { + methods: { + getCmsContent: jest.fn(() => vapsItemDescriptions) + } + }; + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.servicePackageCartItems; + + // Assert + expect(result.length).toBe(1); + expect(result[0].name).toBe(expectedName); + }); + test('returns rear wiper when rear wiper included in types', () => { + // Arrange + const packageContents = [partTypeStrings.REAR_WIPER]; + getPackageContents.mockImplementationOnce(() => packageContents); + + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const expectedName = 'some other name'; + const vapsItemDescriptions = [ + { + Name: partTypeStrings.REAR_WIPER, + Text: expectedName + } + ]; + const mockMixin = { + methods: { + getCmsContent: jest.fn(() => vapsItemDescriptions) + } + }; + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.servicePackageCartItems; + + // Assert + expect(result.length).toBe(1); + expect(result[0].name).toBe(expectedName); + }); + test('returns rain defense when rain defense included in types', () => { + // Arrange + const packageContents = [partTypeStrings.RAIN_DEFENSE]; + getPackageContents.mockImplementationOnce(() => packageContents); + + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const expectedName = 'different name'; + const vapsItemDescriptions = [ + { + Name: partTypeStrings.RAIN_DEFENSE, + Text: expectedName + } + ]; + const mockMixin = { + methods: { + getCmsContent: jest.fn(() => vapsItemDescriptions) + } + }; + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.servicePackageCartItems; + + // Assert + expect(result.length).toBe(1); + expect(result[0].name).toBe(expectedName); + }); + test('returns expected when all included in types', () => { + // Arrange + const packageContents = [partTypeStrings.FRONT_WIPER, partTypeStrings.REAR_WIPER, partTypeStrings.RAIN_DEFENSE]; + getPackageContents.mockImplementationOnce(() => packageContents); + + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const expectedFrontWiperName = 'front wiper'; + const expectedRearWiperName = 'rear wiper'; + const expectedRainDefenseName = 'rain defense'; + const vapsItemDescriptions = [ + { + Name: partTypeStrings.FRONT_WIPER, + Text: expectedFrontWiperName + }, + { + Name: partTypeStrings.REAR_WIPER, + Text: expectedRearWiperName + }, + { + Name: partTypeStrings.RAIN_DEFENSE, + Text: expectedRainDefenseName + } + ]; + const mockMixin = { + methods: { + getCmsContent: jest.fn(() => vapsItemDescriptions) + } + }; + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.servicePackageCartItems; + + // Assert + expect(result.length).toBe(3); + expect(result).toContainEqual(expect.objectContaining({ + name: expectedFrontWiperName + })); + expect(result).toContainEqual(expect.objectContaining({ + name: expectedRearWiperName + })); + expect(result).toContainEqual(expect.objectContaining({ + name: expectedRainDefenseName + })); + }); + }); + describe('servicePackageLabelWidget', () => { + test.each([ + [null], + [undefined] + ])('returns "" when servicePackageNames %p', (servicePackageNames) => { + // Arrange + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const mockMixin = { + methods: { + getCmsContent: jest.fn(() => servicePackageNames) + } + }; + mountOptions.mixins = [mockMixin]; + + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.servicePackageLabelWidget; + + // Assert + expect(result).toBe(''); + }); + test('returns "" when servicePackageTier not found in servicePackageNames', () => { + // Arrange + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + getHighestFullySatisfiedTier.mockImplementationOnce(() => 'some other tier'); + const servicePackageNames = [{ Name: 'some tier' }]; + const mockMixin = { + methods: { + getCmsContent: jest.fn(() => servicePackageNames) + } + }; + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.servicePackageLabelWidget; + + // Assert + expect(result).toBe(''); + }); + test('returns "" when servicePackageTier has no SubWidgetName', () => { + // Arrange + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const tier = 'tier1'; + getHighestFullySatisfiedTier.mockImplementationOnce(() => tier); + const servicePackageNames = [{ Name: tier }]; + const mockMixin = { + methods: { + getCmsContent: jest.fn(() => servicePackageNames) + } + }; + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.servicePackageLabelWidget; + + // Assert + expect(result).toBe(''); + }); + test('returns expected when servicePackageTier has SubWidgetName', () => { + // Arrange + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const tier = 'tier1'; + getHighestFullySatisfiedTier.mockImplementationOnce(() => tier); + const expected = 'name of sub widget'; + const servicePackageNames = [{ + Name: tier, + SubWidgetName: expected + }]; + const mockMixin = { + methods: { + getCmsContent: jest.fn(() => servicePackageNames) + } + }; + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.servicePackageLabelWidget; + + // Assert + expect(result).toBe(expected); + }); + }); + describe.only('recycleFeeCartItem', () => { + test.each([ + [null], [undefined], [[]] + ])('returns null when supporting items %p', (supportingItems) => { + // Arrange + const storeData = { + order: { + lineItems: { supportingItems } + } + }; + const { wrapper } = getMountedComponent(storeData); + const expected = null; + + // Act + const result = wrapper.vm.recycleFeeCartItem; + + // Assert + expect(result).toStrictEqual(expected); + }); + test('returns null when recycle fee not in non empty supporting items', () => { + // Arrange + const storeData = { + order: { + lineItems: { + supportingItems: [{ partType: 'not recycle' }] + } + } + }; + const { wrapper } = getMountedComponent(storeData); + const expected = null; + + // Act + const result = wrapper.vm.recycleFeeCartItem; + + // Assert + expect(result).toStrictEqual(expected); + }); + test('returns expected when recycle fee in supporting items', () => { + // Arrange + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const expectedName = 'recycling fee'; + const widgetName = 'RecycleFeeWidget'; + const mockMixin = { + methods: { + getCmsContent: jest.fn((widget, _) => (widget === widgetName ? expectedName : [])) + } + }; + mountOptions.mixins = [mockMixin]; + const storeData = { + order: { + lineItems: { + supportingItems: [{ partType: partTypeStrings.RECYCLE_FEE }] + } + } + }; + const testingPinia = createTestingPinia({ + initialState: { + main: storeData + } + }); + useMainStore(testingPinia); + mountOptions.global.plugins = [testingPinia]; + + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.recycleFeeCartItem; + + // Assert + expect(result.name).toBe(expectedName); + }); + }); + describe.only('mobileFeeCartItem', () => { + test.each([[null], [undefined]])('returns null when mobile fee %p', (mobileFee) => { + // Arrange + const storeData = { + order: { + lineItems: { mobileFee } + } + }; + const { wrapper } = getMountedComponent(storeData); + const expected = null; + + // Act + const result = wrapper.vm.mobileFeeCartItem; + + // Assert + expect(result).toStrictEqual(expected); + }); + test('returns expected when mobile fee in supporting items', () => { + // Arrange + const mountOptions = getMountOptions({ + router: { navigate: jest.fn() } + }); + const expectedName = 'mobile fee'; + const widgetName = 'MobileServiceWidget'; + const mockMixin = { + methods: { + getCmsContent: jest.fn((widget, _) => (widget === widgetName ? expectedName : [])) + } + }; + mountOptions.mixins = [mockMixin]; + const storeData = { + order: { + lineItems: { + mobileFee: { partType: partTypeStrings.MOBILE_FEE } + } + } + }; + const testingPinia = createTestingPinia({ + initialState: { + main: storeData + } + }); + useMainStore(testingPinia); + mountOptions.global.plugins = [testingPinia]; + + const wrapper = shallowMount(cartDropdown, mountOptions); + + // Act + const result = wrapper.vm.mobileFeeCartItem; + + // Assert + expect(result.name).toBe(expectedName); + }); + }); }); describe('method', () => { describe('getDisplayed', () => { @@ -625,5 +1106,17 @@ describe('cart-dropdown component', () => { expect(result).toBe(dollarAmount); }); }); + // TODO + describe('getCartItemForVapsPart', () => { + test('returns item with no label when no descriptions returned', () => {}); + test('returns item with no label when type not in descriptions', () => {}); + test('returns item with no label when description text not defined', () => {}); + test('returns expected label when vaps description text set', () => {}); + test.each([[undefined], [null], []])('returns item with no line items when vapsInOrder %p', (vapsInOrder) => {}); + test('returns item with expected lineItems when part type found in vapsInOrder', () => {}); + }); + describe('removeItem', () => { + // TODO when written + }); }); }); diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 448764ad..c714da37 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -51,7 +51,7 @@ {{ formatAmountInDollars(packagePrice) }}
{{ item.name }} - - - + + +
@@ -197,7 +196,8 @@ export default { salesTax: 'SalesTaxWidget', recycleFee: 'RecycleFeeWidget', mobileFee: 'MobileServiceWidget', - servicePackage: 'ServicePackageTitle' + servicePackage: 'ServicePackageTitle', + vapsItemDescriptions: 'VapsItemDescriptions' } }; }, @@ -261,24 +261,14 @@ export default { } return items; }, - frontWipersCartItem() { - const frontWipersLabel = this.getCmsContentForVapsType(partTypeStrings.FRONT_WIPER); - const frontWipersLineItems = this.vapsInOrder - .filter((vapsLineItem) => vapsLineItem.partType === partTypeStrings.FRONT_WIPER); - return this.getCartItem(frontWipersLabel, frontWipersLineItems); + return this.getCartItemForVapsPart(partTypeStrings.FRONT_WIPER); }, rearWipersCartItem() { - const rearWipersLabel = this.getCmsContentForVapsType(partTypeStrings.REAR_WIPER); - const rearWipersLineItems = this.vapsInOrder - .filter((vapsLineItem) => vapsLineItem.partType === partTypeStrings.REAR_WIPER); - return this.getCartItem(rearWipersLabel, rearWipersLineItems); + return this.getCartItemForVapsPart(partTypeStrings.REAR_WIPER); }, rainDefenseCartItem() { - const rainDefenseLabel = this.getCmsContentForVapsType(partTypeStrings.RAIN_DEFENSE); - const rainDefenseLineItem = this.vapsInOrder - ?.find((vapsLineItem) => vapsLineItem.partType === partTypeStrings.RAIN_DEFENSE); - return this.getCartItem(rainDefenseLabel, [rainDefenseLineItem]); + return this.getCartItemForVapsPart(partTypeStrings.RAIN_DEFENSE); }, packagePrice() { return getPriceOfLineItems(this.vapsInOrder); @@ -298,7 +288,6 @@ export default { salesTaxLabel() { return this.getCmsContent(this.widget.salesTax, widgetFields.TEXT_BLOCK_WIDGET.TEXT); }, - // TODO confirm what happens when servicePackageNames is null with test servicePackageNames() { return this.getCmsContent( this.widget.servicePackage, @@ -312,11 +301,12 @@ export default { const currentPackage = this.servicePackageNames ?.find((entry) => entry.Name === this.servicePackageTier); - return currentPackage.SubWidgetName ?? ''; + return currentPackage?.SubWidgetName ?? ''; }, recycleFeeCartItem() { const recycleFeeLineItem = useMainStore().lineItems.supportingItems - ?.find((lineItem) => lineItem.partType === partTypeStrings.REPLACE_FEE); + ?.find((lineItem) => lineItem.partType === partTypeStrings.RECYCLE_FEE); + console.log(`line item: ${JSON.stringify(recycleFeeLineItem)}`); return recycleFeeLineItem ? this.getCartItem( this.getCmsContent(this.widget.recycleFee, widgetFields.TEXT_BLOCK_WIDGET.TEXT), @@ -359,20 +349,27 @@ export default { return cartItem; }, + getCartItemForVapsPart(partType) { + const label = this.getCmsContentForVapsType(partType); + const lineItems = this.vapsInOrder + ?.filter((vapsLineItem) => vapsLineItem.partType === partType); + return this.getCartItem(label, lineItems); + }, removeItem() { // TODO in later ticket }, getCmsContentForVapsType(vapsType) { - // TODO make strings constants - const vapsItemDescriptions = this.getCmsContent('VapsItemDescriptions', 'Answers'); + const vapsItemDescriptions = this.getCmsContent( + this.widget.vapsItemDescriptions, + widgetFields.INPUT_QUESTION_WIDGET.ANSWERS + ); if (!vapsItemDescriptions) { return ''; } - const vapsTypeName = vapsItemDescriptions?.find((entry) => entry.Name === vapsType); - - return vapsTypeName.Text; + const vapsTypeDescription = vapsItemDescriptions?.find((entry) => entry.Name === vapsType); + return vapsTypeDescription?.Text ?? ''; }, formatAmountInDollars }