diff --git a/src/iss-components/google-map/__snapshots__/google-map.spec.js.snap b/src/iss-components/google-map/__snapshots__/google-map.spec.js.snap index efab5bbf..74a1d74d 100644 --- a/src/iss-components/google-map/__snapshots__/google-map.spec.js.snap +++ b/src/iss-components/google-map/__snapshots__/google-map.spec.js.snap @@ -3,6 +3,22 @@ exports[`Google Map should render expected initial data 1`] = ` Object { "country": "USA", - "geocoder": null, + "geocoder": Object { + "geocode": [MockFunction] { + "calls": Array [ + Array [ + Object { + "address": " USA", + }, + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + }, } `; diff --git a/src/iss-components/google-map/google-map.spec.js b/src/iss-components/google-map/google-map.spec.js index 2c4ad709..b26d36a2 100644 --- a/src/iss-components/google-map/google-map.spec.js +++ b/src/iss-components/google-map/google-map.spec.js @@ -1,6 +1,11 @@ import { shallowMount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; import googleMap from '@/iss-components/google-map/google-map.vue'; +// Supporting Files +import { getMountOptions } from '@/helpers/unit-test-helper.js'; +import { useMainStore } from '@/store'; + const mockFitBounds = jest.fn(); const mockMapInstance = { fitBounds: mockFitBounds @@ -8,10 +13,13 @@ const mockMapInstance = { const mockMap = jest.fn(() => mockMapInstance); const mockGeocode = jest.fn(); -const mockGeocoderInstance = { +const mockGeocoderInstance1 = { geocode: mockGeocode }; -const mockGeocoder = jest.fn(() => (mockGeocoderInstance)); +const mockGeocoderInstance2 = { + geocode: mockGeocode +}; +const mockGeocoder = jest.fn(() => (mockGeocoderInstance1)); const mockAdvancedMarkerElement = jest.fn(); @@ -47,20 +55,52 @@ beforeEach(() => { setupGoogleMock(); }); +function getMountedComponent(mainInitialState = {}, initialData = {}, propsData = {}) { + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + + const testingPinia = createTestingPinia({ + initialState: { + main: mainInitialState + } + }); + useMainStore(testingPinia); + + mountOptions.global.plugins = [testingPinia]; + mountOptions.data = () => (initialData); + mountOptions.propsData = propsData; + + const wrapper = shallowMount(googleMap, mountOptions); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {}); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} + +async function awaitingSetupTicks(wrapper) { + for (let i = 0; i < 11; i++) { + // eslint-disable-next-line no-await-in-loop + await wrapper.vm.$nextTick(); + } +} + describe('Google Map', () => { describe('should render', () => { test('expected initial data', async () => { // Arrange const wrapper = shallowMount(googleMap, {}); - await wrapper.vm.$nextTick(); + await awaitingSetupTicks(wrapper); // Assert expect(wrapper.vm.$data).toMatchSnapshot(); }); - test('map', () => { + test('map', async () => { // Arrange const mapReference = '#map'; const wrapper = shallowMount(googleMap, {}); + await awaitingSetupTicks(wrapper); // Act const map = wrapper.find(mapReference); @@ -78,8 +118,8 @@ describe('Google Map', () => { 'given that zipcode set to "%p", computed zipCodeAddress should return "%p"', async (zipCode, expected) => { // Arrange - const wrapper = shallowMount(googleMap, {}); - await wrapper.setData({ zipCode }); + const { wrapper } = getMountedComponent({}, {}, { zipCode }); + await awaitingSetupTicks(wrapper); // Act const result = wrapper.vm.zipCodeAddress; @@ -88,11 +128,78 @@ describe('Google Map', () => { expect(result).toBe(expected); } ); + test('before mount addresses creates map with expected markers', async () => { + // Arrange + const mockGetCenter = jest.fn(); + const mockNorthEast = jest.fn(); + const mockSouthWest = jest.fn(); + const zipCodeGeocodeResult = { + results: [ + { + geometry: { + bounds: + { + getCenter: mockGetCenter, + getNorthEast: mockNorthEast, + getSouthWest: mockSouthWest + } + } + } + ] + }; + + const zipCode = '00882'; + const [address1, address2, position1, position2] = ['a1', 'a2', 'p1', 'p2']; + const addresses = [address1, address2]; + mockGeocode.mockImplementation((obj) => { + let result = {}; + if (obj.address.includes(zipCode)) { + result = zipCodeGeocodeResult; + } else if (obj.address === address1) { + result = { + results: [ + { geometry: { location: position1 } } + ] + }; + } else if (obj.address === address2) { + result = { + results: [ + { geometry: { location: position2 } } + ] + }; + } + return Promise.resolve(result); + }); + + const propsData = { addresses, zipCode }; + const { wrapper } = getMountedComponent({}, {}, propsData); + await awaitingSetupTicks(wrapper); + + // Assert + expect(mockMap).toBeCalledTimes(1); + expect(mockAdvancedMarkerElement).toBeCalledTimes(2); + expect(mockAdvancedMarkerElement).toBeCalledWith(expect.objectContaining({ + map: expect.anything(), + position: position1 + })); + expect(mockAdvancedMarkerElement).toBeCalledWith(expect.objectContaining({ + map: expect.anything(), + position: position2 + })); + expect(mockGeocoder).toBeCalledTimes(1); + + expect(mockExtend).toBeCalledTimes(4); + expect(mockFitBounds).toBeCalledTimes(1); + + expect(mockGetCenter).toBeCalledTimes(1); + expect(mockNorthEast).toBeCalledTimes(1); + expect(mockSouthWest).toBeCalledTimes(1); + }); test('watch addresses creates map with expected markers', async () => { // Arrange - const wrapper = shallowMount(googleMap, {}); const zipCode = '00882'; - await wrapper.setData({ zipCode }); + const { wrapper } = getMountedComponent({}, { zipCode }); + await awaitingSetupTicks(wrapper); const mockGetCenter = jest.fn(); const mockNorthEast = jest.fn(); @@ -135,14 +242,10 @@ describe('Google Map', () => { // Act await wrapper.vm.$options.watch.addresses.call(wrapper.vm, newAddresses); - - for (let i = 0; i < 11; i++) { - // eslint-disable-next-line no-await-in-loop - await wrapper.vm.$nextTick(); - } + await awaitingSetupTicks(wrapper); // Assert - expect(mockMap).toBeCalledTimes(1); + expect(mockMap).toBeCalledTimes(2); expect(mockAdvancedMarkerElement).toBeCalledTimes(2); expect(mockAdvancedMarkerElement).toBeCalledWith(expect.objectContaining({ map: expect.anything(), @@ -154,8 +257,8 @@ describe('Google Map', () => { })); expect(mockGeocoder).toBeCalledTimes(1); - expect(mockExtend).toBeCalledTimes(4); - expect(mockFitBounds).toBeCalledTimes(1); + expect(mockExtend).toBeCalledTimes(6); + expect(mockFitBounds).toBeCalledTimes(2); expect(mockGetCenter).toBeCalledTimes(1); expect(mockNorthEast).toBeCalledTimes(1); @@ -165,6 +268,7 @@ describe('Google Map', () => { test('getMap calls map constructor with expected parameters', async () => { // Arrange const wrapper = shallowMount(googleMap, {}); + await awaitingSetupTicks(wrapper); const center = { lat: 90, lng: -5 }; // Act @@ -185,32 +289,35 @@ describe('Google Map', () => { [['loc1', 'loc1', 'loc1', 'loc1'], 4] ])( 'given parameter %p, getBounds calls extend %p time(s)', - (locations, numberOfExtendCalls) => { + async (locations, numberOfExtendCallsPostMount) => { // Arrange const wrapper = shallowMount(googleMap, {}); + await awaitingSetupTicks(wrapper); + const numberOfExtendCallsDuringMount = 2; // Act const result = wrapper.vm.getBounds(locations); // Assert - expect(mockExtend).toHaveBeenCalledTimes(numberOfExtendCalls); + expect(mockExtend).toHaveBeenCalledTimes( + numberOfExtendCallsDuringMount + numberOfExtendCallsPostMount); expect(result).toBe(mockLatLngBound); } ); test.each([ - [1, null, mockGeocoderInstance], - [1, undefined, mockGeocoderInstance], - [0, {}, {}], - [0, { value: 'any value' }, { value: 'any value' }] + [1, null, mockGeocoderInstance1], + [1, undefined, mockGeocoderInstance1], + [0, mockGeocoderInstance2, mockGeocoderInstance2] ])( 'setGeocoder calls Geocoder constructor %p time(s) when original geocoder %p and geocoder set to %p', async (numberOfCalls, originalGeocoder, newGeocoder) => { // Arrange - const wrapper = shallowMount(googleMap, {}); - await wrapper.setData({ geocoder: originalGeocoder }); + const { wrapper } = getMountedComponent({}, { geocoder: originalGeocoder }, {}); + await awaitingSetupTicks(wrapper); // Act await wrapper.vm.setGeocoder(); + await wrapper.vm.$nextTick(); // Assert expect(mockGeocoder).toHaveBeenCalledTimes(numberOfCalls); @@ -228,6 +335,7 @@ describe('Google Map', () => { async (positions, numberOfCalls) => { // Arrange const wrapper = shallowMount(googleMap, {}); + await awaitingSetupTicks(wrapper); const map = jest.fn(); // Act @@ -246,21 +354,26 @@ describe('Google Map', () => { [['a1', 'a2', 'a3'], 3] ])( 'given address(es) %p calls geocode %p times', - async (addresses, numberOfCalls) => { + async (addresses, numberOfCallsPostMount) => { // Arrange const wrapper = shallowMount(googleMap, {}); + await awaitingSetupTicks(wrapper); + const numberOfCallsFromMount = 1; + expect(mockGeocode).toHaveBeenCalledTimes(numberOfCallsFromMount); // Act await wrapper.vm.getLocationsFromAddresses(addresses); + await wrapper.vm.$nextTick(); // Assert - expect(mockGeocode).toHaveBeenCalledTimes(numberOfCalls); + expect(mockGeocode).toHaveBeenCalledTimes(numberOfCallsFromMount + numberOfCallsPostMount); expect(wrapper.vm.geocoder).not.toBeNull(); } ); test('only returns geocode results that are not null', async () => { // Arrange const wrapper = shallowMount(googleMap, {}); + await awaitingSetupTicks(wrapper); const addresses = ['a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8']; mockGeocode.mockImplementationOnce(() => null) .mockImplementationOnce(() => ({ results: null })) @@ -300,6 +413,7 @@ describe('Google Map', () => { test('returns expected when geocode returns valid result', async () => { // Arrange const wrapper = shallowMount(googleMap, {}); + await awaitingSetupTicks(wrapper); const address = 'random address'; const expectedResult = 'bounds returned'; const geocodeResult = { @@ -321,6 +435,7 @@ describe('Google Map', () => { test('returns null when geocode returns invalid result', async () => { // Arrange const wrapper = shallowMount(googleMap, {}); + await awaitingSetupTicks(wrapper); const address = 'random address'; mockGeocode.mockImplementationOnce(() => Promise.resolve({})); @@ -335,9 +450,6 @@ describe('Google Map', () => { describe('createMapWithMarkersForAddresses', () => { test('calls expected when addresses provided', async () => { // Arrange - const wrapper = shallowMount(googleMap, {}); - const zipCode = '00882'; - await wrapper.setData({ zipCode }); const mockGetCenter = jest.fn(); const mockNorthEast = jest.fn(); const mockSouthWest = jest.fn(); @@ -360,34 +472,35 @@ describe('Google Map', () => { { geometry: { location: 'valid location' } } ] }; + const zipCode = '00882'; mockGeocode.mockImplementation((obj) => Promise.resolve(obj.address.includes(zipCode) ? zipCodeGeocodeResult : shopGeocodeResult)); const addresses = ['a1', 'a2']; + const { wrapper } = getMountedComponent({}, { zipCode }); + await awaitingSetupTicks(wrapper); // Act await wrapper.vm.createMapWithMarkersForAddresses(addresses); + await awaitingSetupTicks(wrapper); // Assert - expect(mockMap).toBeCalledTimes(1); + expect(mockMap).toBeCalledTimes(2); expect(mockAdvancedMarkerElement).toBeCalledTimes(2); expect(mockGeocoder).toBeCalledTimes(1); - expect(mockExtend).toBeCalledTimes(4); - expect(mockFitBounds).toBeCalledTimes(1); + expect(mockExtend).toBeCalledTimes(6); + expect(mockFitBounds).toBeCalledTimes(2); - expect(mockGetCenter).toBeCalledTimes(1); - expect(mockNorthEast).toBeCalledTimes(1); - expect(mockSouthWest).toBeCalledTimes(1); + expect(mockGetCenter).toBeCalledTimes(2); + expect(mockNorthEast).toBeCalledTimes(2); + expect(mockSouthWest).toBeCalledTimes(2); }); test.each([null, undefined, []])( 'calls expected when addresses argument is "%p"', async (addresses) => { // Arrange - const wrapper = shallowMount(googleMap, {}); - const zipCode = '00882'; - await wrapper.setData({ zipCode }); const mockGetCenter = jest.fn(); const mockNorthEast = jest.fn(); const mockSouthWest = jest.fn(); @@ -406,21 +519,25 @@ describe('Google Map', () => { ] }; mockGeocode.mockImplementation(() => Promise.resolve(zipCodeGeocodeResult)); + const zipCode = '00882'; + const { wrapper } = getMountedComponent({}, { zipCode }); + await awaitingSetupTicks(wrapper); // Act await wrapper.vm.createMapWithMarkersForAddresses(addresses); + await awaitingSetupTicks(wrapper); // Assert - expect(mockMap).toBeCalledTimes(1); + expect(mockMap).toBeCalledTimes(2); expect(mockAdvancedMarkerElement).toBeCalledTimes(0); expect(mockGeocoder).toBeCalledTimes(1); - expect(mockExtend).toBeCalledTimes(2); - expect(mockFitBounds).toBeCalledTimes(1); + expect(mockExtend).toBeCalledTimes(4); + expect(mockFitBounds).toBeCalledTimes(2); - expect(mockGetCenter).toBeCalledTimes(1); - expect(mockNorthEast).toBeCalledTimes(1); - expect(mockSouthWest).toBeCalledTimes(1); + expect(mockGetCenter).toBeCalledTimes(2); + expect(mockNorthEast).toBeCalledTimes(2); + expect(mockSouthWest).toBeCalledTimes(2); } ); }); diff --git a/src/iss-components/google-map/google-map.vue b/src/iss-components/google-map/google-map.vue index fa5a57d8..0c901dec 100644 --- a/src/iss-components/google-map/google-map.vue +++ b/src/iss-components/google-map/google-map.vue @@ -27,6 +27,9 @@ export default { this.createMapWithMarkersForAddresses(newAddresses); } }, + beforeMount() { + this.createMapWithMarkersForAddresses(this.addresses); + }, methods: { async getMap(center) { const { Map } = await window.google.maps.importLibrary('maps'); @@ -72,13 +75,13 @@ export default { async createMapWithMarkersForAddresses(addresses) { const shopPositions = await this.getLocationsFromAddresses(addresses); const zipBounds = await this.getBoundsFromAddress(this.zipCodeAddress); - const map = await this.getMap(zipBounds.getCenter()); + const map = await this.getMap(zipBounds?.getCenter()); await this.addMarkersToMap(map, shopPositions); - const positionsToDisplay = shopPositions.concat(zipBounds.getNorthEast(), zipBounds.getSouthWest()); + const positionsToDisplay = shopPositions.concat(zipBounds?.getNorthEast(), zipBounds?.getSouthWest()); const bounds = this.getBounds(positionsToDisplay); - map.fitBounds(bounds); + map?.fitBounds(bounds); } } }; diff --git a/src/layouts/tpa-search/__snapshots__/tpa-search.spec.js.snap b/src/layouts/tpa-search/__snapshots__/tpa-search.spec.js.snap index b8e194a6..fc429c1b 100644 --- a/src/layouts/tpa-search/__snapshots__/tpa-search.spec.js.snap +++ b/src/layouts/tpa-search/__snapshots__/tpa-search.spec.js.snap @@ -6,8 +6,24 @@ Object { "displayAvailabilityIndicators": false, }, "filter": "", + "initialLoading": false, "mapZipCode": "12663", "providers": Array [], + "radiusFilterPairs": Array [ + Object { + "filter": "25 miles", + "radius": 25, + }, + Object { + "filter": "50 miles", + "radius": 50, + }, + Object { + "filter": "100 miles", + "radius": 100, + }, + ], + "reloadProviders": false, "rules": Object { "filter": "option-required", "provider": "option-required", @@ -89,14 +105,25 @@ Object { "setup": [Function], }, "loader": Object { + "computed": Object { + "cssProps": [Function], + }, "name": "loader", "props": Object { + "height": Object { + "default": 1, + "type": [Function], + }, "loaderColor": Object { "type": [Function], }, "loaderPosition": Object { "type": [Function], }, + "width": Object { + "default": 1, + "type": [Function], + }, }, "render": [Function], }, diff --git a/src/layouts/tpa-search/tpa-search.spec.js b/src/layouts/tpa-search/tpa-search.spec.js index 1854c470..d8185733 100644 --- a/src/layouts/tpa-search/tpa-search.spec.js +++ b/src/layouts/tpa-search/tpa-search.spec.js @@ -10,6 +10,7 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import settleAllPromises from '@/helpers/layout-helper.js'; 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', () => ({ @@ -149,7 +150,18 @@ describe('TPA search page', () => { // Assert expect(providerSelectionForm.exists()).toBeTruthy(); }); - test('map', async () => { + test('map loader when initialLoading is true', async () => { + // Arrange + const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ initialLoading: true }); + + // Act + const mapLoader = wrapper.findComponent('#mapLoader'); + + // Assert + expect(mapLoader.exists()).toBeTruthy(); + }); + test('map when initialLoading is false', async () => { // Arrange const zipCode = '12345'; const { wrapper } = getMountedComponent(); @@ -162,7 +174,8 @@ describe('TPA search page', () => { zipCode: '99230' } }], - mapZipCode: zipCode + mapZipCode: zipCode, + initialLoading: false }); const expectedAddresses = ['123 Lane Ave, New York, NY 99230']; @@ -175,9 +188,10 @@ describe('TPA search page', () => { expect(map.props().addresses).toEqual(expectedAddresses); expect(map.props().zipCode).toBe(zipCode); }); - test('search radius filter', () => { + test('search radius filter when initialLoading is false', async () => { // Arrange const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ initialLoading: false }); const expectedWidgetName = 'FilterByQuestion'; // Act @@ -188,12 +202,23 @@ describe('TPA search page', () => { expect(searchRadiusFilter.props().cmsWidgetName).toBe(expectedWidgetName); expect(searchRadiusFilter.props().validationRules).toBe(globalRules.OPTION_REQUIRED); }); - test('select provider question', async () => { + test('providers loader when initialLoading is false and reloadProviders is true', async () => { + // Arrange + const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ initialLoading: false, reloadProviders: true }); + + // Act + const providersLoader = wrapper.findComponent('#providersLoader'); + + // Assert + expect(providersLoader.exists()).toBeTruthy(); + }); + test('select provider question when initialLoading and reloadProviders are false', async () => { // Arrange const wrapper = shallowMount(tpaSearch, getMountOptions()); await wrapper.setData({ providers: [{ - name: 'Shop Auto Glass', + companyName: 'Shop Auto Glass', phoneNumber: '740-555-1234', distanceInMiles: 1.2345, providerNumber: '232209', @@ -203,7 +228,9 @@ describe('TPA search page', () => { state: 'NY', zipCode: '99230' } - }] + }], + initialLoading: false, + reloadProviders: false }); const expectedAnswers = [{ buttonLabel: 'Shop Auto Glass', @@ -230,13 +257,17 @@ describe('TPA search page', () => { expect(selectProviderQuestion.props().additionalButtonData).toEqual(expectedAdditionalButtonData); }); test.each([[], null, undefined])( - 'no network providers alert when providers length is 0, undefined, or null', - (providers) => { + 'no network providers alert when providers length is 0, undefined, or null and initialLoading and reloadProviders are false', + async (providers) => { // Arrange const initialData = { providers }; const wrapper = shallowMount(tpaSearch, getMountOptions({}, initialData)); + await wrapper.setData({ + initialLoading: false, + reloadProviders: false + }); // Act const noNetworkProvidersAlert = wrapper.findComponent('#alertNoNetworkProviders'); @@ -248,9 +279,13 @@ describe('TPA search page', () => { expect(noNetworkProvidersAlert.props().isDismissible).toBeFalsy(); } ); - test('preferred shop not listed link', () => { + test('preferred shop not listed link when initialLoading and reloadProviders are false', async () => { // Arrange const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ + initialLoading: false, + reloadProviders: false + }); // Act const preferredShopNotListedLink = wrapper.findComponent('#preferredShopNotListedLink'); @@ -272,16 +307,123 @@ describe('TPA search page', () => { expect(footer.props().cmsWidgetName).toBe('SiteFooterWidget'); }); }); - test('should not render no network providers alert when providers length is not 0', async () => { - // Arrange - const wrapper = shallowMount(tpaSearch, getMountOptions()); - await wrapper.setData({ providers: ['p1', 'p2'] }); + describe('should not render', () => { + test('map loader when initialLoading is false', async () => { + // Arrange + const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ initialLoading: false }); - // Act - const noNetworkProvidersAlert = wrapper.findComponent('#alertNoNetworkProviders'); + // Act + const mapLoader = wrapper.findComponent('#mapLoader'); - // Assert - expect(noNetworkProvidersAlert.exists()).toBeFalsy(); + // Assert + expect(mapLoader.exists()).toBeFalsy(); + }); + test('map when initialLoading is true', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + await wrapper.setData({ initialLoading: true }); + + // Act + const map = wrapper.findComponent('#map'); + + // Assert + expect(map.exists()).toBeFalsy(); + }); + test('search radius filter when initialLoading is true', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + await wrapper.setData({ initialLoading: true }); + + // Act + const searchRadiusFilter = wrapper.findComponent('#searchRadiusFilter'); + + // Assert + expect(searchRadiusFilter.exists()).toBeFalsy(); + }); + describe('select provider question', () => { + test('when initialLoading is true', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + await wrapper.setData({ initialLoading: true }); + + // Act + const selectProviderQuestion = wrapper.findComponent('#selectProviderQuestion'); + + // Assert + expect(selectProviderQuestion.exists()).toBeFalsy(); + }); + test('when reloadProviders is true', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + await wrapper.setData({ reloadProviders: 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 () => { + // Arrange + const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ providers: ['p1', 'p2'] }); + + // Act + const noNetworkProvidersAlert = wrapper.findComponent('#alertNoNetworkProviders'); + + // Assert + expect(noNetworkProvidersAlert.exists()).toBeFalsy(); + }); + test('when initialLoading is true', async () => { + // Arrange + const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ providers: [], initialLoading: true }); + + // Act + const noNetworkProvidersAlert = wrapper.findComponent('#alertNoNetworkProviders'); + + // Assert + expect(noNetworkProvidersAlert.exists()).toBeFalsy(); + }); + test('when reloadProviders is true', async () => { + // Arrange + const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ providers: [], reloadProviders: true }); + + // Act + const noNetworkProvidersAlert = wrapper.findComponent('#alertNoNetworkProviders'); + + // Assert + expect(noNetworkProvidersAlert.exists()).toBeFalsy(); + }); + }); + describe('preferred shop not listed link', () => { + test('when initialLoading is true', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + await wrapper.setData({ initialLoading: true }); + + // Act + const preferredShopNotListedLink = wrapper.findComponent('#preferredShopNotListedLink'); + + // Assert + expect(preferredShopNotListedLink.exists()).toBeFalsy(); + }); + test('when reloadProviders is true', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + await wrapper.setData({ reloadProviders: true }); + + // Act + const preferredShopNotListedLink = wrapper.findComponent('#preferredShopNotListedLink'); + + // Assert + expect(preferredShopNotListedLink.exists()).toBeFalsy(); + }); + }); }); describe('computed', () => { describe('filterOptions', () => { @@ -330,7 +472,7 @@ describe('TPA search page', () => { }); }); test.each([null, undefined, '', 'non empty string'])( - 'tpaSearchQuestionLabel returns value from getCmsContent', + 'tpaSearchQuestionLabel returns "%p" from getCmsContent', (cmsContent) => { // Arrange const mountOptions = getMountOptions(); @@ -352,7 +494,7 @@ describe('TPA search page', () => { } ); test.each([null, undefined, '', 'non empty string'])( - 'searchInstructionsText returns value from getCmsContent', + 'searchInstructionsText returns "%p" from getCmsContent', (cmsContent) => { // Arrange const mountOptions = getMountOptions(); @@ -374,7 +516,7 @@ describe('TPA search page', () => { } ); test.each([null, undefined, '', 'non empty string'])( - 'shopNotListedModalLink returns value from getCmsContent', + 'shopNotListedModalLink returns "%p" from getCmsContent', (cmsContent) => { // Arrange const mountOptions = getMountOptions(); @@ -508,7 +650,7 @@ describe('TPA search page', () => { await wrapper.setData({ providers: [ { - name: 'Shop Auto Glass', + companyName: 'Shop Auto Glass', phoneNumber: '740-555-1234', distanceInMiles: 1.2345, providerNumber: '232209', @@ -520,7 +662,7 @@ describe('TPA search page', () => { } }, { - name: 'Safelite AutoGlass', + companyName: 'Safelite AutoGlass', phoneNumber: '676-555-0099', distanceInMiles: 123.9452, providerNumber: '123456', @@ -547,7 +689,7 @@ describe('TPA search page', () => { }); describe('providerButtonData', () => { test.each([null, undefined, []])( - 'returns empty list when providers empty', + 'returns empty list when providers equals "%p"', async (providers) => { // Arrange const wrapper = shallowMount(tpaSearch, getMountOptions()); @@ -566,7 +708,7 @@ describe('TPA search page', () => { await wrapper.setData({ providers: [ { - name: 'Shop Auto Glass', + companyName: 'Shop Auto Glass', phoneNumber: '740-555-1234', distanceInMiles: 1.2345, providerNumber: '232209', @@ -578,7 +720,7 @@ describe('TPA search page', () => { } }, { - name: 'Safelite AutoGlass', + companyName: 'Safelite AutoGlass', phoneNumber: '676-555-0099', distanceInMiles: 123.9452, providerNumber: '123456', @@ -613,8 +755,86 @@ describe('TPA search page', () => { expect(result).toEqual(expectedResult); }); }); + describe('selectedProviderIsSafeliteShop', () => { + test('no issue when provider in providers with no provider number', async () => { + // Arrange + const selectedProviderNumber = '10099'; + const providers = [ + { isSafeliteShop: false }, + { isSafeliteShop: true } + ]; + const wrapper = shallowMount(tpaSearch, getMountOptions()); + await wrapper.setData({ selectedProviderNumber, providers }); + + // Act + const result = wrapper.vm.selectedProviderIsSafeliteShop; + + // Assert + expect(result).toEqual(false); + }); + 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({ selectedProviderNumber, providers }); + + // 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'; @@ -635,6 +855,7 @@ describe('TPA search page', () => { expect(wrapper.vm.providers).toEqual(providers.data.shopProviders); expect(wrapper.vm.mapZipCode).toBe(zipCode); }); + // TODO confirm tests appropriate. Also should this method be async? describe('on providers', () => { test.each([null, undefined, []])( 'sets selected provider number to "" when there are no providers', @@ -686,7 +907,6 @@ describe('TPA search page', () => { (streetAddress, city, state, zipCode, expected) => { // Arrange const { wrapper } = getMountedComponent(); - useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => (newProviders)); const provider = { address: { streetAddress, @@ -723,7 +943,7 @@ describe('TPA search page', () => { const { wrapper } = getMountedComponent(); const providers = { data: { - shopProviders: [{ name: 'foo' }] + shopProviders: [{ companyName: 'foo' }] } }; useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => (providers)); @@ -774,7 +994,7 @@ describe('TPA search page', () => { zipCode, mapZipCode: initialMapZipCode }); - const shopProviders = [{ name: 'foo' }]; + const shopProviders = [{ companyName: 'foo' }]; useMainStore().getTpaProviders = jest.fn().mockImplementationOnce(() => ({ data: { shopProviders } })); @@ -797,15 +1017,46 @@ describe('TPA search page', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); }); - test('forwardButtonAction invokes navigate method', () => { - // Arrange - const { wrapper } = getMountedComponent(); + describe('forwardButtonAction', () => { + test('invokes navigate method with safelite shop scenario when selectedProviderIsSafeliteShop true', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + const providerNumber = '1109'; + await wrapper.setData({ + selectedProviderNumber: providerNumber, + providers: [{ + providerNumber, + isSafeliteShop: true + }] + }); - // Act - wrapper.vm.backButtonAction(); + // Act + wrapper.vm.forwardButtonAction(); - // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP, undefined); + }); + test('invokes navigate method with non safelite shop scenario when selectedProviderIsSafeliteShop false', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + const providerNumber = '928'; + await wrapper.setData({ + selectedProviderNumber: providerNumber, + providers: [{ + providerNumber, + isSafeliteShop: false + }] + }); + + // Act + wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, + undefined + ); + }); }); describe('getCustomValueFromString', () => { test('returns radius in miles value if "radiusInMiles"', () => { @@ -855,7 +1106,7 @@ describe('TPA search page', () => { // Arrange const wrapper = shallowMount(tpaSearch, getMountOptions()); const provider = { - name: 'Shop Auto Glass', + companyName: 'Shop Auto Glass', phoneNumber: '740-555-1234', distanceInMiles: 1.2345, providerNumber: '232209', @@ -882,10 +1133,10 @@ describe('TPA search page', () => { describe('returns result with button label', () => { test.each(['', undefined, null])( 'equal to empty string when name is empty', - (name) => { + (companyName) => { // Arrange const wrapper = shallowMount(tpaSearch, getMountOptions()); - const provider = { name }; + const provider = { companyName }; // Act const result = wrapper.vm.getShopButtonDataFromProvider(provider); @@ -897,14 +1148,14 @@ describe('TPA search page', () => { test('returns provider name when exists', () => { // Arrange const wrapper = shallowMount(tpaSearch, getMountOptions()); - const name = 'Some Shop Name'; - const provider = { name }; + const companyName = 'Some Shop Name'; + const provider = { companyName }; // Act const result = wrapper.vm.getShopButtonDataFromProvider(provider); // Assert - expect(result.buttonLabel).toEqual(name); + expect(result.buttonLabel).toEqual(companyName); }); }); describe('returns result with button label sub copy', () => { @@ -994,7 +1245,7 @@ describe('TPA search page', () => { const { wrapper } = getMountedComponent(); const zipCode = '18394'; useMainStore().order.customer.address.zipCode = zipCode; - const providers = [{ name: 'provider' }]; + const providers = [{ companyName: 'provider' }]; useMainStore().getTpaProviders = jest.fn().mockImplementation((_, radius) => ({ data: { shopProviders: radius === 25 ? providers : [] } })); const expectedFilter = '25 miles'; @@ -1013,13 +1264,14 @@ describe('TPA search page', () => { // Assert expect(wrapper.vm.filter).toBe(expectedFilter); expect(wrapper.vm.providers).toEqual(providers); + expect(useMainStore().getTpaProviders).toBeCalledTimes(1); }); 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 = zipCode; - const providers = [{ name: 'provider' }]; + const providers = [{ companyName: 'provider' }]; useMainStore().getTpaProviders = jest.fn().mockImplementation((_, radius) => ({ data: { shopProviders: radius === 50 ? providers : [] } })); const expectedFilter = '50 miles'; @@ -1038,6 +1290,7 @@ describe('TPA search page', () => { // Assert expect(wrapper.vm.filter).toBe(expectedFilter); expect(wrapper.vm.providers).toEqual(providers); + expect(useMainStore().getTpaProviders).toBeCalledTimes(2); }); test( 'when providers exist at 100 mile radius but not 50 or 25, filter is set to "100 miles" and providers set to expected', @@ -1046,7 +1299,7 @@ describe('TPA search page', () => { const { wrapper } = getMountedComponent(); const zipCode = '18394'; useMainStore().order.customer.address.zipCode = zipCode; - const providers = [{ name: 'provider' }]; + const providers = [{ companyName: 'provider' }]; useMainStore().getTpaProviders = jest.fn().mockImplementation((_, radius) => ({ data: { shopProviders: radius === 100 ? providers : [] } })); const expectedFilter = '100 miles'; @@ -1065,6 +1318,7 @@ describe('TPA search page', () => { // Assert expect(wrapper.vm.filter).toBe(expectedFilter); expect(wrapper.vm.providers).toEqual(providers); + expect(useMainStore().getTpaProviders).toBeCalledTimes(3); } ); test( @@ -1091,6 +1345,7 @@ describe('TPA search page', () => { // Assert expect(wrapper.vm.filter).toBe(expectedFilter); expect(wrapper.vm.providers).toEqual([]); + expect(useMainStore().getTpaProviders).toBeCalledTimes(3); } ); }); diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue index 29fce69c..00ebacdc 100644 --- a/src/layouts/tpa-search/tpa-search.vue +++ b/src/layouts/tpa-search/tpa-search.vue @@ -1,104 +1,122 @@