diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 86bcfeea..31d912a0 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -265,7 +265,7 @@ input[type='date']::-webkit-calendar-picker-indicator { } span { font-weight: 400; - font-size: 14px; + font-size: 0.875rem; color: #4d5151; } .form-test-error span { diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 75c669a5..432c03d7 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -6,6 +6,23 @@ import dynamicStrings from '@/constants/dynamic-strings'; import { useMainStore } from '@/store'; +/** + * @function getStringWithCustomValues + * @summary Returns str with all custom values replaced in accordance with the provided customValueMap + * @param {string} str + * @param {Dictionary} customValueMap + * @returns {string} + */ +export function getStringWithCustomValues(str, customValueMap) { + let newString = str ?? ''; + if (customValueMap != null) { + Object.keys(customValueMap).forEach((key) => { + newString = newString.replaceAll(`{custom:${key}}`, customValueMap[key]); + }); + } + return newString; +} + // This function will process the widget item and replace any global state variables with their values. // This is a recursive function, it will call itself until it runs out of items to iterate on given the object. /** diff --git a/src/helpers/cms-content-helper.spec.js b/src/helpers/cms-content-helper.spec.js new file mode 100644 index 00000000..a69a10c5 --- /dev/null +++ b/src/helpers/cms-content-helper.spec.js @@ -0,0 +1,18 @@ +import { getStringWithCustomValues } from '@/helpers/cms-content-helper.js'; + +describe('getStringWithCustomValues', () => { + test.each([ + ['Hello, {custom:name}!', { name: 'John' }, 'Hello, John!'], + ['{custom:greeting}, {custom:name}!', { greeting: 'Hi', name: 'John' }, 'Hi, John!'], + ['{custom:greeting}, {custom:name}!', { greeting: 'Hi' }, 'Hi, {custom:name}!'], + ['Hello, {custom:name}!', {}, 'Hello, {custom:name}!'], + ['Hello, world!', { name: 'John' }, 'Hello, world!'], + ['', { name: 'John' }, ''], + ['Hello, {custom:name}!', null, 'Hello, {custom:name}!'], + ['Hello, {custom:name}!', undefined, 'Hello, {custom:name}!'], + [null, { name: 'John' }, ''], + [undefined, { name: 'John' }, ''] + ])('getStringWithCustomValues(%s, %o) should return %s', (str, customValueMap, expected) => { + expect(getStringWithCustomValues(str, customValueMap)).toBe(expected); + }); +}); diff --git a/src/helpers/text-helper.js b/src/helpers/text-helper.js index 41e19a66..d9f66779 100644 --- a/src/helpers/text-helper.js +++ b/src/helpers/text-helper.js @@ -44,3 +44,56 @@ export function toDisplayPhoneNumber(phoneNumber) { } return result; } + +/** + * @function formatAddress + * @summary given address fields, returns a string representation of said address + * @param {string} addressLine1 + * @param {string} addressLine2 + * @param {string} city + * @param {string} state + * @param {string} zipCode + * @returns {string} + */ +export function formatAddress(addressLine1, addressLine2, city, state, zipCode) { + let address = ''; + + if (addressLine1) { + address += addressLine1; + } + + if (addressLine2) { + address += address ? `, ${addressLine2}` : addressLine2; + } + + if (city) { + address += address ? `, ${city}` : city; + } + address = toTitleCase(address); + + if (state) { + address += address ? `, ${state}` : state; + } + + if (zipCode) { + address += address ? ` ${zipCode}` : zipCode; + } + + return address; +} + +/** + * @function formatAmountInDollars + * @param {string, number} amount + * @returns {string} + */ +export function formatAmountInDollars(amount) { + const numericAmount = typeof amount === 'string' ? parseFloat(amount) : amount; + + if (Number.isNaN(numericAmount) || amount === null || amount === undefined) { + return ''; + } + + const roundedAmount = numericAmount.toFixed(2); + return `$${roundedAmount}`; +} diff --git a/src/helpers/text-helper.spec.js b/src/helpers/text-helper.spec.js index 1b2daf64..6062ee14 100644 --- a/src/helpers/text-helper.spec.js +++ b/src/helpers/text-helper.spec.js @@ -1,4 +1,4 @@ -import { toTitleCase, toDisplayPhoneNumber } from '@/helpers/text-helper.js'; +import { toTitleCase, toDisplayPhoneNumber, formatAddress, formatAmountInDollars } from '@/helpers/text-helper.js'; describe('text-helper', () => { test.each([ @@ -39,4 +39,33 @@ describe('text-helper', () => { expect(result).toEqual(expected); } ); + test.each([ + [null, null, null, null, null, ''], + ['123 Main St', null, null, null, null, '123 Main St'], + ['123 main st', 'Apt 4B', null, null, null, '123 Main St, Apt 4b'], + ['123 Main St', 'apt 4B', 'Anytown', null, null, '123 Main St, Apt 4b, Anytown'], + ['123 Main St', 'Apt 4B', 'Anytown', 'ny', null, '123 Main St, Apt 4b, Anytown, ny'], + ['123 Main St', 'Apt 4B', 'AnYtoWn', 'NY', '12345', '123 Main St, Apt 4b, Anytown, NY 12345'] + ])('formatAddress(%s, %s, %s, %s, %s) should return %s', (addressLine1, addressLine2, city, state, zipCode, expected) => { + expect(formatAddress(addressLine1, addressLine2, city, state, zipCode)).toBe(expected); + }); + test.each([ + [1234.5678, '$1234.57'], + ['1234.5678', '$1234.57'], + [1234.56, '$1234.56'], + ['1234.56', '$1234.56'], + [1234.5, '$1234.50'], + ['1234.5', '$1234.50'], + [1234, '$1234.00'], + ['1234', '$1234.00'], + [0, '$0.00'], + ['0', '$0.00'], + [NaN, ''], + ['NaN', ''], + [null, ''], + ['', ''], + ['abc', ''] + ])('formatAmountInDollars(%s) should return %s', (amount, expected) => { + expect(formatAmountInDollars(amount)).toBe(expected); + }); }); diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 15a4c21a..81eb5a86 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -118,7 +118,7 @@ import loadingModal from '@/iss-components/loading-modal/loading-modal.vue'; import textBlock from '@/digital-components/text-block/text-block.vue'; // Import Supporting Files -import { fetchCmsContentForPage, setupModalLinks, setupModalLink, processIfStatements } from '@/helpers/cms-content-helper.js'; +import { fetchCmsContentForPage, setupModalLinks, processIfStatements } from '@/helpers/cms-content-helper.js'; import settleAllPromises from '@/helpers/layout-helper.js'; import { getDamageString } from '@/helpers/damage-helper.js'; import { useMainStore } from '@/store/index.js'; diff --git a/src/layouts/tpa-search/tpa-search.spec.js b/src/layouts/tpa-search/tpa-search.spec.js index 0d9f74f3..30318933 100644 --- a/src/layouts/tpa-search/tpa-search.spec.js +++ b/src/layouts/tpa-search/tpa-search.spec.js @@ -108,7 +108,7 @@ describe('TPA search page', () => { expect(searchQuestionLabel.classes()).toContain('mb-0'); expect(searchQuestionLabel.classes()).toContain('text-black'); expect(searchQuestionLabel.classes()).toContain('w-100'); - expect(searchQuestionLabel.classes()).toContain('search-question'); + expect(searchQuestionLabel.classes()).toContain('fs-5'); }); test('search instructions', () => { // Arrange @@ -277,7 +277,8 @@ describe('TPA search page', () => { // Assert expect(preferredShopNotListedLink.exists()).toBeTruthy(); expect(preferredShopNotListedLink.props().linkType).toBe('navigation'); - expect(preferredShopNotListedLink.props().href).toBe('#!'); + // eslint-disable-next-line no-script-url + expect(preferredShopNotListedLink.props().href).toBe('javascript:void(0)'); }); test('site footer', () => { // Arrange @@ -843,6 +844,108 @@ describe('TPA search page', () => { expect(wrapper.vm.selectedProviderNumber).toBe(''); }); }); + describe('selectedProviderNumber', () => { + describe('does not call updateServiceLocation when', () => { + test('providers list is null ', () => { + // Arrange + const { wrapper } = getMountedComponent({}, { + providers: null + }); + const newProviderNumber = 11235; + + // Act + wrapper.vm.$options.watch.selectedProviderNumber.call(wrapper.vm, newProviderNumber); + + // Assert + expect(wrapper.vm.mainStore.updateServiceLocation).not.toHaveBeenCalled(); + }); + test('providers list is empty ', () => { + // Arrange + const { wrapper } = getMountedComponent({}, { + providers: [] + }); + const newProviderNumber = 11235; + + // Act + wrapper.vm.$options.watch.selectedProviderNumber.call(wrapper.vm, newProviderNumber); + + // Assert + expect(wrapper.vm.mainStore.updateServiceLocation).not.toHaveBeenCalled(); + }); + test('providers list does not contain match for provider number ', () => { + // Arrange + const { wrapper } = getMountedComponent({}, { + providers: [{ + providerNumber: 8374, + address: { + streetAddress: '143 Average Lane', + city: 'Cambridge', + state: 'OH', + zipCode: '72983', + zipCodeCtu: '0390' + }, + companyName: "Sally's Auto", + phoneNumber: '1234567890' + }] + }); + const newProviderNumber = 11235; + + // Act + wrapper.vm.$options.watch.selectedProviderNumber.call(wrapper.vm, newProviderNumber); + + // Assert + expect(wrapper.vm.mainStore.updateServiceLocation).not.toHaveBeenCalled(); + }); + }); + test('Calls updateServiceLocation when matching provider found.', () => { + // Arrange + const newProviderNumber = 11235; + const streetAddress = '143 Average Lane'; + const city = 'Berlin'; + const state = 'MA'; + const zipCode = '12345'; + const zipCodeCtu = '0004'; + const companyName = "Sally's Auto"; + const phoneNumber = '3298479879'; + const provider = { + providerNumber: newProviderNumber, + address: { + streetAddress, + city, + state, + zipCode, + zipCodeCtu + }, + companyName, + phoneNumber + }; + const { wrapper } = getMountedComponent({}, { + providers: [ + provider, + { providerNumber: 328949832 } + ] + }); + + // Act + wrapper.vm.$options.watch.selectedProviderNumber.call(wrapper.vm, newProviderNumber); + + // Assert + expect(wrapper.vm.mainStore.updateServiceLocation).toHaveBeenCalledWith({ + provider: { + providerNumber: newProviderNumber, + address: { + streetAddress, + city, + state, + zipCode, + zipCodeCtu + }, + companyName, + phoneNumber + } + }); + }); + }); }); describe('method', () => { test.each([ diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue index 3ce478c0..e20cb67b 100644 --- a/src/layouts/tpa-search/tpa-search.vue +++ b/src/layouts/tpa-search/tpa-search.vue @@ -13,7 +13,7 @@