diff --git a/src/assets/img/tints/GlassTint.png b/src/assets/img/tints/GlassTint.png
new file mode 100644
index 00000000..b3cf01ba
Binary files /dev/null and b/src/assets/img/tints/GlassTint.png differ
diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js
index 45bceb0a..1c234ada 100644
--- a/src/constants/endpoints.js
+++ b/src/constants/endpoints.js
@@ -93,6 +93,10 @@ const endpoints = Object.freeze({
) => `${LOCATION_BASE_URL}/providers/${zipCode}/${damageType}/${radius}/${parentAccountNumber}/${safeliteOnly}/${carId}/${recalPartNumber != null ? `${recalPartNumber}/` : ''}${isBigTruck}`,
method: 'GET'
},
+ GetTpaAndSafeliteProviders: {
+ url: `${LOCATION_BASE_URL}/tpa-and-safelite-providers`,
+ method: 'GET'
+ },
GetCapabilityQuestions: {
url: `${PARTS_BASE_URL}/capability-questions`,
method: 'GET'
diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js
index 224c6e30..1705ff1f 100644
--- a/src/constants/error-messages.js
+++ b/src/constants/error-messages.js
@@ -67,7 +67,10 @@ const errorMessages = Object.freeze({
DATE_REQUIRED: 'Please select a date',
TIME_REQUIRED: 'Please select an appointment time.',
PRIMARY_PHONE_REQUIRED: 'Primary phone number is required.',
- BAILOUT_EMAIL_ADDRESS_REQUIRED: 'Email address is required.'
+ BAILOUT_EMAIL_ADDRESS_REQUIRED: 'Email address is required.',
+ TPA_SEARCH_ZIP_FORMAT: 'Please enter a valid Zip code.',
+ TPA_SEARCH_SHOP_FORMAT: 'Please enter a valid shop name.',
+ TPA_SEARCH_REQUIRED: 'Please enter a shop name or ZIP code.'
});
export default errorMessages;
diff --git a/src/constants/global-rules.js b/src/constants/global-rules.js
index 878b7a27..840f8db3 100644
--- a/src/constants/global-rules.js
+++ b/src/constants/global-rules.js
@@ -28,7 +28,8 @@ const globalRules = Object.freeze({
ZIP_CODE_SEARCH_FORMAT: 'zip-code-search-format',
OPTION_REQUIRED: 'option-required',
PRIMARY_PHONE_REQUIRED: 'primary-phone-required',
- BAILOUT_EMAIL_ADDRESS_REQUIRED: 'bailout-email-address-required'
+ BAILOUT_EMAIL_ADDRESS_REQUIRED: 'bailout-email-address-required',
+ TPA_SEARCH_FORMAT: 'tpa-search-format'
});
export default globalRules;
diff --git a/src/constants/tint-mapper.js b/src/constants/tint-mapper.js
deleted file mode 100644
index 91fbd57b..00000000
--- a/src/constants/tint-mapper.js
+++ /dev/null
@@ -1,91 +0,0 @@
-// TintMap with array keys by location, lowercase to avoid as much string mismatching as possible.
-// Src assumes you have a @/assets/img/tints/, making the final value @/assets/img/tints/{Src} in the markup.
-// See vehicle-parts for implementation example.
-const tintMap = Object.freeze({
- other: [
- // Blue Shade
- { name: 'blue tint, blue shade', src: 'Glass-BlueShade-BlueTint.svg' },
- { name: 'brown tint, blue shade', src: 'Glass-BlueShade-BrownTint.svg' },
- { name: 'gray tint, blue shade', src: 'Glass-BlueShade-GrayTint.svg' },
- { name: 'green tint, blue shade', src: 'Glass-BlueShade-GreenTint.svg' },
- { name: 'clear, blue shade', src: 'Glass-BlueShade-NoTint.svg' },
-
- // Brown Shade
- { name: 'brown tint, brown shade', src: 'Glass-BrownShade-BrownTint.svg' },
-
- // Gray Shade
- { name: 'blue tint, gray shade', src: 'Glass-GrayShade-BlueTint.svg' },
- { name: 'brown tint, gray shade', src: 'Glass-GrayShade-BrownTint.svg' },
- { name: 'gray tint, gray shade', src: 'Glass-GrayShade-GrayTint.svg' },
- { name: 'green tint, gray shade', src: 'Glass-GrayShade-GreenTint.svg' },
-
- // Green Shade
- { name: 'blue tint, green shade', src: 'Glass-GreenShade-BlueTint.svg' },
- { name: 'brown tint, green shade', src: 'Glass-GreenShade-BrownTint.svg' },
- { name: 'green tint, green shade', src: 'Glass-GreenShade-GreenTint.svg' },
-
- // Tints Only
- { name: 'blue tint privacy', src: 'Glass-NoShade-BlueTint.svg' },
- { name: 'bronze tint', src: 'Glass-NoShade-BrownTint.svg' },
- { name: 'dark brown tint', src: 'Glass-NoShade-DarkBrownTint.svg' },
- { name: 'privacy, black frame', src: 'Glass-NoShade-Privacy.svg' },
- { name: 'gray tint', src: 'Glass-NoShade-GrayTint.svg' },
- { name: 'green tint', src: 'Glass-NoShade-GreenTint.svg' },
- { name: 'gray tint privacy', src: 'Glass-NoShade-GrayTint.svg' },
- { name: 'blue tint', src: 'Glass-NoShade-BlueTint.svg' },
- { name: 'green tint privacy', src: 'Glass-NoShade-GreenTint.svg' },
-
- // No shade or tint
- { name: 'clear', src: 'Glass-NoShade-NoTint.svg' }
- ],
-
- windshield: [
- // Blue Shade
- { name: 'blue tint, blue shade', src: 'Windshield-BlueShade-BlueTint.svg' },
- { name: 'bronze tint, blue shade', src: 'Windshield-BlueShade-BrownTint.svg' },
- { name: 'gray tint, blue shade', src: 'Windshield-BlueShade-GrayTint.svg' },
- { name: 'green tint, blue shade', src: 'Windshield-BlueShade-GreenTint.svg' },
- { name: 'clear, blue shade', src: 'Windshield-BlueShade-NoTint.svg' },
-
- // Brown Shade
- { name: 'bronze tint, bronze shade', src: 'Windshield-BrownShade-BrownTint.svg' },
-
- // Gray Shade
- { name: 'blue tint, gray shade', src: 'Windshield-GrayShade-BlueTint.svg' },
- { name: 'brown tint, gray shade', src: 'Windshield-GrayShade-BrownTint.svg' },
- { name: 'gray tint, gray shade', src: 'Windshield-GrayShade-GrayTint.svg' },
- { name: 'green tint, gray shade', src: 'Windshield-GrayShade-GreenTint.svg' },
-
- // Green Shade
- { name: 'blue tint, green shade', src: 'Windshield-GreenShade-BlueTint.svg' },
- { name: 'brown tint, green shade', src: 'Windshield-GreenShade-BrownTint.svg' },
- { name: 'green tint, green shade', src: 'Windshield-GreenShade-GreenTint.svg' },
-
- // Tints Only
- { name: 'blue tint', src: 'Windshield-NoShade-BlueTint.svg' },
- { name: 'bronze tint', src: 'Windshield-NoShade-BrownTint.svg' },
- { name: 'dark brown tint', src: 'Windshield-NoShade-DarkBrownTint.svg' },
- { name: 'privacy, black frame', src: 'Windshield-NoShade-Privacy.svg' },
- { name: 'gray tint', src: 'Windshield-NoShade-GrayTint.svg' },
- { name: 'green tint', src: 'Windshield-NoShade-GreenTint.svg' },
- { name: 'gray tint privacy', src: 'Windshield-NoShade-GrayTint.svg' },
-
- // No shade or tint
- { name: 'clear', src: 'Windshield-NoShade-NoTint.svg' }
- ]
-});
-
-// Gets the tint image source string given the glass location, and the tint description (like 'Green Tint')
-// Use lowered strings here to try to avoid mismatch. Returns an empty string if array key doesn't exist.
-// Returns undefined if no items are found.
-const getTintImage = (glassLocation, colorString) => {
- // Windshield glass has special images, all other glass uses the same though.
- const glassLoc = (glassLocation.toLowerCase() !== 'windshield') ? 'other' : 'windshield';
- if (tintMap[glassLoc] === undefined) {
- return '';
- }
-
- return tintMap[glassLoc].find((item) => item.name.toLowerCase() === colorString.toLowerCase());
-};
-
-export default getTintImage;
diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue
index 85bef043..6bf89bb5 100644
--- a/src/digital-components/textbox-question/textbox-question.vue
+++ b/src/digital-components/textbox-question/textbox-question.vue
@@ -310,22 +310,31 @@ input::-webkit-date-and-time-value {
.input-wrapper {
position: relative;
&.has-search-icon {
+ display:flex;
+ .form-control {
+ &:focus, &:focus-within {
+ border: 1px solid #0070d1;
+ }
+ max-height: 3rem;
+ }
input[type='text'] {
- border-radius: $border-radius;
+ border-color: #0070d1;
+ box-shadow: rgba(0, 0, 0, 0.2) 0rem 0.0625rem .25rem 0rem;
+ border-right: none;
+ border-radius: 4.5rem 0 0 4.5rem;
+ height: 3rem;
+ &:focus, &:focus-within {
+ border-right:none;
+ }
}
button[type='submit'] {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- right: 0;
background-image: url($svg-search-icon);
background-repeat: no-repeat;
background-position: center;
- border-radius: 0 $border-radius-lg $border-radius-lg 0;
+ border-radius: 0 4.5rem 4.5rem 0;
background-color: $blue-100;
width: 2.75rem;
- height: 100%;
- border: 1px solid $gray-500;
+ border: 1px solid #0070d1;
border-left: none;
display: flex;
}
diff --git a/src/helpers/global-rule-definer.js b/src/helpers/global-rule-definer.js
index b91f3dc0..58f52516 100644
--- a/src/helpers/global-rule-definer.js
+++ b/src/helpers/global-rule-definer.js
@@ -125,6 +125,28 @@ function defineGlobalZipCodeRules() {
defineRule(globalRules.ZIP_CODE_SEARCH_FORMAT, regex(/^\d{5}$/, errorMessages.ZIP_FORMAT));
}
+/**
+ * @summary Define global rules related to the zip code/shop name search on TPA Search page
+ */
+function defineGlobalTpaSearchRules() {
+ defineRule(globalRules.TPA_SEARCH_FORMAT, (value) => {
+ if (value.length === 0) {
+ return errorMessages.TPA_SEARCH_REQUIRED;
+ }
+ // Non Numeric
+ if (isNaN(value)) {
+ if (value.length < 3) {
+ return errorMessages.TPA_SEARCH_SHOP_FORMAT;
+ }
+ } else {
+ if (value.length != 5) {
+ return errorMessages.TPA_SEARCH_ZIP_FORMAT;
+ }
+ }
+ return true;
+ });
+}
+
/**
* @function defineGlobalRules
* @summary Define all global rules
@@ -138,6 +160,6 @@ export default function defineGlobalRules() {
defineGlobalPolicyNumberRules();
defineGlobalPolicyZipCodeRules();
defineGlobalZipCodeRules();
-
+ defineGlobalTpaSearchRules();
defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED));
}
diff --git a/src/helpers/text-helper.js b/src/helpers/text-helper.js
index b6fc5184..c05b870a 100644
--- a/src/helpers/text-helper.js
+++ b/src/helpers/text-helper.js
@@ -46,7 +46,7 @@ export function createUnorderedListFromStringOfParagraphs(stringOfParagraphs) {
*/
export function toTitleCase(text) {
let temp = text?.toLowerCase() ?? '';
- return temp.replace(/(^|\s|-)\S/g, (letter) => letter.toUpperCase());
+ return temp.replace(/(^|\s|-|\/)\S/g, (letter) => letter.toUpperCase());
}
/**
diff --git a/src/iss-components/questions-page-layout/questions-page-layout.vue b/src/iss-components/questions-page-layout/questions-page-layout.vue
index 43ce4251..9a20bb12 100644
--- a/src/iss-components/questions-page-layout/questions-page-layout.vue
+++ b/src/iss-components/questions-page-layout/questions-page-layout.vue
@@ -6,7 +6,7 @@
diff --git a/src/iss-components/site-footer/site-footer.vue b/src/iss-components/site-footer/site-footer.vue
index 9499c3c2..a694015e 100644
--- a/src/iss-components/site-footer/site-footer.vue
+++ b/src/iss-components/site-footer/site-footer.vue
@@ -14,14 +14,13 @@
id="stacked"
class="col button-col d-flex px-0">
diff --git a/src/iss-components/tpa-shop-list-button/tpa-shop-list-button.vue b/src/iss-components/tpa-shop-list-button/tpa-shop-list-button.vue
new file mode 100644
index 00000000..8fbe5146
--- /dev/null
+++ b/src/iss-components/tpa-shop-list-button/tpa-shop-list-button.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+ {{ buttonLabel }}
+
+ {{ buttonLabelSubCopy }}
+
+
+
+
+
+
+ {{ screenReaderOnlyText }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/layouts/tpa-search/__snapshots__/tpa-search.spec.js.snap b/src/layouts/tpa-search/__snapshots__/tpa-search.spec.js.snap
deleted file mode 100644
index 0c7e4c55..00000000
--- a/src/layouts/tpa-search/__snapshots__/tpa-search.spec.js.snap
+++ /dev/null
@@ -1,214 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`TPA search page returns the initial data 1`] = `
-Object {
- "additionalButtonData": Object {
- "displayAvailabilityIndicators": false,
- },
- "dataLoaded": false,
- "filter": "",
- "mapZipCode": null,
- "providers": Array [],
- "reloadingProviders": false,
- "rules": Object {
- "filter": "option-required",
- "provider": "option-required",
- "zipCode": "zip-code-required|zip-code-search-format",
- },
- "selectedProviderNumber": "",
- "shopListButton": Object {
- "beforeMount": [Function],
- "components": Object {
- "baseInputButton": Object {
- "computed": Object {
- "buttonId": [Function],
- "eventTypes": [Function],
- "inputType": [Function],
- "isChecked": [Function],
- "isValueSelectedOnClick": [Function],
- },
- "data": [Function],
- "emits": Array [
- "update:modelValue",
- ],
- "methods": Object {
- "handleBlur": [Function],
- "handleClick": [Function],
- "handleEventAction": [Function],
- "handleFocus": [Function],
- "handleSelectionChange": [Function],
- },
- "mounted": [Function],
- "name": "base-input-button",
- "props": Object {
- "buttonWrapperClasses": Array [
- [Function],
- [Function],
- [Function],
- ],
- "groupName": Object {
- "required": true,
- "type": [Function],
- },
- "inputClasses": Array [
- [Function],
- [Function],
- [Function],
- ],
- "isMultiSelect": [Function],
- "isRequired": Object {
- "default": true,
- "type": [Function],
- },
- "lastValuePushedToGa": Array [
- [Function],
- [Function],
- ],
- "modelValue": Object {
- "required": true,
- "validator": [Function],
- },
- "selectingInitiatesLoad": Object {
- "default": false,
- "type": [Function],
- },
- "setLastValuePushedToGa": [Function],
- "suppressError": [Function],
- "validationRules": Object {
- "default": "",
- "type": [Function],
- },
- "value": Object {
- "required": true,
- "type": Array [
- [Function],
- [Function],
- ],
- },
- "valueToLogType": [Function],
- },
- "render": [Function],
- "setup": [Function],
- },
- "loader": Object {
- "computed": Object {
- "cssProps": [Function],
- },
- "methods": Object {
- "captureClick": [Function],
- },
- "name": "loader",
- "props": Object {
- "allowPageInteraction": Object {
- "default": false
- "type": [Function],
- },
- "height": Object {
- "default": 1,
- "type": [Function],
- },
- "loaderColor": Object {
- "type": [Function],
- },
- "loaderPosition": Object {
- "type": [Function],
- },
- "width": Object {
- "default": 1,
- "type": [Function],
- },
- },
- "render": [Function],
- },
- },
- "computed": Object {
- "availabilityRatingClass": [Function],
- "badgeText": [Function],
- "isLoaderDisplayed": [Function],
- },
- "data": [Function],
- "mixins": Array [
- Object {
- "computed": Object {
- "selectedValue": Object {
- "get": [Function],
- "set": [Function],
- },
- },
- "model": Object {
- "event": "change",
- "prop": "modelValue",
- },
- "props": Object {
- "additionalButtonData": [Function],
- "additionalButtonStyling": [Function],
- "altText": Object {
- "default": "",
- "type": [Function],
- },
- "buttonAuxiliaryCopy": [Function],
- "buttonBodyCopy": [Function],
- "buttonFooterCopy": [Function],
- "buttonImage": [Function],
- "buttonImageId": [Function],
- "buttonLabel": Array [
- [Function],
- [Function],
- ],
- "buttonLabelSubCopy": [Function],
- "groupName": Object {
- "required": true,
- "type": [Function],
- },
- "isMultiSelect": [Function],
- "isRequired": Object {
- "default": true,
- "type": [Function],
- },
- "isWide": [Function],
- "lastValuePushedToGa": Array [
- [Function],
- [Function],
- ],
- "modelValue": Object {
- "required": true,
- "validator": [Function],
- },
- "screenReaderOnlyText": [Function],
- "selectingInitiatesLoad": Object {
- "default": false,
- "type": [Function],
- },
- "setLastValuePushedToGa": [Function],
- "suppressError": [Function],
- "textPosition": [Function],
- "validationRules": Object {
- "default": "",
- "type": [Function],
- },
- "value": Object {
- "required": true,
- "type": Array [
- [Function],
- [Function],
- ],
- },
- "valueToLogType": [Function],
- },
- },
- ],
- "name": "shop-list-button",
- "render": [Function],
- },
- "widget": Object {
- "filterByQuestion": "FilterByQuestion",
- "noNetworkShopsAlert": "NoNetworkShopsAlertWidget",
- "searchInstructions": "SearchInstructions",
- "shopNotListedLink": "ShopNotListedLink",
- "siteFooter": "SiteFooterWidget",
- "siteHeader": "SiteHeaderWidget",
- "tpaSearchQuestion": "TPASearchQuestion",
- },
- "zipCode": null,
-}
-`;
diff --git a/src/layouts/tpa-search/tpa-search.spec.js b/src/layouts/tpa-search/tpa-search.spec.js
index 393938b8..d2d5ad2e 100644
--- a/src/layouts/tpa-search/tpa-search.spec.js
+++ b/src/layouts/tpa-search/tpa-search.spec.js
@@ -1,1031 +1,503 @@
+/* eslint-disable max-len */
// Components
-import { shallowMount } from '@vue/test-utils';
-import { createTestingPinia } from '@pinia/testing';
import tpaSearch from '@/layouts/tpa-search/tpa-search.vue';
// Supporting Files
-import baseMixin from '@/mixins/base-mixin';
+import { nextTick } from 'vue';
+import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
-import { useMainStore } from '@/store';
-import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
+import { createTestingPinia } from '@pinia/testing';
+import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
import settleAllPromises from '@/helpers/layout-helper.js';
+import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
+import { useMainStore } from '@/store';
+import { toTitleCase, toDisplayPhoneNumber } from '@/helpers/text-helper.js';
+import bailoutMessage from '@/constants/bailoutMessage';
import globalRules from '@/constants/global-rules.js';
-import widgetFields from '@/constants/cms-widget-fields.js';
-import navigationScenarios from '@/router/router-constants/navigation-scenarios';
-// Mock fetchCmsContentForPage
-jest.mock('@/helpers/cms-content-helper', () => ({
- fetchCmsContentForPage: jest.fn(),
- doesCopyContainRouterLink: jest.fn()
-}));
-
-// Mock our module for promises.
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
-function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRunAfterInitializingStore = () => {}) {
+jest.mock('@/helpers/cms-content-helper', () => ({
+ fetchCmsContentForPage: jest.fn(),
+ setupModalLinks: jest.fn(),
+ processIfStatements: jest.fn()
+}));
+
+jest.mock('@/helpers/text-helper', () => ({
+ toTitleCase: jest.fn((text) => text?.toLowerCase()?.replace(/(^|\s|-)\S/g, (letter) => letter.toUpperCase()) ?? ''),
+ toDisplayPhoneNumber: jest.fn((phone) => phone ?? '')
+}));
+
+const mockMixin = {
+ methods: {
+ getCmsContent: jest.fn().mockImplementation(() => ''),
+ setCmsContent: jest.fn(),
+ onSubmit: jest.fn(),
+ onInvalidSubmit: jest.fn(),
+ navigateBack: jest.fn(),
+ savePageDataToStore: jest.fn()
+ }
+};
+
+const footerStub = {
+ render: () => {},
+ methods: {
+ updateButtonText: jest.fn()
+ }
+};
+
+const loaderStub = {
+ render: () => {},
+ template: ''
+};
+
+function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) {
const mountOptions = getMountOptions({
router: {
navigate: jest.fn()
+ },
+ route: {
+ query: { issPage: 'tpa-search' }
}
});
+ mountOptions.global.stubs = {
+ ...mountOptions.global.stubs,
+ siteFooter: footerStub,
+ siteHeader: true,
+ textboxQuestion: true,
+ dropdownQuestion: true,
+ buttonQuestion: true,
+ textLink: true,
+ alert: true,
+ googleMap: true,
+ loader: loaderStub
+ };
+
const testingPinia = createTestingPinia({
initialState: {
- main: mainInitialState
+ main: {
+ order: {
+ customer: {
+ address: {
+ zipCode: '43215'
+ }
+ },
+ serviceLocation: {
+ provider: {
+ providerNumber: ''
+ }
+ }
+ },
+ ...mainInitialState
+ }
}
});
useMainStore(testingPinia);
- methodToRunAfterInitializingStore();
+ methodToRun();
mountOptions.global.plugins = [testingPinia];
- mountOptions.data = () => (initialData);
+ mountOptions.mixins = [mockMixin];
+ mountOptions.data = () => ({
+ dataLoaded: true,
+ ...initialData
+ });
- const apiResponses = { cmsContent: {} };
-
- settleAllPromises.mockImplementation(() => apiResponses);
+ const apiResponses = {
+ cmsContent: {},
+ providers: []
+ };
+ const apiPromise = Promise.resolve(apiResponses);
+ settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const wrapper = shallowMount(tpaSearch, mountOptions);
- wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {});
- wrapper.vm.setCmsContent = jest.fn();
- wrapper.vm.$router.navigateWithSpinner = jest.fn();
- wrapper.vm.navigateBack = baseMixin.methods.navigateBack;
-
return { wrapper };
}
-describe('TPA search page', () => {
- test.skip('returns the initial data', () => {
- // Arrange
- const zipCode = '12663';
- const mainInitialState = {
- order: {
- customer: {
- address: { zipCode }
- }
- }
- };
- const { wrapper } = getMountedComponent(mainInitialState);
-
- // Assert
- expect(wrapper.vm.$data).toMatchSnapshot();
+describe('tpa-search.vue', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
});
- describe('should render', () => {
- test('site header', () => {
+
+ describe('Rendering', () => {
+ test('Should render site header', () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const expectedWidgetName = 'SiteHeaderWidget';
+ const { wrapper } = getMountedComponent();
// Act
const siteHeader = wrapper.findComponent({ ref: 'siteHeader' });
// Assert
- expect(siteHeader.exists()).toBeTruthy();
- expect(siteHeader.props().cmsWidgetName).toBe(expectedWidgetName);
+ expect(siteHeader.exists()).toBe(true);
});
- test('search providers form', () => {
+
+ test('Should render site footer', () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
-
- // Act
- const searchProvidersForm = wrapper.findComponent('#searchProvidersForm');
-
- // Assert
- expect(searchProvidersForm.exists()).toBeTruthy();
- });
- test('search question label', () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
-
- // Act
- const searchQuestionLabel = wrapper.find('#tpaSearchQuestionLabel');
-
- // Assert
- expect(searchQuestionLabel.exists()).toBeTruthy();
- expect(searchQuestionLabel.attributes().for).toBe('tpaSearchQuestionField');
- expect(searchQuestionLabel.classes()).toContain('text-center');
- expect(searchQuestionLabel.classes()).toContain('mt-5');
- expect(searchQuestionLabel.classes()).toContain('mb-0');
- expect(searchQuestionLabel.classes()).toContain('text-black');
- expect(searchQuestionLabel.classes()).toContain('w-100');
- expect(searchQuestionLabel.classes()).toContain('fs-5');
- });
- test('search instructions', () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
-
- // Act
- const searchInstructions = wrapper.find('#searchInstructions');
-
- // Assert
- expect(searchInstructions.exists()).toBeTruthy();
- expect(searchInstructions.attributes().for).toBe('tpaSearchQuestionField');
- expect(searchInstructions.classes()).toContain('text-center');
- expect(searchInstructions.classes()).toContain('small');
- expect(searchInstructions.classes()).toContain('darker-gray');
- expect(searchInstructions.classes()).toContain('w-100');
- expect(searchInstructions.classes()).toContain('mb-4');
- });
- test('search question field', () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const expectedWidgetName = 'TPASearchQuestion';
-
- // Act
- const searchQuestionField = wrapper.findComponent('#tpaSearchQuestionField');
-
- // Assert
- expect(searchQuestionField.exists()).toBeTruthy();
- expect(searchQuestionField.props().inputId).toBe('tpaSearchQuestionFieldInput');
- expect(searchQuestionField.props().isRequired).toBeTruthy();
- expect(searchQuestionField.props().cmsWidgetName).toBe(expectedWidgetName);
- expect(searchQuestionField.props().includeSearchIcon).toBeTruthy();
- expect(searchQuestionField.props().displayQuestionText).toBeFalsy();
- expect(searchQuestionField.props().validationRules)
- .toBe(`${globalRules.ZIP_CODE_REQUIRED}|${globalRules.ZIP_CODE_SEARCH_FORMAT}`);
- });
- test('provider selection form', () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
-
- // Act
- const providerSelectionForm = wrapper.findComponent('#providerSelectionForm');
-
- // Assert
- expect(providerSelectionForm.exists()).toBeTruthy();
- });
- test('map', async () => {
- // Arrange
- const zipCode = '12345';
const { wrapper } = getMountedComponent();
- await wrapper.setData({
- providers: [{
- address: {
- streetAddress: '123 Lane Ave',
- city: 'New York',
- state: 'NY',
- zipCode: '99230'
- }
- }],
- mapZipCode: zipCode
- });
- const expectedAddresses = ['123 Lane Ave, New York, NY 99230'];
// Act
- const map = wrapper.findComponent('#map');
+ const siteFooter = wrapper.findComponent({ ref: 'siteFooter' });
// Assert
- expect(map.exists()).toBeTruthy();
- expect(map.classes()).toContain('mb-4');
- expect(map.props().markers.map((p) => p.fullAddress)).toEqual(expectedAddresses);
- expect(map.props().zipCode).toBe(zipCode);
+ expect(siteFooter.exists()).toBe(true);
});
- test('search radius filter', async () => {
+
+ test('Should render tpa search question label', () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const expectedWidgetName = 'FilterByQuestion';
+ const { wrapper } = getMountedComponent();
// Act
- const searchRadiusFilter = wrapper.findComponent('#searchRadiusFilter');
+ const label = wrapper.find('#tpaSearchQuestionLabel');
// Assert
- expect(searchRadiusFilter.exists()).toBeTruthy();
- expect(searchRadiusFilter.props().cmsWidgetName).toBe(expectedWidgetName);
- expect(searchRadiusFilter.props().validationRules).toBe(globalRules.OPTION_REQUIRED);
+ expect(label.exists()).toBe(true);
});
- test('providers loader when reloadingProviders is true', async () => {
+
+ test('Should render search instructions label', () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ reloadingProviders: true });
+ const { wrapper } = getMountedComponent();
// Act
- const providersLoader = wrapper.findComponent('#providersLoader');
+ const label = wrapper.find('#searchInstructions');
// Assert
- expect(providersLoader.exists()).toBeTruthy();
+ expect(label.exists()).toBe(true);
});
- test('select provider question when reloadingProviders are false', async () => {
+
+ test('Should render textbox question for TPA search', () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({
- providers: [{
- companyName: 'Shop Auto Glass',
- phoneNumber: '740-555-1234',
- distanceInMiles: 1.2345,
- providerNumber: '232209',
- address: {
- streetAddress: '123 Lane Ave',
- city: 'New York',
- state: 'NY',
- zipCode: '99230'
- }
- }],
+ const { wrapper } = getMountedComponent();
+
+ // Act
+ const textbox = wrapper.find('#tpaSearchQuestionField');
+
+ // Assert
+ expect(textbox.exists()).toBe(true);
+ });
+
+ test('Should render dropdown for radius filter', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+
+ // Act
+ const dropdown = wrapper.find('#searchRadiusFilter');
+
+ // Assert
+ expect(dropdown.exists()).toBe(true);
+ });
+
+ test('Should render google map', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+
+ // Act
+ const map = wrapper.find('#map');
+
+ // Assert
+ expect(map.exists()).toBe(true);
+ });
+
+ test('Should show loader state when reloadingProviders is true', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, { reloadingProviders: true });
+
+ // Assert
+ expect(wrapper.vm.reloadingProviders).toBe(true);
+ });
+
+ test('Should show provider selection when reloadingProviders is false', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, { reloadingProviders: false });
+
+ // Assert
+ expect(wrapper.vm.reloadingProviders).toBe(false);
+ });
+
+ test('Should render no network shops alert when providers is empty', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, { providers: [] });
+
+ // Act
+ const alert = wrapper.find('#alertNoNetworkProviders');
+
+ // Assert
+ expect(alert.exists()).toBe(true);
+ });
+
+ test('Should render preferred shop not listed link', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, { reloadingProviders: false });
+
+ // Act
+ const link = wrapper.find('#preferredShopNotListedLink');
+
+ // Assert
+ expect(link.exists()).toBe(true);
+ });
+
+ test('Should have needHelpLinkText computed property', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, {
reloadingProviders: false
});
- const expectedAnswers = [{
- buttonLabel: 'Shop Auto Glass',
- buttonLabelSubCopy: '1.2 mi',
- buttonBodyCopy: '123 Lane Ave, New York, NY 99230
740-555-1234',
- value: '232209'
- }];
- const expectedAdditionalButtonData = {
- displayAvailabilityIndicators: false
- };
- // Act
- const selectProviderQuestion = wrapper.findComponent('#selectProviderQuestion');
-
- // Assert
- expect(selectProviderQuestion.exists()).toBeTruthy();
- expect(selectProviderQuestion.props().buttonTypeString).toBe('shopListButton');
- expect(selectProviderQuestion.classes()).toContain('radioQuestion');
- expect(selectProviderQuestion.props().groupName).toBe('chooseShop');
- expect(selectProviderQuestion.props().textPosition).toBe('text-start');
- expect(selectProviderQuestion.props().isRequired).toBeTruthy();
- expect(selectProviderQuestion.props().validationRules).toBe(globalRules.OPTION_REQUIRED);
- expect(selectProviderQuestion.props().answers).toEqual(expectedAnswers);
- expect(selectProviderQuestion.props().additionalButtonData).toEqual(expectedAdditionalButtonData);
- });
- test.each([[], null, undefined])(
- 'no network providers alert when providers length is 0, undefined, or null and reloadingProviders is false',
- async (providers) => {
- // Arrange
- const initialData = {
- providers
- };
- const wrapper = shallowMount(tpaSearch, getMountOptions({}, initialData));
- await wrapper.setData({ reloadingProviders: false });
-
- // Act
- const noNetworkProvidersAlert = wrapper.findComponent('#alertNoNetworkProviders');
-
- // Assert
- expect(noNetworkProvidersAlert.exists()).toBeTruthy();
- expect(noNetworkProvidersAlert.props().cmsWidgetName).toBeTruthy();
- expect(noNetworkProvidersAlert.props().alertClass).toBe('alert-warning');
- expect(noNetworkProvidersAlert.props().isDismissible).toBeFalsy();
- }
- );
- test('preferred shop not listed link when reloadingProviders is false', async () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ reloadingProviders: false });
-
- // Act
- const preferredShopNotListedLink = wrapper.findComponent('#preferredShopNotListedLink');
-
- // Assert
- expect(preferredShopNotListedLink.exists()).toBeTruthy();
- expect(preferredShopNotListedLink.props().linkType).toBe('navigation');
- // eslint-disable-next-line no-script-url
- expect(preferredShopNotListedLink.props().href).toBe('javascript:void(0)');
- });
- test('site footer', () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
-
- // Act
- const footer = wrapper.findComponent({ ref: 'siteFooter' });
-
- // Assert
- expect(footer.exists()).toBeTruthy();
- expect(footer.props().cmsWidgetName).toBe('SiteFooterWidget');
+ // Assert - needHelpLinkText computed exists and returns a value (empty string from mock)
+ expect(wrapper.vm.needHelpLinkText).toBeDefined();
});
});
- describe('should not render', () => {
- test('select provider question when reloadingProviders is true', async () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- await wrapper.setData({ reloadingProviders: true });
- // Act
- const selectProviderQuestion = wrapper.findComponent('#selectProviderQuestion');
-
- // Assert
- expect(selectProviderQuestion.exists()).toBeFalsy();
- });
- describe('no network providers alert', () => {
- test('when providers length is not 0', async () => {
+ describe('Computed', () => {
+ describe('radiusFilterOptions', () => {
+ test('returns empty object when no options', () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ providers: ['p1', 'p2'] });
+ const { wrapper } = getMountedComponent();
// Act
- const noNetworkProvidersAlert = wrapper.findComponent('#alertNoNetworkProviders');
+ const result = wrapper.vm.radiusFilterOptions;
// Assert
- expect(noNetworkProvidersAlert.exists()).toBeFalsy();
+ expect(result).toEqual({});
});
- test('when reloadingProviders is true', async () => {
+
+ test('returns formatted options when CMS content exists', () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ providers: [], reloadingProviders: true });
+ const mockOptions = [
+ { Name: '10', Text: '10 miles' },
+ { Name: '25', Text: '25 miles' },
+ { Name: '50', Text: '50 miles' }
+ ];
+ const mountOptions = getMountOptions({ router: { navigate: jest.fn() } });
+ mountOptions.global.stubs = { siteFooter: footerStub, siteHeader: true, loader: loaderStub };
+ mountOptions.mixins = [{
+ methods: {
+ getCmsContent: jest.fn().mockImplementation(() => mockOptions),
+ setCmsContent: jest.fn(),
+ onSubmit: jest.fn(),
+ onInvalidSubmit: jest.fn(),
+ navigateBack: jest.fn(),
+ savePageDataToStore: jest.fn()
+ }
+ }];
+ mountOptions.data = () => ({ dataLoaded: true });
+ const wrapper = shallowMount(tpaSearch, mountOptions);
// Act
- const noNetworkProvidersAlert = wrapper.findComponent('#alertNoNetworkProviders');
+ const result = wrapper.vm.radiusFilterOptions;
// Assert
- expect(noNetworkProvidersAlert.exists()).toBeFalsy();
+ expect(result).toEqual({
+ '10': '10 miles',
+ '25': '25 miles',
+ '50': '50 miles'
+ });
});
});
- test('preferred shop not listed link when reloadingProviders is true', async () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- await wrapper.setData({ reloadingProviders: true });
- // Act
- const preferredShopNotListedLink = wrapper.findComponent('#preferredShopNotListedLink');
-
- // Assert
- expect(preferredShopNotListedLink.exists()).toBeFalsy();
- });
- });
- describe('computed', () => {
- describe('filterOptions', () => {
- test.each([[], null, undefined])(
- 'returns empty object when cms content is empty, null or undefined',
- (cmsContent) => {
- // Arrange
- const mountOptions = getMountOptions();
- mountOptions.mixins = [{
- methods: {
- getCmsContent: jest.fn().mockImplementation((widget, field) =>
- (widget === 'FilterByQuestion' && field === widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
- ? cmsContent
- : ''))
- }
- }];
- const wrapper = shallowMount(tpaSearch, mountOptions);
-
- // Act
- const result = wrapper.vm.filterOptions;
-
- // Assert
- expect(result).toEqual({});
- }
- );
- test('returns expected when cms content is some non empty iterable', () => {
+ describe('radiusFilteredAndCappedProviders', () => {
+ test('filters providers by radius and caps at 5', () => {
// Arrange
- const mountOptions = getMountOptions();
- const cmsContent = [{ Name: 'foo' }, { Name: 'bar' }];
- mountOptions.mixins = [{
- methods: {
- getCmsContent: jest.fn().mockImplementation((widget, field) =>
- (widget === 'FilterByQuestion' && field === widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
- ? cmsContent
- : ''))
- }
- }];
- const wrapper = shallowMount(tpaSearch, mountOptions);
- const expected = { foo: 'foo', bar: 'bar' };
+ const providers = [
+ { providerNumber: '1', distanceInMiles: 5, companyName: 'Shop 1', address: {} },
+ { providerNumber: '2', distanceInMiles: 15, companyName: 'Shop 2', address: {} },
+ { providerNumber: '3', distanceInMiles: 20, companyName: 'Shop 3', address: {} },
+ { providerNumber: '4', distanceInMiles: 30, companyName: 'Shop 4', address: {} },
+ { providerNumber: '5', distanceInMiles: 35, companyName: 'Shop 5', address: {} },
+ { providerNumber: '6', distanceInMiles: 40, companyName: 'Shop 6', address: {} },
+ { providerNumber: '7', distanceInMiles: 45, companyName: 'Shop 7', address: {} }
+ ];
+ const { wrapper } = getMountedComponent({}, { providers, radiusFilter: 50 });
// Act
- const result = wrapper.vm.filterOptions;
+ const result = wrapper.vm.radiusFilteredAndCappedProviders;
// Assert
- expect(result).toEqual(expected);
+ expect(result.length).toBe(5);
+ });
+
+ test('filters out providers beyond radius', () => {
+ // Arrange
+ const providers = [
+ { providerNumber: '1', distanceInMiles: 5, companyName: 'Shop 1', address: {} },
+ { providerNumber: '2', distanceInMiles: 15, companyName: 'Shop 2', address: {} },
+ { providerNumber: '3', distanceInMiles: 30, companyName: 'Shop 3', address: {} }
+ ];
+ const { wrapper } = getMountedComponent({}, { providers, radiusFilter: 25 });
+
+ // Act
+ const result = wrapper.vm.radiusFilteredAndCappedProviders;
+
+ // Assert
+ expect(result.length).toBe(2);
+ expect(result.map(p => p.providerNumber)).toEqual(['1', '2']);
});
});
- test.each([null, undefined, '', 'non empty string'])(
- 'tpaSearchQuestionLabel returns "%p" from getCmsContent',
- (cmsContent) => {
- // Arrange
- const mountOptions = getMountOptions();
- mountOptions.mixins = [{
- methods: {
- getCmsContent: jest.fn().mockImplementation((widget, field) =>
- (widget === 'TPASearchQuestion' && field === widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT
- ? cmsContent
- : ''))
- }
- }];
- const wrapper = shallowMount(tpaSearch, mountOptions);
- // Act
- const result = wrapper.vm.tpaSearchQuestionLabel;
-
- // Assert
- expect(result).toEqual(cmsContent);
- }
- );
- test.each([null, undefined, '', 'non empty string'])(
- 'searchInstructionsText returns "%p" from getCmsContent',
- (cmsContent) => {
- // Arrange
- const mountOptions = getMountOptions();
- mountOptions.mixins = [{
- methods: {
- getCmsContent: jest.fn().mockImplementation((widget, field) =>
- (widget === 'SearchInstructions' && field === widgetFields.TEXT_BLOCK_WIDGET.TEXT
- ? cmsContent
- : ''))
- }
- }];
- const wrapper = shallowMount(tpaSearch, mountOptions);
-
- // Act
- const result = wrapper.vm.searchInstructionsText;
-
- // Assert
- expect(result).toEqual(cmsContent);
- }
- );
- test.each([null, undefined, '', 'non empty string'])(
- 'shopNotListedModalLink returns "%p" from getCmsContent',
- (cmsContent) => {
- // Arrange
- const mountOptions = getMountOptions();
- mountOptions.mixins = [{
- methods: {
- getCmsContent: jest.fn().mockImplementation((widget, field) =>
- (widget === 'ShopNotListedLink' && field === widgetFields.TEXT_BLOCK_WIDGET.TEXT
- ? cmsContent
- : ''))
- }
- }];
- const wrapper = shallowMount(tpaSearch, mountOptions);
-
- // Act
- const result = wrapper.vm.shopNotListedModalLink;
-
- // Assert
- expect(result).toEqual(cmsContent);
- }
- );
- describe('radiusInMiles', () => {
- test.each([
- [15, '15 miles'],
- [25, '25 miles'],
- [50, '50 miles'],
- [100, '100 miles']
- ])(
- 'returns %p when filter is "%p"',
- async (expectedRadius, filter) => {
- // Arrange
- const { wrapper } = getMountedComponent();
- await wrapper.setData({ filter });
-
- // Act
- const result = wrapper.vm.radiusInMiles;
-
- // Assert
- expect(result).toEqual(expectedRadius);
- }
- );
- test.each([null, undefined, 'some random string'])(
- 'returns 0 when filter is "%p"',
- async (filter) => {
- // Arrange
- const { wrapper } = getMountedComponent();
- await wrapper.setData({ filter });
-
- // Act
- const result = wrapper.vm.radiusInMiles;
-
- // Assert
- expect(result).toEqual(0);
- }
- );
- });
- describe('noNetworkShopsAlertHeaderText', () => {
- test('returns exact cmsContent value when "{custom:radiusInMiles}" is not a substring', async () => {
- // Arrange
- const cmsContent = 'content returned from cms';
- const mountOptions = getMountOptions();
- mountOptions.mixins = [{
- methods: {
- getCmsContent: jest.fn().mockImplementation((widget, field) =>
- (widget === 'NoNetworkShopsAlertWidget' && field === widgetFields.ALERT_WIDGET.HEADLINE_TEXT
- ? cmsContent
- : ''))
- }
- }];
- const wrapper = shallowMount(tpaSearch, mountOptions);
-
- // Act
- const result = wrapper.vm.noNetworkShopsAlertHeaderText;
-
- // Assert
- expect(result).toEqual(cmsContent);
- });
- test('returns cmsContent value with all instances of "{custom:radiusInMiles}" replaced with radiusInMiles', () => {
- // Arrange
- const cmsContent = '{custom:radiusInMiles} ret{custom:radiusInMiles}urned {custom:radiusInMiles}cms{custom:radiusInMiles}';
- const mountOptions = getMountOptions();
- mountOptions.mixins = [{
- methods: {
- getCmsContent: jest.fn().mockImplementation((widget, field) =>
- (widget === 'NoNetworkShopsAlertWidget' && field === widgetFields.ALERT_WIDGET.HEADLINE_TEXT
- ? cmsContent
- : ''))
- }
- }];
- const wrapper = shallowMount(tpaSearch, mountOptions);
- const expected = '0 ret0urned 0cms0';
-
- // Act
- const result = wrapper.vm.noNetworkShopsAlertHeaderText;
-
- // Assert
- expect(result).toEqual(expected);
- });
- });
describe('providerAddresses', () => {
- test.each([null, undefined, []])(
- 'returns empty list when providers empty',
- async (providers) => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ providers });
-
- // Act
- const result = wrapper.vm.providerAddresses;
-
- // Assert
- expect(result).toEqual([]);
- }
- );
- test('returns expected when providers not empty', async () => {
+ test('maps providers to address objects for google map', () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({
- providers: [
- {
- companyName: 'Shop Auto Glass',
- phoneNumber: '740-555-1234',
- distanceInMiles: 1.2345,
- providerNumber: '232209',
- address: {
- streetAddress: '123 Lane Ave',
- city: 'New York',
- state: 'NY',
- zipCode: '99230'
- }
- },
- {
- companyName: 'Safelite AutoGlass',
- phoneNumber: '676-555-0099',
- distanceInMiles: 123.9452,
- providerNumber: '123456',
- address: {
- streetAddress: '2003 Coral Ln',
- city: 'Birmingham',
- state: 'AL',
- zipCode: '43001'
- }
- }
- ]
- });
- const expectedResult = [
- '123 Lane Ave, New York, NY 99230',
- '2003 Coral Ln, Birmingham, AL 43001'
- ];
-
- // Act
- const result = wrapper.vm.providerAddresses.map((pa) => pa.fullAddress);
-
- // Assert
- expect(result).toEqual(expectedResult);
- });
- });
- describe('providerButtonData', () => {
- test.each([null, undefined, []])(
- 'returns empty list when providers equals "%p"',
- async (providers) => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ providers });
-
- // Act
- const result = wrapper.vm.providerButtonData;
-
- // Assert
- expect(result).toEqual([]);
- }
- );
- test('returns expected when providers not empty', async () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({
- providers: [
- {
- companyName: 'Shop Auto Glass',
- phoneNumber: '740-555-1234',
- distanceInMiles: 1.2345,
- providerNumber: '232209',
- address: {
- streetAddress: '123 Lane Ave',
- city: 'New York',
- state: 'NY',
- zipCode: '99230'
- }
- },
- {
- companyName: 'Safelite AutoGlass',
- phoneNumber: '676-555-0099',
- distanceInMiles: 123.9452,
- providerNumber: '123456',
- address: {
- streetAddress: '2003 Coral Ln',
- city: 'Birmingham',
- state: 'AL',
- zipCode: '43001'
- }
- }
- ]
- });
- const expectedResult = [
+ const providers = [
{
- buttonLabel: 'Shop Auto Glass',
- buttonLabelSubCopy: '1.2 mi',
- buttonBodyCopy: '123 Lane Ave, New York, NY 99230
740-555-1234',
- value: '232209'
- },
- {
- buttonLabel: 'Safelite AutoGlass',
- buttonLabelSubCopy: '123.9 mi',
- buttonBodyCopy: '2003 Coral Ln, Birmingham, AL 43001
676-555-0099',
- value: '123456'
+ providerNumber: '1',
+ companyName: 'TEST SHOP',
+ distanceInMiles: 5,
+ address: {
+ streetAddress: '123 MAIN ST',
+ city: 'COLUMBUS',
+ state: 'OH',
+ zipCode: '43215'
+ }
}
];
+ const { wrapper } = getMountedComponent({}, { providers, radiusFilter: 25 });
+
+ // Act
+ const result = wrapper.vm.providerAddresses;
+
+ // Assert
+ expect(result.length).toBe(1);
+ expect(result[0].title).toBe('test shop');
+ expect(result[0].addressLines.length).toBe(2);
+ });
+
+ test('returns empty array when no providers', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, { providers: [], radiusFilter: 25 });
+
+ // Act
+ const result = wrapper.vm.providerAddresses;
+
+ // Assert
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('providerButtonData', () => {
+ test('maps providers to button data format', () => {
+ // Arrange
+ const providers = [
+ {
+ providerNumber: '12345',
+ companyName: 'AUTO GLASS SHOP',
+ distanceInMiles: 5.75,
+ phoneNumber: '6145551234',
+ address: {
+ streetAddress: '456 OAK AVE',
+ city: 'DUBLIN',
+ state: 'OH',
+ zipCode: '43017'
+ }
+ }
+ ];
+ const { wrapper } = getMountedComponent({}, { providers, radiusFilter: 25 });
// Act
const result = wrapper.vm.providerButtonData;
// Assert
- expect(result).toEqual(expectedResult);
+ expect(result.length).toBe(1);
+ expect(result[0].buttonLabel).toBe('auto glass shop');
+ expect(result[0].buttonLabelSubCopy).toBe('5.8 mi');
+ expect(result[0].value).toBe('12345');
});
});
+
describe('selectedProviderIsSafeliteShop', () => {
- test('no issue when provider in providers with no provider number', async () => {
+ test('returns true when selected provider is Safelite shop', () => {
// Arrange
- const selectedProviderNumber = '10099';
const providers = [
- { isSafeliteShop: false },
- { isSafeliteShop: true }
+ { providerNumber: '123', isSafeliteShop: true },
+ { providerNumber: '456', isSafeliteShop: false }
];
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ selectedProviderNumber, providers });
+ const { wrapper } = getMountedComponent({}, {
+ providers,
+ selectedProviderNumber: '123',
+ radiusFilter: 25
+ });
// Act
const result = wrapper.vm.selectedProviderIsSafeliteShop;
// Assert
- expect(result).toEqual(false);
+ expect(result).toBe(true);
});
- test.each([null, undefined, []])(
- 'returns false when providers %s',
- async (providers) => {
- // Arrange
- const selectedProviderNumber = '10099';
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ selectedProviderNumber, providers });
- // Act
- const result = wrapper.vm.selectedProviderIsSafeliteShop;
-
- // Assert
- expect(result).toEqual(false);
- }
- );
- test.each([
- [true, true],
- [false, false]
- ])(
- 'returns %p when first instance of multiple matching providerNumbers has isSafeliteShop value %p',
- async (expectedOutput, isSafeliteShop) => {
- // Arrange
- const selectedProviderNumber = '29987';
- const providers = [
- {
- providerNumber: selectedProviderNumber,
- isSafeliteShop
- },
- {
- providerNumber: selectedProviderNumber,
- isSafeliteShop: !isSafeliteShop
- }
- ];
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ providers });
- await wrapper.setData({ selectedProviderNumber });
-
- // Act
- const result = wrapper.vm.selectedProviderIsSafeliteShop;
-
- // Assert
- expect(result).toEqual(expectedOutput);
- }
- );
- test.each([[false, false], [true, true]])(
- 'returns %p when providerNumber match has isSafeliteShop equal to %p',
- async (expectedOutput, isSafeliteShop) => {
- // Arrange
- const selectedProviderNumber = '19274';
- const providers = [{
- providerNumber: selectedProviderNumber,
- isSafeliteShop
- }];
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- await wrapper.setData({ selectedProviderNumber, providers });
-
- // Act
- const result = wrapper.vm.selectedProviderIsSafeliteShop;
-
- // Assert
- expect(result).toEqual(expectedOutput);
- }
- );
- });
- });
- describe('watch', () => {
- // TODO update/add to filter watch tests
- test('on filter calls getTpaProviders and sets providers', async () => {
- // Arrange
- const zipCode = '78220';
- const initialMapZipCode = '88800';
- const { wrapper } = getMountedComponent({}, {
- zipCode,
- mapZipCode: initialMapZipCode,
- dataLoaded: true
- });
- const providers = { data: { shopProviders: ['some data', 'some more data'] } };
- useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => (providers));
- const newFilter = 'new filter';
-
- // Act
- await wrapper.vm.$options.watch.filter.call(wrapper.vm, newFilter);
-
- // Assert
- expect(useMainStore().getTpaProviders).toBeCalled();
- expect(wrapper.vm.providers).toEqual(providers.data.shopProviders);
- expect(wrapper.vm.mapZipCode).toBe(zipCode);
- });
- describe('on filter', () => {
- test('calls getTpaProviders once and sets providers when dataLoaded is true', async () => {
+ test('returns false when selected provider is not Safelite shop', () => {
// Arrange
- const zipCode = '78220';
- const initialMapZipCode = '88800';
+ const providers = [
+ { providerNumber: '123', isSafeliteShop: true },
+ { providerNumber: '456', isSafeliteShop: false }
+ ];
const { wrapper } = getMountedComponent({}, {
- zipCode,
- mapZipCode: initialMapZipCode,
- dataLoaded: true
+ providers,
+ selectedProviderNumber: '456',
+ radiusFilter: 25
});
- const providers = { data: { shopProviders: ['some data', 'some more data'] } };
- useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => (providers));
- const newFilter = 'new filter';
// Act
- await wrapper.vm.$options.watch.filter.call(wrapper.vm, newFilter);
+ const result = wrapper.vm.selectedProviderIsSafeliteShop;
// Assert
- expect(useMainStore().getTpaProviders).toBeCalled();
- expect(wrapper.vm.providers).toEqual(providers.data.shopProviders);
- expect(wrapper.vm.mapZipCode).toBe(zipCode);
+ expect(result).toBe(false);
});
- test('never calls getTpaProviders and does not set providers when dataLoaded is false', async () => {
+
+ test('returns false when no provider is selected', () => {
// Arrange
- const zipCode = '78220';
- const initialMapZipCode = '88800';
+ const providers = [
+ { providerNumber: '123', isSafeliteShop: true }
+ ];
const { wrapper } = getMountedComponent({}, {
- zipCode,
- mapZipCode: initialMapZipCode,
- dataLoaded: false
+ providers,
+ selectedProviderNumber: '',
+ radiusFilter: 25
});
- const providers = { data: { shopProviders: ['some data', 'some more data'] } };
- useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => (providers));
- const newFilter = 'new filter';
// Act
- await wrapper.vm.$options.watch.filter.call(wrapper.vm, newFilter);
+ const result = wrapper.vm.selectedProviderIsSafeliteShop;
// Assert
- expect(useMainStore().getTpaProviders).not.toBeCalled();
- expect(wrapper.vm.providers).not.toEqual(providers.data.shopProviders);
- expect(wrapper.vm.mapZipCode).toBe(initialMapZipCode);
+ expect(result).toBe(false);
});
});
- // TODO confirm tests appropriate. Also should this method be async?
- describe('on providers', () => {
- test('does not update provider number when dataLoaded false', () => {
+
+ describe('noNetworkShopsAlertHeaderText', () => {
+ test('replaces radius placeholder with actual value', () => {
// Arrange
- const initialValue = 1234;
- const { wrapper } = getMountedComponent({}, {
- dataLoaded: false,
- selectedProviderNumber: initialValue
- });
- const value = 'some other value';
- const newProviders = [{ providerNumber: value }];
-
- // Act
- wrapper.vm.$options.watch.providers.call(wrapper.vm, newProviders);
-
- // Assert
- expect(wrapper.vm.selectedProviderNumber).toBe(initialValue);
- });
- test.each([null, undefined, []])(
- 'sets selected provider number to "" when there are no providers',
- (newProviders) => {
- // Arrange
- const { wrapper } = getMountedComponent({}, {
- dataLoaded: true,
- selectedProviderNumber: null
- });
-
- // Act
- wrapper.vm.$options.watch.providers.call(wrapper.vm, newProviders);
-
- // Assert
- expect(wrapper.vm.selectedProviderNumber).toBe('');
- }
- );
- test('sets selected provider number to value of provider when there is one provider', () => {
- // Arrange
- const { wrapper } = getMountedComponent({}, {
- dataLoaded: true,
- selectedProviderNumber: null
- });
- const value = 'some value';
- const newProviders = [{ providerNumber: value }];
-
- // Act
- wrapper.vm.$options.watch.providers.call(wrapper.vm, newProviders);
-
- // Assert
- expect(wrapper.vm.selectedProviderNumber).toBe(value);
- });
- test('sets selected provider number to "" when there are more than one provider', () => {
- // Arrange
- const { wrapper } = getMountedComponent({}, {
- dataLoaded: true,
- selectedProviderNumber: null
- });
- const newProviders = [{ value: 'val1' }, { value: 'val2' }];
-
- // Act
- wrapper.vm.$options.watch.providers.call(wrapper.vm, newProviders);
-
- // Assert
- expect(wrapper.vm.selectedProviderNumber).toBe('');
- });
- });
- describe('selectedProviderNumber', () => {
- describe('does not call updateServiceLocation when', () => {
- test('dataLoaded is false', () => {
- // Arrange
- const providerNumber = 38447;
- const { wrapper } = getMountedComponent({}, {
- providers: [{
- providerNumber,
- address: {
- streetAddress: '143 Average Lane',
- city: 'Cambridge',
- state: 'OH',
- zipCode: '72983',
- zipCodeCtu: '0390'
- },
- companyName: "Sally's Auto",
- phoneNumber: '1234567890'
- }],
- dataLoaded: false
- });
-
- // Act
- wrapper.vm.$options.watch.selectedProviderNumber.call(wrapper.vm, providerNumber);
-
- // Assert
- expect(wrapper.vm.mainStore.updateServiceLocation).not.toHaveBeenCalled();
- });
- test('providers list is null ', () => {
- // Arrange
- const { wrapper } = getMountedComponent({}, {
- providers: null,
- dataLoaded: true
- });
- 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: [],
- dataLoaded: true
- });
- 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'
- }],
- dataLoaded: true
- });
- 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 filter = '10 miles';
- const serviceZipCode = 10098;
- const { wrapper } = getMountedComponent({}, {
- providers: [
- provider,
- { providerNumber: 328949832 }
- ],
- filter,
- zipCode: serviceZipCode,
- dataLoaded: true
- });
-
- // Act
- wrapper.vm.$options.watch.selectedProviderNumber.call(wrapper.vm, newProviderNumber);
-
- // Assert
- expect(wrapper.vm.mainStore.updateServiceLocation).toHaveBeenCalledTimes(1);
- expect(wrapper.vm.mainStore.updateServiceLocation).toHaveBeenCalledWith({
- searchFilter: filter,
- zipCode: serviceZipCode,
- provider: {
- providerNumber: newProviderNumber,
- address: {
- streetAddress,
- city,
- state,
- zipCode,
- zipCodeCtu
- },
- companyName,
- phoneNumber
+ const mountOptions = getMountOptions({ router: { navigate: jest.fn() } });
+ mountOptions.global.stubs = { siteFooter: footerStub, siteHeader: true, loader: loaderStub };
+ mountOptions.mixins = [{
+ methods: {
+ getCmsContent: jest.fn().mockImplementation(() => 'No shops within {custom:radiusInMiles}'),
+ setCmsContent: jest.fn(),
+ onSubmit: jest.fn(),
+ onInvalidSubmit: jest.fn(),
+ navigateBack: jest.fn(),
+ savePageDataToStore: jest.fn()
}
- });
+ }];
+ mountOptions.data = () => ({ dataLoaded: true, radiusFilter: 25 });
+ const wrapper = shallowMount(tpaSearch, mountOptions);
+
+ // Act
+ const result = wrapper.vm.noNetworkShopsAlertHeaderText;
+
+ // Assert
+ expect(result).toBe('No shops within 25 miles');
});
});
});
- describe('method', () => {
- test.each([
- ['address', 'city', 'ST', 'zip', 'Address, City, ST zip'],
- ['address', null, 'ST', 'zip', 'Address, ST zip'],
- ['address', 'city', null, 'zip', 'Address, City zip'],
- ['address', 'city', 'ST', null, 'Address, City, ST'],
- [null, null, null, null, '']
- ])(
- 'getFullProviderAddress returns expected',
- (streetAddress, city, state, zipCode, expected) => {
+
+ describe('Methods', () => {
+ describe('getFullProviderAddress', () => {
+ test('returns combined address lines', () => {
// Arrange
const { wrapper } = getMountedComponent();
const provider = {
address: {
- streetAddress,
- city,
- state,
- zipCode
+ streetAddress: '123 MAIN ST',
+ city: 'COLUMBUS',
+ state: 'OH',
+ zipCode: '43215'
}
};
@@ -1033,26 +505,20 @@ describe('TPA search page', () => {
const result = wrapper.vm.getFullProviderAddress(provider);
// Assert
- expect(result).toEqual(expected);
- }
- );
- test.each([
- ['address', 'city', 'ST', 'zip', 'Address'],
- ['address', null, 'ST', 'zip', 'Address'],
- ['address', 'city', null, 'zip', 'Address'],
- ['address', 'city', 'ST', null, 'Address'],
- [null, null, null, null, '']
- ])(
- 'getProviderAddress returns expected',
- (streetAddress, city, state, zipCode, expected) => {
+ expect(result).toContain('123 Main St');
+ expect(result).toContain('Columbus');
+ expect(result).toContain('OH');
+ expect(result).toContain('43215');
+ });
+ });
+
+ describe('getProviderAddress', () => {
+ test('returns title cased street address', () => {
// Arrange
const { wrapper } = getMountedComponent();
const provider = {
address: {
- streetAddress,
- city,
- state,
- zipCode
+ streetAddress: 'UPPERCASE STREET'
}
};
@@ -1060,26 +526,31 @@ describe('TPA search page', () => {
const result = wrapper.vm.getProviderAddress(provider);
// Assert
- expect(result).toEqual(expected);
- }
- );
- test.each([
- ['address', 'city', 'ST', 'zip', 'City, ST zip'],
- ['address', null, 'ST', 'zip', 'ST zip'],
- ['address', 'city', null, 'zip', 'City zip'],
- ['address', 'city', 'ST', null, 'City, ST'],
- [null, null, null, null, '']
- ])(
- 'getProviderCityZipState returns expected',
- (streetAddress, city, state, zipCode, expected) => {
+ expect(toTitleCase).toHaveBeenCalledWith('UPPERCASE STREET');
+ });
+
+ test('handles null address', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+ const provider = { address: null };
+
+ // Act
+ const result = wrapper.vm.getProviderAddress(provider);
+
+ // Assert
+ expect(result).toBe('');
+ });
+ });
+
+ describe('getProviderCityZipState', () => {
+ test('returns formatted city, state, zip', () => {
// Arrange
const { wrapper } = getMountedComponent();
const provider = {
address: {
- streetAddress,
- city,
- state,
- zipCode
+ city: 'COLUMBUS',
+ state: 'OH',
+ zipCode: '43215'
}
};
@@ -1087,132 +558,174 @@ describe('TPA search page', () => {
const result = wrapper.vm.getProviderCityZipState(provider);
// Assert
- expect(result).toEqual(expected);
- }
- );
- describe('getProviderButtonData', () => {
- test.each([null, undefined, {}])(
- 'returns empty list when getTpaProviders returns no data',
- async (newProviders) => {
- // Arrange
- const { wrapper } = getMountedComponent();
- useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => (newProviders));
+ expect(result).toContain('OH');
+ expect(result).toContain('43215');
+ });
- // Act
- const result = await wrapper.vm.getProviderButtonData();
-
- // Assert
- expect(result).toEqual([]);
- }
- );
- test('returns expected when getTpaProviders returns data', async () => {
+ test('handles missing city', () => {
// Arrange
const { wrapper } = getMountedComponent();
- const providers = {
- data: {
- shopProviders: [{ companyName: 'foo' }]
+ const provider = {
+ address: {
+ state: 'OH',
+ zipCode: '43215'
}
};
- useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => (providers));
// Act
- const result = await wrapper.vm.getProviderButtonData();
+ const result = wrapper.vm.getProviderCityZipState(provider);
// Assert
- expect(result).toEqual(providers.data.shopProviders);
+ expect(result).toBe('OH 43215');
+ });
+
+ test('handles missing state and zip', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+ const provider = {
+ address: {
+ city: 'COLUMBUS'
+ }
+ };
+
+ // Act
+ const result = wrapper.vm.getProviderCityZipState(provider);
+
+ // Assert
+ expect(result).toContain('Columbus');
});
});
- test('doNotSeeMyShopLinkClick invokes navigate method', () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- // Act
- wrapper.vm.doNotSeeMyShopLinkClick();
-
- // Assert
- expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
- });
- describe('searchClick', () => {
- test.each([null, undefined, {}])(
- 'sets providers to empty list when no data returned from getProviders',
- async (newProviders) => {
- // Arrange
- const zipCode = '28331';
- const initialMapZipCode = '10022';
- const { wrapper } = getMountedComponent({}, {
- zipCode,
- mapZipCode: initialMapZipCode
- });
- useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => (newProviders));
-
- // Act
- await wrapper.vm.searchClick();
-
- // Assert
- expect(wrapper.vm.providers).toEqual([]);
- expect(wrapper.vm.mapZipCode).toEqual(zipCode);
- }
- );
- test('returns value from getProviders', async () => {
+ describe('getShopButtonDataFromProvider', () => {
+ test('returns formatted button data with distance', () => {
// Arrange
- const zipCode = '12990';
- const initialMapZipCode = '00981';
- const { wrapper } = getMountedComponent({}, {
- zipCode,
- mapZipCode: initialMapZipCode
- });
- const shopProviders = [{ companyName: 'foo' }];
- useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => ({
- data: { shopProviders }
- }));
+ const { wrapper } = getMountedComponent();
+ const provider = {
+ providerNumber: '12345',
+ companyName: 'TEST SHOP',
+ distanceInMiles: 5.789,
+ phoneNumber: '6145551234',
+ address: {
+ streetAddress: '123 MAIN ST',
+ city: 'COLUMBUS',
+ state: 'OH',
+ zipCode: '43215'
+ }
+ };
+
+ // Act
+ const result = wrapper.vm.getShopButtonDataFromProvider(provider);
+
+ // Assert
+ expect(result.buttonLabel).toBe('test shop');
+ expect(result.buttonLabelSubCopy).toBe('5.8 mi');
+ expect(result.value).toBe('12345');
+ expect(result.buttonBodyCopy).toContain('
');
+ });
+
+ test('returns empty distance when distanceInMiles is null', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+ const provider = {
+ providerNumber: '12345',
+ companyName: 'TEST SHOP',
+ distanceInMiles: null,
+ phoneNumber: '6145551234',
+ address: {}
+ };
+
+ // Act
+ const result = wrapper.vm.getShopButtonDataFromProvider(provider);
+
+ // Assert
+ expect(result.buttonLabelSubCopy).toBe('');
+ });
+
+ test('returns empty distance when distanceInMiles is NaN', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+ const provider = {
+ providerNumber: '12345',
+ companyName: 'TEST SHOP',
+ distanceInMiles: NaN,
+ phoneNumber: '6145551234',
+ address: {}
+ };
+
+ // Act
+ const result = wrapper.vm.getShopButtonDataFromProvider(provider);
+
+ // Assert
+ expect(result.buttonLabelSubCopy).toBe('');
+ });
+ });
+
+ describe('searchClick', () => {
+ test('searches by shop name when input is not a zip code', async () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+ wrapper.vm.tpaSearchValue = 'Auto Glass Shop';
+ wrapper.vm.getProviderButtonData = jest.fn().mockResolvedValue([]);
// Act
await wrapper.vm.searchClick();
// Assert
- expect(wrapper.vm.providers).toEqual(shopProviders);
- expect(wrapper.vm.mapZipCode).toEqual(zipCode);
+ expect(wrapper.vm.getProviderButtonData).toHaveBeenCalledWith('Auto Glass Shop');
});
- });
- test('backButtonAction invokes navigate method', () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- // Act
- wrapper.vm.navigateBack();
-
- // Assert
- expect(wrapper.vm.$router.navigateWithSpinner).toHaveBeenCalled();
- });
- describe('forwardButtonAction', () => {
- test('invokes navigate method with safelite shop scenario when selectedProviderIsSafeliteShop true', async () => {
+ test('updates mapZipCode when input is a zip code', async () => {
// Arrange
const { wrapper } = getMountedComponent();
- const providerNumber = '1109';
- await wrapper.setData({
- selectedProviderNumber: providerNumber,
- providers: [{
- providerNumber,
- isSafeliteShop: true
- }]
+ wrapper.vm.tpaSearchValue = '43215';
+ wrapper.vm.mapZipCode = '12345';
+ wrapper.vm.getProviderButtonData = jest.fn().mockResolvedValue([]);
+
+ // Act
+ await wrapper.vm.searchClick();
+
+ // Assert
+ expect(wrapper.vm.mapZipCode).toBe('43215');
+ expect(wrapper.vm.getProviderButtonData).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('forwardButtonAction', () => {
+ test('navigates with SAFELITE_SHOP scenario when provider is Safelite', () => {
+ // Arrange
+ const providers = [
+ { providerNumber: '123', isSafeliteShop: true, distanceInMiles: 5, companyName: 'Safelite', address: {} }
+ ];
+ const { wrapper } = getMountedComponent({}, {
+ providers,
+ selectedProviderNumber: '123',
+ radiusFilter: 25,
+ tpaSearchValue: 'test',
+ mapZipCode: '43215'
});
// Act
wrapper.vm.forwardButtonAction();
// Assert
- expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP, undefined);
+ expect(wrapper.vm.mainStore.updateIsSafeliteProvider).toHaveBeenCalledWith(true);
+ expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
+ navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP,
+ expect.anything()
+ );
});
- test('invokes navigate method with non safelite shop scenario when selectedProviderIsSafeliteShop false', async () => {
+
+ test('navigates with NON_SAFELITE_SHOP scenario when provider is not Safelite', () => {
// Arrange
- const { wrapper } = getMountedComponent();
- const providerNumber = '928';
- await wrapper.setData({
- selectedProviderNumber: providerNumber,
- providers: [{
- providerNumber,
- isSafeliteShop: false
- }]
+ const providers = [
+ { providerNumber: '456', isSafeliteShop: false, distanceInMiles: 5, companyName: 'Other Shop', address: {} }
+ ];
+ const { wrapper } = getMountedComponent({}, {
+ providers,
+ selectedProviderNumber: '456',
+ radiusFilter: 25,
+ tpaSearchValue: 'test',
+ mapZipCode: '43215'
});
// Act
@@ -1221,421 +734,335 @@ describe('TPA search page', () => {
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
- undefined
+ expect.anything()
+ );
+ });
+
+ test('saves empty tpaSearchValue when it equals mapZipCode', () => {
+ // Arrange
+ const providers = [
+ { providerNumber: '123', isSafeliteShop: false, distanceInMiles: 5, companyName: 'Test Shop', address: {} }
+ ];
+ const { wrapper } = getMountedComponent({}, {
+ providers,
+ selectedProviderNumber: '123',
+ radiusFilter: 25,
+ tpaSearchValue: '43215',
+ mapZipCode: '43215'
+ });
+ const savePageDataSpy = jest.spyOn(wrapper.vm, 'savePageDataToStore');
+
+ // Act
+ wrapper.vm.forwardButtonAction();
+
+ // Assert
+ expect(savePageDataSpy).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({ tpaSearchValue: '' })
+ );
+ });
+
+ test('saves tpaSearchValue when different from mapZipCode', () => {
+ // Arrange
+ const providers = [
+ { providerNumber: '123', isSafeliteShop: false, distanceInMiles: 5, companyName: 'Auto Shop', address: {} }
+ ];
+ const { wrapper } = getMountedComponent({}, {
+ providers,
+ selectedProviderNumber: '123',
+ radiusFilter: 25,
+ tpaSearchValue: 'Auto Shop',
+ mapZipCode: '43215'
+ });
+ const savePageDataSpy = jest.spyOn(wrapper.vm, 'savePageDataToStore');
+
+ // Act
+ wrapper.vm.forwardButtonAction();
+
+ // Assert
+ expect(savePageDataSpy).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({ tpaSearchValue: 'Auto Shop' })
);
});
});
- describe('getCustomValueFromString', () => {
- test('returns radius in miles value if "radiusInMiles"', () => {
+
+ describe('needHelpLinkClick', () => {
+ test('sets bailout and navigates', () => {
// Arrange
const { wrapper } = getMountedComponent();
- const str = 'radiusInMiles';
// Act
- const result = wrapper.vm.getCustomValueFromString(str);
+ wrapper.vm.needHelpLinkClick();
// Assert
- expect(result).toBe(0);
- });
- test('returns radius in miles value if not "radiusInMiles"', () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- const str = 'some other string';
-
- // Act
- const result = wrapper.vm.getCustomValueFromString(str);
-
- // Assert
- expect(result).toBeNull();
+ expect(wrapper.vm.mainStore.setBailout).toHaveBeenCalled();
+ expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
+ navigationScenarios.CLICKED_NEED_HELP,
+ expect.anything()
+ );
});
});
- describe('getShopButtonDataFromProvider', () => {
- test.each([null, undefined, {}])(
- 'returns empty list given parameter with no provider',
- (provider) => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const expectedResult = {
- buttonLabel: '',
- buttonLabelSubCopy: '',
- buttonBodyCopy: '
',
- value: ''
- };
- // Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
-
- // Assert
- expect(result).toEqual(expectedResult);
- }
- );
- test('returns expected given provider', () => {
+ describe('getProviderButtonData', () => {
+ test('sets reloadingProviders to true then false', async () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const provider = {
- companyName: 'Shop Auto Glass',
- phoneNumber: '740-555-1234',
- distanceInMiles: 1.2345,
- providerNumber: '232209',
- address: {
- streetAddress: '123 Lane Ave',
- city: 'New York',
- state: 'NY',
- zipCode: '99230'
- }
- };
- const expectedResult = {
- buttonLabel: 'Shop Auto Glass',
- buttonLabelSubCopy: '1.2 mi',
- buttonBodyCopy: '123 Lane Ave, New York, NY 99230
740-555-1234',
- value: '232209'
- };
+ const { wrapper } = getMountedComponent();
+ wrapper.vm.mainStore.getTpaAndSafeliteProviders = jest.fn().mockResolvedValue({ data: [] });
// Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
+ const promise = wrapper.vm.getProviderButtonData();
+ expect(wrapper.vm.reloadingProviders).toBe(true);
+ await promise;
// Assert
- expect(result).toEqual(expectedResult);
+ expect(wrapper.vm.reloadingProviders).toBe(false);
});
- describe('returns result with button label', () => {
- test.each(['', undefined, null])(
- 'equal to empty string when name is empty',
- (companyName) => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const provider = { companyName };
- // Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
-
- // Assert
- expect(result.buttonLabel).toEqual('');
- }
- );
- test('returns provider name when exists', () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const companyName = 'Some Shop Name';
- const provider = { companyName };
-
- // Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
-
- // Assert
- expect(result.buttonLabel).toEqual(companyName);
- });
- });
- describe('returns result with button label sub copy', () => {
- test.each([null, undefined, 'random string'])(
- 'as empty string when distanceInMiles is not a number',
- (distanceInMiles) => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const provider = { distanceInMiles };
-
- // Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
-
- // Assert
- expect(result.buttonLabelSubCopy).toEqual('');
- }
- );
- test.each([[0, 0], [0, 0.000], [-7.89, -7.9], [109, 109], [1.234, 1.2], [2.99, 3]])(
- 'displays expected distance value',
- (distanceInMiles, displayedDistance) => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const provider = { distanceInMiles };
- const expectedSubCopy = `${displayedDistance} mi`;
-
- // Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
-
- // Assert
- expect(result.buttonLabelSubCopy).toEqual(expectedSubCopy);
- }
- );
- });
- test('returns result with button body copy showing expected address and phone number', () => {
+ test('calls store method with zipCode and shopName', async () => {
// Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const provider = {
- phoneNumber: '123-555-0099',
- address: {
- streetAddress: '434 Up Down Blvd',
- city: 'San Francisco',
- state: 'CA',
- zipCode: '90887'
- }
- };
- const expected = '434 Up Down Blvd, San Francisco, CA 90887
123-555-0099';
+ const { wrapper } = getMountedComponent();
+ wrapper.vm.mapZipCode = '43215';
+ wrapper.vm.mainStore.getTpaAndSafeliteProviders = jest.fn().mockResolvedValue({ data: [] });
// Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
+ await wrapper.vm.getProviderButtonData('Test Shop');
// Assert
- expect(result.buttonBodyCopy).toEqual(expected);
- });
- describe('returns result with value', () => {
- test.each(['', undefined, null])(
- 'equal to empty string when providerNumber is empty',
- (providerNumber) => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const provider = { providerNumber };
-
- // Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
-
- // Assert
- expect(result.value).toEqual('');
- }
- );
- test('returns provider number when exists', () => {
- // Arrange
- const wrapper = shallowMount(tpaSearch, getMountOptions());
- const providerNumber = '123391';
- const provider = { providerNumber };
-
- // Act
- const result = wrapper.vm.getShopButtonDataFromProvider(provider);
-
- // Assert
- expect(result.value).toEqual(providerNumber);
- });
+ expect(wrapper.vm.mainStore.getTpaAndSafeliteProviders).toHaveBeenCalledWith('43215', 'Test Shop');
});
});
});
- describe('before route enter', () => {
- test('when service location zipCode set in store, it is used', async () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- const customerZipCode = '18394';
- const serviceZipCode = '43982';
- useMainStore().order.customer.address.zipCode = customerZipCode;
- useMainStore().order.serviceLocation.zipCode = serviceZipCode;
- // Act
- await tpaSearch.beforeRouteEnter.call(
- wrapper.vm,
- { query: { issPage: 'tpa-search' } },
- undefined,
- (c) => c(wrapper.vm)
- );
-
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
-
- // Assert
- expect(wrapper.vm.zipCode).toBe(serviceZipCode);
- });
- test('when service location zipCode not set in store, customer zipCode used', async () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- const customerZipCode = '18394';
- useMainStore().order.customer.address.zipCode = customerZipCode;
- useMainStore().order.serviceLocation.zipCode = null;
-
- // Act
- await tpaSearch.beforeRouteEnter.call(
- wrapper.vm,
- { query: { issPage: 'tpa-search' } },
- undefined,
- (c) => c(wrapper.vm)
- );
-
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
-
- // Assert
- expect(wrapper.vm.zipCode).toBe(customerZipCode);
- });
- test('when search filter set in store, expected filter and provider number returned', async () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- const customerZipCode = '18394';
- const searchFilter = '25 miles';
- const providerNumber = 749321;
- useMainStore().order.customer.address.zipCode = customerZipCode;
- useMainStore().order.serviceLocation.zipCode = null;
- useMainStore().order.serviceLocation.searchFilter = searchFilter;
- useMainStore().order.serviceLocation.provider.providerNumber = providerNumber;
- const providers = [{ companyName: 'some provider' }];
- const expectedRadius = 25;
- useMainStore().getTpaProviders = jest.fn().mockImplementation((_, radius) =>
- ({ data: { shopProviders: radius === expectedRadius ? providers : [] } }));
-
- // Act
- await tpaSearch.beforeRouteEnter.call(
- wrapper.vm,
- { query: { issPage: 'tpa-search' } },
- undefined,
- (c) => c(wrapper.vm)
- );
-
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
-
- // Assert
- expect(wrapper.vm.filter).toBe(searchFilter);
- expect(wrapper.vm.providers).toEqual(providers);
- expect(wrapper.vm.selectedProviderNumber).toBe(providerNumber);
- expect(useMainStore().getTpaProviders).toBeCalledTimes(1);
- expect(useMainStore().getTpaProviders).toBeCalledWith(customerZipCode, expectedRadius);
- });
- test('when providers exist at 15 mile radius, filter is set to "15 miles" and providers set to expected', async () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- const zipCode = '18394';
- useMainStore().order.customer.address.zipCode = '00001';
- useMainStore().order.serviceLocation.zipCode = zipCode;
- useMainStore().order.serviceLocation.searchFilter = null;
- const providers = [{ companyName: 'provider' }];
- useMainStore().getTpaProviders = jest.fn().mockImplementation((_, radius) =>
- ({ data: { shopProviders: radius === 15 ? providers : [] } }));
- const expectedFilter = '15 miles';
-
- // Act
- await tpaSearch.beforeRouteEnter.call(
- wrapper.vm,
- { query: { issPage: 'tpa-search' } },
- undefined,
- (c) => c(wrapper.vm)
- );
-
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
-
- // Assert
- expect(wrapper.vm.zipCode).toBe(zipCode);
- expect(wrapper.vm.filter).toBe(expectedFilter);
- expect(wrapper.vm.providers).toEqual(providers);
- expect(wrapper.vm.selectedProviderNumber).toBeNull();
- expect(useMainStore().getTpaProviders).toBeCalledTimes(1);
- });
- test('when providers exist at 25 mile radius, filter is set to "25 miles" and providers set to expected', async () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- const zipCode = '18394';
- useMainStore().order.customer.address.zipCode = '00001';
- useMainStore().order.serviceLocation.zipCode = zipCode;
- useMainStore().order.serviceLocation.searchFilter = null;
- const providers = [{ companyName: 'provider' }];
- useMainStore().getTpaProviders = jest.fn().mockImplementation((_, radius) =>
- ({ data: { shopProviders: radius === 25 ? providers : [] } }));
- const expectedFilter = '25 miles';
-
- // Act
- await tpaSearch.beforeRouteEnter.call(
- wrapper.vm,
- { query: { issPage: 'tpa-search' } },
- undefined,
- (c) => c(wrapper.vm)
- );
-
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
-
- // Assert
- expect(wrapper.vm.zipCode).toBe(zipCode);
- expect(wrapper.vm.filter).toBe(expectedFilter);
- expect(wrapper.vm.providers).toEqual(providers);
- expect(wrapper.vm.selectedProviderNumber).toBeNull();
- expect(useMainStore().getTpaProviders).toBeCalledTimes(2);
- });
- test('when providers exist at 50 mile radius but not 25, filter is set to "50 miles" and providers set to expected', async () => {
- // Arrange
- const { wrapper } = getMountedComponent();
- const zipCode = '18394';
- useMainStore().order.customer.address.zipCode = '00001';
- useMainStore().order.serviceLocation.zipCode = zipCode;
- useMainStore().order.serviceLocation.searchFilter = null;
- const providers = [{ companyName: 'provider' }];
- useMainStore().getTpaProviders = jest.fn().mockImplementation((_, radius) =>
- ({ data: { shopProviders: radius === 50 ? providers : [] } }));
- const expectedFilter = '50 miles';
-
- // Act
- await tpaSearch.beforeRouteEnter.call(
- wrapper.vm,
- { query: { issPage: 'tpa-search' } },
- undefined,
- (c) => c(wrapper.vm)
- );
-
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
-
- // Assert
- expect(wrapper.vm.zipCode).toBe(zipCode);
- expect(wrapper.vm.filter).toBe(expectedFilter);
- expect(wrapper.vm.providers).toEqual(providers);
- expect(wrapper.vm.selectedProviderNumber).toBeNull();
- expect(useMainStore().getTpaProviders).toBeCalledTimes(3);
- });
- test(
- 'when providers exist at 100 mile radius but not 50 or 25, filter is set to "100 miles" and providers set to expected',
- async () => {
+ describe('Watchers', () => {
+ describe('providers watcher', () => {
+ test('auto-selects provider when only one provider exists', async () => {
// Arrange
- const { wrapper } = getMountedComponent();
- const zipCode = '18394';
- useMainStore().order.customer.address.zipCode = zipCode;
- useMainStore().order.serviceLocation.zipCode = null;
- useMainStore().order.serviceLocation.searchFilter = null;
- const providers = [{ companyName: 'provider' }];
- useMainStore().getTpaProviders = jest.fn().mockImplementation((_, radius) =>
- ({ data: { shopProviders: radius === 100 ? providers : [] } }));
- const expectedFilter = '100 miles';
+ const { wrapper } = getMountedComponent({}, { dataLoaded: true });
+ wrapper.vm.selectedProviderNumber = '';
// Act
- await tpaSearch.beforeRouteEnter.call(
- wrapper.vm,
- { query: { issPage: 'tpa-search' } },
- undefined,
- (c) => c(wrapper.vm)
- );
-
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
+ wrapper.vm.providers = [{ providerNumber: '12345', distanceInMiles: 5, companyName: 'Test Shop', address: {} }];
+ await nextTick();
// Assert
- expect(wrapper.vm.zipCode).toBe(zipCode);
- expect(wrapper.vm.filter).toBe(expectedFilter);
- expect(wrapper.vm.providers).toEqual(providers);
- expect(wrapper.vm.selectedProviderNumber).toBeNull();
- expect(useMainStore().getTpaProviders).toBeCalledTimes(4);
- }
- );
- test(
- 'when no providers exist at 100, 50, or 25 mile radius, filter is set to "100 miles" and providers set to empty list',
- async () => {
+ expect(wrapper.vm.selectedProviderNumber).toBe('12345');
+ });
+
+ test('clears selection when multiple providers exist', async () => {
// Arrange
- const { wrapper } = getMountedComponent();
- const zipCode = '18394';
- useMainStore().order.customer.address.zipCode = '00001';
- useMainStore().order.serviceLocation.zipCode = zipCode;
- useMainStore().order.serviceLocation.searchFilter = null;
- useMainStore().getTpaProviders = jest.fn().mockImplementation(() => ([]));
- const expectedFilter = '100 miles';
+ const { wrapper } = getMountedComponent({}, { dataLoaded: true });
+ wrapper.vm.selectedProviderNumber = '12345';
// Act
- await tpaSearch.beforeRouteEnter.call(
- wrapper.vm,
- { query: { issPage: 'tpa-search' } },
- undefined,
- (c) => c(wrapper.vm)
- );
-
- await wrapper.vm.$nextTick();
- await wrapper.vm.$nextTick();
+ wrapper.vm.providers = [
+ { providerNumber: '12345', distanceInMiles: 5, companyName: 'Shop 1', address: {} },
+ { providerNumber: '67890', distanceInMiles: 10, companyName: 'Shop 2', address: {} }
+ ];
+ await nextTick();
// Assert
- expect(wrapper.vm.zipCode).toBe(zipCode);
- expect(wrapper.vm.filter).toBe(expectedFilter);
- expect(wrapper.vm.providers).toEqual([]);
- expect(wrapper.vm.selectedProviderNumber).toBeNull();
- expect(useMainStore().getTpaProviders).toBeCalledTimes(4);
- }
- );
+ expect(wrapper.vm.selectedProviderNumber).toBe('');
+ });
+
+ test('does not auto-select when dataLoaded is false', async () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, { dataLoaded: false });
+ wrapper.vm.selectedProviderNumber = '';
+
+ // Act
+ wrapper.vm.providers = [{ providerNumber: '12345', distanceInMiles: 5, companyName: 'Test', address: {} }];
+ await nextTick();
+
+ // Assert
+ expect(wrapper.vm.selectedProviderNumber).toBe('');
+ });
+ });
+
+ describe('selectedProviderNumber watcher', () => {
+ test('updates service location in store when provider is selected', async () => {
+ // Arrange
+ const providers = [
+ {
+ providerNumber: '12345',
+ companyName: 'Test Shop',
+ phoneNumber: '6145551234',
+ address: {
+ streetAddress: '123 Main St',
+ city: 'Columbus',
+ state: 'OH',
+ zipCode: '43215',
+ zipCodeCtu: '01234'
+ },
+ distanceInMiles: 5
+ }
+ ];
+ const { wrapper } = getMountedComponent({}, { dataLoaded: true, providers, radiusFilter: 25 });
+
+ // Act
+ wrapper.vm.selectedProviderNumber = '12345';
+ await nextTick();
+
+ // Assert
+ expect(wrapper.vm.mainStore.updateServiceLocation).toHaveBeenCalledWith(
+ expect.objectContaining({
+ provider: expect.objectContaining({
+ providerNumber: '12345',
+ companyName: 'Test Shop'
+ })
+ })
+ );
+ });
+
+ test('does not update store when provider not found', async () => {
+ // Arrange
+ const providers = [
+ { providerNumber: '12345', distanceInMiles: 5, companyName: 'Test', address: {} }
+ ];
+ const { wrapper } = getMountedComponent({}, { dataLoaded: true, providers, radiusFilter: 25 });
+ wrapper.vm.mainStore.updateServiceLocation.mockClear();
+
+ // Act
+ wrapper.vm.selectedProviderNumber = '99999';
+ await nextTick();
+
+ // Assert
+ expect(wrapper.vm.mainStore.updateServiceLocation).not.toHaveBeenCalled();
+ });
+
+ test('does not update store when dataLoaded is false', async () => {
+ // Arrange
+ const providers = [
+ { providerNumber: '12345', distanceInMiles: 5, companyName: 'Test', address: {} }
+ ];
+ const { wrapper } = getMountedComponent({}, { dataLoaded: false, providers, radiusFilter: 25 });
+ wrapper.vm.mainStore.updateServiceLocation.mockClear();
+
+ // Act
+ wrapper.vm.selectedProviderNumber = '12345';
+ await nextTick();
+
+ // Assert
+ expect(wrapper.vm.mainStore.updateServiceLocation).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('beforeRouteEnter', () => {
+ test('fetches CMS content and providers on route enter', async () => {
+ // Arrange
+ const mockProviders = [
+ { providerNumber: '123', distanceInMiles: 5 }
+ ];
+ const { wrapper } = getMountedComponent();
+ settleAllPromises.mockImplementation(() => ({
+ cmsContent: {},
+ providers: mockProviders
+ }));
+
+ const to = { query: { issPage: 'tpa-search' } };
+ const next = jest.fn((callback) => {
+ if (typeof callback === 'function') {
+ callback(wrapper.vm);
+ }
+ });
+
+ // Act
+ await tpaSearch.beforeRouteEnter(to, undefined, next);
+
+ // Assert
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('restores page data from store if available', async () => {
+ // Arrange
+ const pageData = {
+ tpaSearchValue: 'Test Shop',
+ radiusFilter: 50
+ };
+ const { wrapper } = getMountedComponent();
+ wrapper.vm.mainStore.pageData = jest.fn().mockReturnValue(pageData);
+ settleAllPromises.mockImplementation(() => ({
+ cmsContent: {},
+ providers: []
+ }));
+
+ const to = { query: { issPage: 'tpa-search' } };
+ const next = jest.fn((callback) => {
+ if (typeof callback === 'function') {
+ callback(wrapper.vm);
+ }
+ });
+
+ // Act
+ await tpaSearch.beforeRouteEnter(to, undefined, next);
+
+ // Assert
+ expect(next).toHaveBeenCalled();
+ });
+ });
+
+ describe('Data initialization', () => {
+ test('widget names are correctly defined', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+
+ // Assert
+ expect(wrapper.vm.widget.siteHeader).toBe('SiteHeaderWidget');
+ expect(wrapper.vm.widget.tpaSearchQuestion).toBe('TPASearchQuestion');
+ expect(wrapper.vm.widget.filterByQuestion).toBe('FilterByQuestion');
+ expect(wrapper.vm.widget.noNetworkShopsAlert).toBe('NoNetworkShopsAlertWidget');
+ expect(wrapper.vm.widget.siteFooter).toBe('SiteFooterWidget');
+ });
+
+ test('validation rules are correctly defined', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+
+ // Assert
+ expect(wrapper.vm.rules.tpaSearch).toBe(globalRules.TPA_SEARCH_FORMAT);
+ expect(wrapper.vm.rules.filter).toBe(globalRules.OPTION_REQUIRED);
+ expect(wrapper.vm.rules.provider).toBe(globalRules.OPTION_REQUIRED);
+ });
+
+ test('additionalButtonData is correctly initialized', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent();
+
+ // Assert
+ expect(wrapper.vm.additionalButtonData).toEqual({
+ displayAvailabilityIndicators: false
+ });
+ });
+ });
+
+ describe('dataLoaded flag', () => {
+ test('dataLoaded can be initialized as false', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, { dataLoaded: false });
+
+ // Assert - verify initial state
+ expect(wrapper.vm.dataLoaded).toBe(false);
+ });
+
+ test('dataLoaded can be initialized as true', () => {
+ // Arrange
+ const { wrapper } = getMountedComponent({}, { dataLoaded: true });
+
+ // Assert
+ expect(wrapper.vm.dataLoaded).toBe(true);
+ });
+
+ test('dataLoaded affects provider watcher behavior', async () => {
+ // Arrange - with dataLoaded false, provider watcher should not auto-select
+ const { wrapper } = getMountedComponent({}, { dataLoaded: false, selectedProviderNumber: '' });
+
+ // Act - set providers (watcher should not auto-select because dataLoaded is false)
+ wrapper.vm.providers = [{ providerNumber: '12345', distanceInMiles: 5, companyName: 'Test', address: {} }];
+ await nextTick();
+
+ // Assert - selectedProviderNumber should remain empty
+ expect(wrapper.vm.selectedProviderNumber).toBe('');
+ });
});
});
diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue
index 83d211c1..13e9a767 100644
--- a/src/layouts/tpa-search/tpa-search.vue
+++ b/src/layouts/tpa-search/tpa-search.vue
@@ -15,26 +15,26 @@
@@ -52,10 +52,10 @@
@invalidSubmit="onInvalidSubmit">
@@ -73,7 +73,7 @@
id="selectProviderQuestion"
v-model="selectedProviderNumber"
buttonTypeString="shopListButton"
- :buttonTypeObject="shopListButton"
+ :buttonTypeObject="tpaShopListButton"
class="radioQuestion"
:answers="providerButtonData"
groupName="chooseShop"
@@ -99,12 +99,23 @@
:text="shopNotListedModalLink"
@clickEvent="doNotSeeMyShopLinkClick" />
+
+
+
+
@@ -123,7 +134,7 @@ import textLink from '@/ux-components/text-link/text-link.vue';
import alert from '@/ux-components/alert/alert.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import googleMap from '@/iss-components/google-map/google-map.vue';
-import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue';
+import tpaShopListButton from '@/iss-components/tpa-shop-list-button/tpa-shop-list-button.vue';
import loader from '@/ux-components/loader/loader.vue';
// Supporting files
@@ -135,53 +146,9 @@ import widgetFields from '@/constants/cms-widget-fields.js';
import { shallowRef } from 'vue';
import { toTitleCase, toDisplayPhoneNumber } from '@/helpers/text-helper.js';
import bailoutMessage from '@/constants/bailoutMessage';
+import settleAllPromises from '@/helpers/layout-helper';
+import issPageValues from '@/router/router-constants/issPage-values';
-const radiusFilterPairs = [
- { radius: 15, filter: '15 miles' },
- { radius: 25, filter: '25 miles' },
- { radius: 50, filter: '50 miles' },
- { radius: 100, filter: '100 miles' }
-];
-
-function convertRadiusFilterToInteger(filter) {
- const pair = radiusFilterPairs.find((p) => p.filter === filter);
- return pair?.radius ?? 0;
-}
-
-async function getInitialSearchData() {
- const customerZipCode = useMainStore().order.customer.address.zipCode;
- const serviceLocationZipCode = useMainStore().order.serviceLocation.zipCode;
- const zipCode = serviceLocationZipCode ?? customerZipCode;
-
- const { searchFilter } = useMainStore().order.serviceLocation;
- let { providerNumber } = useMainStore().order.serviceLocation.provider;
-
- let providers = [];
- let radius = 0;
- if (searchFilter) {
- radius = convertRadiusFilterToInteger(searchFilter);
- const result = await useMainStore().getTpaProviders(zipCode, radius);
- providers = result?.data?.shopProviders ?? [];
-
- return { zipCode, filter: searchFilter, providers, providerNumber };
- }
-
- providerNumber = null;
- let pairIndex = 0;
- let filter = '';
- while (providers.length === 0 && pairIndex < radiusFilterPairs.length) {
- const pair = radiusFilterPairs[pairIndex];
- radius = pair.radius;
- filter = pair.filter;
- // eslint-disable-next-line no-await-in-loop
- const result = await useMainStore().getTpaProviders(zipCode, radius);
- providers = result?.data?.shopProviders ?? [];
-
- pairIndex += 1;
- }
-
- return { zipCode, filter, providers, providerNumber };
-}
export default {
name: 'tpa-search',
@@ -200,23 +167,40 @@ export default {
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
- const { zipCode, filter, providers, providerNumber } =
- await getInitialSearchData();
- const cmsContent = await fetchCmsContentForPage(to.query.issPage);
-
+ const zipCode = useMainStore().order.customer.address.zipCode;
+ const pageData = useMainStore().pageData(to.query.issPage);
+ const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
+ const providersPromise = useMainStore().getTpaAndSafeliteProviders(zipCode, pageData?.tpaSearchValue ?? '');
+ const promiseResultMap = [
+ {
+ resultKey: 'cmsContent',
+ promise: cmsContentPromise
+ },
+ {
+ resultKey: 'providers',
+ promise: providersPromise
+ }
+ ];
+ const resultMap = await settleAllPromises(promiseResultMap);
next(async (vm) => {
- vm.setCmsContent(cmsContent);
- vm.setInitialSearchData(zipCode, filter, providers, providerNumber);
+ vm.setCmsContent(resultMap.cmsContent);
+ vm.mapZipCode = zipCode;
+ vm.providers = resultMap.providers;
+ if (pageData) {
+ vm.tpaSearchValue = pageData?.tpaSearchValue ?? vm.mapZipCode;
+ vm.radiusFilter = pageData?.radiusFilter ?? 25;
+ }
});
},
data() {
return {
dataLoaded: false,
- zipCode: null,
+ pageData: null,
+ tpaSearchValue: null,
mapZipCode: null,
- filter: '',
+ radiusFilter: null,
providers: [],
- selectedProviderNumber: '',
+ selectedProviderNumber: useMainStore().order.serviceLocation.provider.providerNumber,
reloadingProviders: false,
additionalButtonData: {
displayAvailabilityIndicators: false
@@ -228,28 +212,28 @@ export default {
filterByQuestion: 'FilterByQuestion',
noNetworkShopsAlert: 'NoNetworkShopsAlertWidget',
shopNotListedLink: 'ShopNotListedLink',
- siteFooter: 'SiteFooterWidget'
+ siteFooter: 'SiteFooterWidget',
+ needHelpLink: 'NeedHelpLink'
},
rules: {
- zipCode: `${globalRules.ZIP_CODE_REQUIRED}|${globalRules.ZIP_CODE_SEARCH_FORMAT}`,
+ tpaSearch: globalRules.TPA_SEARCH_FORMAT,
filter: globalRules.OPTION_REQUIRED, // TODO do we even need this?
provider: globalRules.OPTION_REQUIRED
},
- shopListButton: shallowRef(shopListButton)
+ tpaShopListButton: shallowRef(tpaShopListButton)
};
},
computed: {
- filterOptions() {
- const filterByAnswers =
- this.getCmsContent(
+ radiusFilterOptions() {
+ const radiusFilterOptions = this.getCmsContent(
this.widget.filterByQuestion,
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
) ?? [];
- const filterByAnswersObj = {};
- [...filterByAnswers].forEach((answer) => {
- filterByAnswersObj[answer.Name] = answer.Name;
- });
- return filterByAnswersObj;
+ const options = {};
+ for (const option of radiusFilterOptions) {
+ options[option.Name] = option.Text;
+ }
+ return options;
},
tpaSearchQuestionLabel() {
return this.getCmsContent(
@@ -257,6 +241,9 @@ export default {
widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT
);
},
+ needHelpLinkText() {
+ return this.getCmsContent(this.widget.needHelpLink, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
+ },
searchInstructionsText() {
return this.getCmsContent(
this.widget.searchInstructions,
@@ -269,25 +256,25 @@ export default {
widgetFields.TEXT_BLOCK_WIDGET.TEXT
);
},
- radiusInMiles() {
- return convertRadiusFilterToInteger(this.filter);
- },
noNetworkShopsAlertHeaderText() {
return this.getCmsContent(
this.widget.noNetworkShopsAlert,
widgetFields.ALERT_WIDGET.HEADLINE_TEXT
- )?.replaceAll('{custom:radiusInMiles}', this.radiusInMiles);
+ )?.replaceAll('{custom:radiusInMiles}', this.radiusFilter + " miles");
+ },
+ radiusFilteredAndCappedProviders() {
+ return this.providers.filter((provider) => provider.distanceInMiles <= this.radiusFilter).slice(0, 5);
},
providerAddresses() {
- return this.providers?.map((provider) => ({
- title: provider.companyName,
+ return this.radiusFilteredAndCappedProviders?.map((provider) => ({
+ title: provider.companyName.toLowerCase(),
fullAddress: this.getFullProviderAddress(provider),
addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)]
})) ?? [];
},
providerButtonData() {
return (
- this.providers?.map((provider) =>
+ this.radiusFilteredAndCappedProviders?.map((provider) =>
this.getShopButtonDataFromProvider(provider)) ?? []
);
},
@@ -298,14 +285,6 @@ export default {
}
},
watch: {
- async filter() {
- if (this.dataLoaded) {
- await this.getProviderButtonData().then((providers) => {
- this.providers = providers;
- });
- this.mapZipCode = this.zipCode;
- }
- },
providers(newProviders) {
if (this.dataLoaded) {
this.selectedProviderNumber =
@@ -318,7 +297,6 @@ export default {
const provider = this.providers?.find((p) => p.providerNumber === newNumber);
if (provider && this.dataLoaded) {
useMainStore().updateServiceLocation({
- searchFilter: this.filter,
zipCode: this.zipCode,
provider: {
providerNumber: provider?.providerNumber,
@@ -342,13 +320,6 @@ export default {
}
},
methods: {
- setInitialSearchData(zipCode, filter, providers, providerNumber) {
- this.zipCode = zipCode;
- this.mapZipCode = zipCode;
- this.filter = filter;
- this.providers = providers;
- this.selectedProviderNumber = providerNumber;
- },
getFullProviderAddress(provider) {
const addressLine1 = this.getProviderAddress(provider);
const addressLine2 = this.getProviderCityZipState(provider);
@@ -379,16 +350,16 @@ export default {
}
return addressLine2;
},
- async getProviderButtonData() {
+ async getProviderButtonData(shopName = "") {
this.reloadingProviders = true;
- const getTpaProvidersResult = await useMainStore().getTpaProviders(
- this.zipCode,
- this.radiusInMiles
+ const getTpaProvidersResult = await useMainStore().getTpaAndSafeliteProviders(
+ this.mapZipCode,
+ shopName
);
this.reloadingProviders = false;
- return getTpaProvidersResult?.data?.shopProviders ?? [];
+ return getTpaProvidersResult?.data ?? [];
},
- doNotSeeMyShopLinkClick() {
+ needHelpLinkClick() {
this.mainStore.setBailout(bailoutMessage.RequestCallback());
this.$router.navigate(
this.navigationScenarios.CLICKED_NEED_HELP,
@@ -396,8 +367,12 @@ export default {
);
},
async searchClick() {
- this.providers = await this.getProviderButtonData();
- this.mapZipCode = this.zipCode;
+ if (isNaN(this.tpaSearchValue)) {
+ this.providers = await this.getProviderButtonData(this.tpaSearchValue);
+ } else {
+ this.mapZipCode = this.tpaSearchValue;
+ this.providers = await this.getProviderButtonData();
+ }
},
forwardButtonAction() {
if (this.selectedProviderIsSafeliteShop) {
@@ -407,16 +382,12 @@ export default {
? this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP
: this.navigationScenarios
.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP;
+ // Do not save the zip code as the tpa search value, prevents an outdated zipcode from being used
+ // as the default search value if customer goes back and changes zip earlier in the flow
+ const tpaSearchValueToSave = this.tpaSearchValue === this.mapZipCode ? '' : this.tpaSearchValue;
+ this.savePageDataToStore(issPageValues.TPA_SEARCH, {tpaSearchValue: tpaSearchValueToSave, radiusFilter: this.radiusFilter});
this.$router.navigate(scenario, this.$route);
},
- getCustomValueFromString(str) {
- switch (str) {
- case 'radiusInMiles':
- return this.radiusInMiles;
- default:
- return null;
- }
- },
getShopButtonDataFromProvider(provider) {
const cellNumber = toDisplayPhoneNumber(provider?.phoneNumber);
const distance =
@@ -426,7 +397,7 @@ export default {
: null;
return {
- buttonLabel: provider?.companyName ?? '',
+ buttonLabel: provider?.companyName.toLowerCase() ?? '',
buttonLabelSubCopy: distance === null ? '' : `${distance} mi`,
buttonBodyCopy: `${this.getFullProviderAddress(provider)}
${
cellNumber ?? ''
@@ -442,4 +413,30 @@ export default {
.darker-gray {
color: map-get($colors, 'darker-gray');
}
+
+#tpaSearchQuestionLabel {
+ margin-bottom: .625rem;
+}
+
+#map {
+ height: 27.1875rem;
+}
+
+#providerSelectionForm {
+ #alertNoNetworkProviders {
+ :deep(.alert) {
+ margin-bottom: 0px;
+ }
+ }
+}
+
+hr {
+ margin: 1.375rem 0;
+}
+
+.need-help-link-container {
+ margin-top:1.875rem;
+ margin-bottom: 2.1875rem;
+}
+
diff --git a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.spec.js b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.spec.js
index 41a935b8..fd7afa32 100644
--- a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.spec.js
+++ b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.spec.js
@@ -41,13 +41,14 @@ function setupMocks({ glassNameProp, glassLocationProp, colorAnswersProp, modelV
};
- const wrapper = shallowMount(glassPartQuestion, mountOptions);
-
// Mock store
const partsOrQuestions = pageData ?? { partsOrQuestions: [{ glassName: 'Stationary', glassLocation: 'Rear', parts: [] }] };
useMainStore().pageData = jest.fn();
useMainStore().pageData.mockReturnValue(partsOrQuestions);
document.querySelector = jest.fn().mockReturnValue({ clicked: false, click: jest.fn() });
+
+ const wrapper = shallowMount(glassPartQuestion, mountOptions);
+
return { wrapper };
}
@@ -62,36 +63,23 @@ describe('glass-part-question.vue', () => {
window.console.log(wrapper.vm.featureListData['Green Tint'][0].Text);
// Assert
expect(Object.keys(wrapper.vm.featureListData).length).toBe(2);
- expect(wrapper.vm.featureListData['Green Tint'][0].Text).toBe('heated glass, solar, 1 hole');
+ expect(wrapper.vm.featureListData['Green Tint'][0].Text).toBe('Heated glass, Solar, 1 Hole');
expect(wrapper.vm.featureListData['Green Tint'][0].Name).toBe('DB12209GTYN');
- expect(wrapper.vm.featureListData['Gray Tint Privacy'][0].Text).toBe('heated glass, solar, 1 hole');
+ expect(wrapper.vm.featureListData['Gray Tint Privacy'][0].Text).toBe('Heated glass, Solar, 1 Hole');
expect(wrapper.vm.featureListData['Gray Tint Privacy'][0].Name).toBe('DB12209YPYN');
});
- test('Tint mapper, should get tint image by glassLocation and tintColor', async () => {
+ test('Tint mapper, should get return css class based on tint color', async () => {
// Arrange
const { wrapper } = setupMocks(featureListData);
// Act
await wrapper.vm.$nextTick();
- const tintSourceImage = wrapper.vm.getTintSourceImage('Rear', 'Green Tint');
+ const tintClass = wrapper.vm.convertTintToCSSClass('Green Tint');
// Assert
- expect(tintSourceImage).toBe('Glass-NoShade-GreenTint.svg');
- });
-
- test('Tint mapper, should return empty string if no tint map found', async () => {
- // Arrange
-
- const { wrapper } = setupMocks(featureListData);
-
- // Act
- await wrapper.vm.$nextTick();
- const tintSourceImage = wrapper.vm.getTintSourceImage('Rear', 'Crazy Rainbow Tint');
-
- // Assert
- expect(tintSourceImage).toBe('');
+ expect(tintClass).toBe('green-tint');
});
test('Should emit updateModelValue, and have correct attributes', async () => {
@@ -122,7 +110,7 @@ describe('glass-part-question.vue', () => {
{ partNumber: 'DB12209GTYN', color: 'Green Tint' }
]);
expect(listCard.attributes('groupname')).toBe('Rear-Stationary');
- expect(listCard.attributes('validationrules')).toBe('Rear-Stationary-tint-required');
+ expect(listCard.attributes('validationrules')).toBe('Rear-Stationary-part-required');
});
test('default is selected if only one option', async () => {
@@ -136,58 +124,42 @@ describe('glass-part-question.vue', () => {
}
]
};
+ const updateSpy = jest.spyOn(glassPartQuestion.methods, 'updateSelectedPartNumber');
const { wrapper } = setupMocks(featureListData);
-
- // Act
- await wrapper.vm.$nextTick();
- await wrapper.setData({ selectedTint: 'Green Tint' });
- // take emitted value, pass down as modelValue
- // yes, yes, it's not ideal
- await wrapper.setProps({ modelValue: wrapper.emitted()['update:modelValue'][0][0] });
await wrapper.vm.$nextTick();
// Assert
- expect(wrapper.vm.selectedPartNumber).toBe('DB12209GTYN');
+ expect(updateSpy).toHaveBeenCalledWith('DB12209GTYN');
});
- const partsForSelectedTintTestCases = [
+ const partsForLocationTestCases = [
[
'Rear',
'Stationary',
- 'Green Tint',
[
{ partNumber: 'Glass1', color: 'Green Tint' },
+ { partNumber: 'Glass2', color: 'Blue Tint' },
{ partNumber: 'Glass3', color: 'Green Tint' },
{ partNumber: 'Glass4', color: 'Green Tint' },
- { partNumber: 'Glass6', color: 'Green Tint' }
+ { partNumber: 'Glass5', color: 'Blue Tint' },
+ { partNumber: 'Glass6', color: 'Green Tint' },
+ { partNumber: 'Glass7', color: 'Red Tint' }
]
],
- [
- 'Rear',
- 'Stationary',
- 'Blue Tint',
- [
- { partNumber: 'Glass2', color: 'Blue Tint' },
- { partNumber: 'Glass5', color: 'Blue Tint' }
- ]
- ],
- ['Rear', 'Stationary', 'Red Tint', [{ partNumber: 'Glass7', color: 'Red Tint' }]],
[
'Windshield',
'Single',
- 'Green Tint',
[
{ partNumber: 'Windshield1', color: 'Green Tint' },
{ partNumber: 'Windshield2', color: 'Green Tint' }
]
],
- ['Windshield', 'Single', 'Blue Tint', []],
- ['Driver', 'Quarter', 'Green Tint', []]
+ ['Driver', 'Quarter', []]
];
- test.each(partsForSelectedTintTestCases)(
- 'partsForSelectedTint returns correct parts',
- async (glassLocation, glassName, selectedTint, expectedResults) => {
+ test.each(partsForLocationTestCases)(
+ 'partsForLocation returns correct parts',
+ async (glassLocation, glassName, expectedResults) => {
// Arrange
const pageData = { partsOrQuestions: [
{
@@ -219,11 +191,8 @@ describe('glass-part-question.vue', () => {
pageData
});
- // Act
- await wrapper.setData({ selectedTint });
-
// Assert
- expect(expectedResults).toEqual(wrapper.vm.partsForSelectedTint);
+ expect(wrapper.vm.partsForLocation).toEqual(expectedResults);
}
);
});
diff --git a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue
index 0fe2bec3..1d5c2115 100644
--- a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue
+++ b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue
@@ -1,44 +1,27 @@
-
- {{ colorQuestionText }}
-
+
+ {{ partType }}
+
-
-
-
+
+
+ {{ `${partType} - ${tint}` }}
+
-
+
+
diff --git a/src/layouts/vehicle-parts/vehicle-parts.vue b/src/layouts/vehicle-parts/vehicle-parts.vue
index 5ceefd0d..4e75e55f 100644
--- a/src/layouts/vehicle-parts/vehicle-parts.vue
+++ b/src/layouts/vehicle-parts/vehicle-parts.vue
@@ -11,34 +11,36 @@
@@ -51,7 +53,7 @@ import glassPartQuestion from '@/layouts/vehicle-parts/glass-part-question/glass
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
-import alert from '@/ux-components/alert/alert.vue';
+import textLink from '@/ux-components/text-link/text-link.vue';
// Supporting Files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
@@ -61,6 +63,7 @@ import { Form } from 'vee-validate';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';
+import widgetFields from '@/constants/cms-widget-fields';
export default {
name: 'vehicle-parts',
@@ -71,7 +74,7 @@ export default {
siteHeader,
siteSubHeader,
siteFooter,
- alert
+ textLink
},
mixins: [BaseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
@@ -88,17 +91,6 @@ export default {
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
-
- // Glass Part Question dynamic component
- Object.keys(vm.$refs)
- .filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
- .forEach((c) =>
- vm.$refs[c][0].initializeComponent({
- ColorQuestionWidget:
- resultMap.cmsContent.ColorQuestionWidget,
- FeatureQuestionWidget:
- resultMap.cmsContent.FeatureQuestionWidget
- }));
});
},
data() {
@@ -156,6 +148,9 @@ export default {
RefPrefix() {
return 'partQuestion';
+ },
+ needHelpLinkText() {
+ return this.getCmsContent('NeedHelpLinkWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
}
},
mounted() {
@@ -220,23 +215,47 @@ export default {
});
});
});
+ },
+ requestCallbackBailout() {
+ this.mainStore.setBailout(bailoutMessage.RequestCallback());
+ this.$router.navigate(navigationScenarios.CLICKED_NEED_HELP_WITH_BAILOUT, this.$route);
}
}
};
diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js
index 2698360f..c3075d3f 100644
--- a/src/router/router-constants/routing-table.js
+++ b/src/router/router-constants/routing-table.js
@@ -248,6 +248,10 @@ const routingTable = () => [
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
destinationIssPageValue: issPageValues.COVERAGE_STATEMENT
+ },
+ {
+ scenario: navigationScenarios.CLICKED_NEED_HELP_WITH_BAILOUT,
+ destinationIssPageValue: issPageValues.BAILOUT_PAGE
}
]
},
diff --git a/src/store/index.js b/src/store/index.js
index 6759f16f..3b86e15a 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -142,7 +142,7 @@ export const getDefaultState = () => ({
appointmentType: null,
isVehicleProtected: null,
IsSafeliteProvider: null,
- searchFilter: null,
+ tpaSearchRadius: null,
provider: {
providerNumber: null,
address: {
@@ -1038,8 +1038,24 @@ export const useMainStore = defineStore({
return this.getProviders(zipCode, radius, true)
},
- getTpaProviders(zipCode, radius) {
- return this.getProviders(zipCode, radius, false)
+ getTpaAndSafeliteProviders(zipCode, provderNameSearchString = "") {
+ const { parentAccountNumber } = this.order;
+ const carId = this.order.vehicle.carId;
+ const damageType = this.damage.isRepair ? 'Repair' : 'Install';
+
+ const parts = getLineItemsFlattened(this.order.lineItems.glassParts);
+ const partNumbers = parts.map((part) => part.partNumber).join(',');
+
+ let url = `${endpoints.GetTpaAndSafeliteProviders.url}/${zipCode}?accountNumber=${parentAccountNumber}&carId=${carId}&damageType=${damageType}&partNumbers=${partNumbers}`;
+ if (provderNameSearchString) {
+ url += `&providerNameSearchString=${provderNameSearchString}`;
+ }
+ return new Promise((resolve, reject) => {
+ globalMethods.callHttpClient({
+ method: endpoints.GetTpaAndSafeliteProviders.method,
+ endpoint: url
+ }).then((response) => resolve(response), (error) => reject(error));
+ });
},
getProviders(zipcode, radius, safeliteOnly) {
@@ -1844,7 +1860,7 @@ export const useMainStore = defineStore({
phoneNumber: serviceLocationInfo.provider?.phoneNumber
};
}
- this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter;
+ this.order.serviceLocation.tpaSearchRadius = serviceLocationInfo.tpaSearchRadius;
},
resetState() {
diff --git a/src/store/store.spec.js b/src/store/store.spec.js
index 4f4173d8..f92fc95c 100644
--- a/src/store/store.spec.js
+++ b/src/store/store.spec.js
@@ -1966,53 +1966,65 @@ describe('Store', () => {
});
});
- describe('getTpaProviders method', () => {
+ describe('getTpaAndSafeliteProviders method', () => {
describe('successful method call', () => {
- it.each([[true, 'Repair'], [false, 'Replace']])(
- 'calls getProviders api endpoint',
+ it.each([[true, 'Repair'], [false, 'Install']])(
+ 'calls getProviders api endpoint with damageType %s',
async (isRepair, damageType) => {
// Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({}));
const carId = getRandomString(10, 14);
const parentAccountNumber = getRandomString(6, 6);
+ const partNumber = getRandomString(6, 6);
store.order.parentAccountNumber = parentAccountNumber;
store.order.damage.isRepair = isRepair;
store.order.vehicle.carId = carId;
- const zipCode = getRandomString(6, 6);
- const radius = getRandomInt(5, 100);
- const isBigTruck = false;
- store.order.vehicle.isBigTruck = isBigTruck;
- const expectedEndpoint = endpoints.GetProviders.url(
- zipCode,
- damageType,
- radius,
- parentAccountNumber,
- 'false',
- carId,
- null,
- isBigTruck
- );
+ store.order.lineItems.glassParts = [{ partNumber }];
+ const zipCode = getRandomString(5, 5);
+
+ const expectedEndpoint = `${endpoints.GetTpaAndSafeliteProviders.url}/${zipCode}?accountNumber=${parentAccountNumber}&carId=${carId}&damageType=${damageType}&partNumbers=${partNumber}`;
// Act
- await store.getTpaProviders(zipCode, radius);
+ await store.getTpaAndSafeliteProviders(zipCode);
// Asserts
expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining({
- method: endpoints.GetProviders.method,
+ method: endpoints.GetTpaAndSafeliteProviders.method,
endpoint: expectedEndpoint
}));
}
);
+ it('includes providerNameSearchString in endpoint when provided', async () => {
+ // Arrange
+ globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({}));
+
+ const carId = getRandomString(10, 14);
+ const parentAccountNumber = getRandomString(6, 6);
+ const partNumber = getRandomString(6, 6);
+ store.order.parentAccountNumber = parentAccountNumber;
+ store.order.damage.isRepair = true;
+ store.order.vehicle.carId = carId;
+ store.order.lineItems.glassParts = [{ partNumber }];
+ const zipCode = getRandomString(5, 5);
+ const providerNameSearchString = 'Test Shop';
+
+ // Act
+ await store.getTpaAndSafeliteProviders(zipCode, providerNameSearchString);
+
+ // Asserts
+ expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining({
+ endpoint: expect.stringContaining(`&providerNameSearchString=${providerNameSearchString}`)
+ }));
+ });
it('Returns expected response object', async () => {
// Arrange
const response = { ReferralNumber: getRandomString(6, 6) };
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
- const zipCode = getRandomString(6, 6);
- const radius = getRandomInt(5, 100);
+ const zipCode = getRandomString(5, 5);
// Act
- const result = store.getTpaProviders(zipCode, radius);
+ const result = store.getTpaAndSafeliteProviders(zipCode);
// Asserts
await expect(result).resolves.toBe(response);
@@ -2020,11 +2032,10 @@ describe('Store', () => {
it('null response by api => no exceptions thrown', async () => {
// Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(null));
- const zipCode = getRandomString(6, 6);
- const radius = getRandomInt(5, 100);
+ const zipCode = getRandomString(5, 5);
// Act
- await store.getTpaProviders(zipCode, radius);
+ await store.getTpaAndSafeliteProviders(zipCode);
});
it('no providers returned by api => promise resolves to empty list', async () => {
// Arrange
@@ -2034,11 +2045,10 @@ describe('Store', () => {
}
};
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(responseNoProviders));
- const zipCode = getRandomString(6, 6);
- const radius = getRandomInt(5, 100);
+ const zipCode = getRandomString(5, 5);
// Act
- const result = await store.getTpaProviders(zipCode, radius);
+ const result = await store.getTpaAndSafeliteProviders(zipCode);
// Asserts
expect(result.data.shopProviders).toHaveLength(0);
@@ -2060,7 +2070,7 @@ describe('Store', () => {
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(responseProviders));
// Act
- const result = await store.getTpaProviders();
+ const result = await store.getTpaAndSafeliteProviders();
// Asserts
expect(result.data.shopProviders).toHaveLength(2);