572 lines
20 KiB
JavaScript
572 lines
20 KiB
JavaScript
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
|
|
};
|
|
const mockMap = jest.fn(() => mockMapInstance);
|
|
|
|
const mockGeocode = jest.fn();
|
|
const mockGeocoderInstance1 = {
|
|
geocode: mockGeocode
|
|
};
|
|
const mockGeocoderInstance2 = {
|
|
geocode: mockGeocode
|
|
};
|
|
const mockGeocoder = jest.fn(() => (mockGeocoderInstance1));
|
|
|
|
const mockAdvancedMarkerInstance = {
|
|
addListener: jest.fn()
|
|
};
|
|
|
|
const mockAdvancedMarkerElement = jest.fn(() => (mockAdvancedMarkerInstance));
|
|
const mockPinElement = jest.fn();
|
|
const mockInfoWindow = jest.fn();
|
|
|
|
const mockImportLibrary = jest.fn().mockImplementation(() => (Promise.resolve({
|
|
Map: mockMap,
|
|
Geocoder: mockGeocoder,
|
|
AdvancedMarkerElement: mockAdvancedMarkerElement,
|
|
PinElement: mockPinElement
|
|
})));
|
|
|
|
const mockExtend = jest.fn();
|
|
const mockLatLngBound = { extend: mockExtend };
|
|
|
|
const setupGoogleMock = () => {
|
|
global.window.google = {
|
|
maps: {
|
|
importLibrary: mockImportLibrary,
|
|
LatLngBounds: jest.fn(() => (mockLatLngBound)),
|
|
InfoWindow: mockInfoWindow
|
|
}
|
|
};
|
|
};
|
|
|
|
beforeEach(() => {
|
|
// clear constructors
|
|
mockMap.mockClear();
|
|
mockGeocoder.mockClear();
|
|
mockAdvancedMarkerElement.mockClear();
|
|
mockPinElement.mockClear();
|
|
|
|
// clear methods
|
|
mockExtend.mockClear();
|
|
mockGeocode.mockClear();
|
|
mockFitBounds.mockClear();
|
|
|
|
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++) {
|
|
await wrapper.vm.$nextTick();
|
|
}
|
|
}
|
|
|
|
describe('Google Map', () => {
|
|
describe('should render', () => {
|
|
test('expected initial data', async () => {
|
|
// Arrange
|
|
const wrapper = shallowMount(googleMap, {});
|
|
await awaitingSetupTicks(wrapper);
|
|
|
|
// Assert
|
|
expect(wrapper.vm.$data).toMatchSnapshot();
|
|
});
|
|
test('map', async () => {
|
|
// Arrange
|
|
const mapReference = '#map';
|
|
const wrapper = shallowMount(googleMap, {});
|
|
await awaitingSetupTicks(wrapper);
|
|
|
|
// Act
|
|
const map = wrapper.find(mapReference);
|
|
|
|
// Assert
|
|
expect(map.exists()).toBeTruthy();
|
|
});
|
|
});
|
|
test.each([
|
|
['13001', '13001 USA'],
|
|
['9', '9 USA'],
|
|
['', ' USA'],
|
|
[null, ' USA']
|
|
])(
|
|
'given that zipcode set to "%p", computed zipCodeAddress should return "%p"',
|
|
async (zipCode, expected) => {
|
|
// Arrange
|
|
const { wrapper } = getMountedComponent({}, {}, { zipCode });
|
|
await awaitingSetupTicks(wrapper);
|
|
|
|
// Act
|
|
const result = wrapper.vm.zipCodeAddress;
|
|
|
|
// Assert
|
|
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 markers = [
|
|
{
|
|
fullAddress: address1
|
|
},
|
|
{
|
|
fullAddress: 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 = { markers, 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 zipCode = '00882';
|
|
|
|
const mockGetCenter = jest.fn();
|
|
const mockNorthEast = jest.fn();
|
|
const mockSouthWest = jest.fn();
|
|
const zipCodeGeocodeResult = {
|
|
results: [
|
|
{
|
|
geometry: {
|
|
bounds:
|
|
{
|
|
getCenter: mockGetCenter,
|
|
getNorthEast: mockNorthEast,
|
|
getSouthWest: mockSouthWest
|
|
}
|
|
}
|
|
}
|
|
]
|
|
};
|
|
const [address1, address2, position1, position2] = ['a1', 'a2', 'p1', 'p2'];
|
|
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 markers = [
|
|
{
|
|
fullAddress: address1
|
|
},
|
|
{
|
|
fullAddress: address2
|
|
}];
|
|
|
|
// Act
|
|
const { wrapper } = getMountedComponent({}, { zipCode });
|
|
await awaitingSetupTicks(wrapper);
|
|
await wrapper.vm.$options.watch.markers.call(wrapper.vm, markers);
|
|
await awaitingSetupTicks(wrapper);
|
|
|
|
// Assert
|
|
expect(mockMap).toBeCalledTimes(2);
|
|
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(6);
|
|
expect(mockFitBounds).toBeCalledTimes(2);
|
|
|
|
expect(mockGetCenter).toBeCalledTimes(2);
|
|
expect(mockNorthEast).toBeCalledTimes(2);
|
|
expect(mockSouthWest).toBeCalledTimes(2);
|
|
});
|
|
describe('method', () => {
|
|
test('getMap calls map constructor with expected parameters', async () => {
|
|
// Arrange
|
|
const wrapper = shallowMount(googleMap, {});
|
|
await awaitingSetupTicks(wrapper);
|
|
const center = { lat: 90, lng: -5 };
|
|
|
|
// Act
|
|
const result = await wrapper.vm.getMap(center);
|
|
|
|
// Assert
|
|
expect(mockMap).toHaveBeenCalledWith(
|
|
null,
|
|
expect.objectContaining({ center, mapId: 'map_id', mapTypeControl: false })
|
|
);
|
|
expect(result).toBe(mockMapInstance);
|
|
});
|
|
test.each([
|
|
[undefined, 0],
|
|
[null, 0],
|
|
[[], 0],
|
|
[['loc1'], 1],
|
|
[['loc1', 'loc1', 'loc1', 'loc1'], 4]
|
|
])(
|
|
'given parameter %p, getBounds calls extend %p time(s)',
|
|
async (locations, numberOfExtendCallsPostMount) => {
|
|
// Arrange
|
|
const wrapper = shallowMount(googleMap, {});
|
|
await awaitingSetupTicks(wrapper);
|
|
|
|
mockGeocode.mockImplementation(() => {
|
|
const result = {
|
|
results: [
|
|
{ geometry: { location: 'p1' } }
|
|
]
|
|
};
|
|
return Promise.resolve(result);
|
|
});
|
|
|
|
// Act
|
|
const result = wrapper.vm.getBounds(locations);
|
|
|
|
// Assert
|
|
expect(mockExtend).toHaveBeenCalledTimes(numberOfExtendCallsPostMount);
|
|
expect(result).toBe(mockLatLngBound);
|
|
}
|
|
);
|
|
test.each([
|
|
[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 } = getMountedComponent({}, { geocoder: originalGeocoder }, {});
|
|
await awaitingSetupTicks(wrapper);
|
|
|
|
// Act
|
|
await wrapper.vm.setGeocoder();
|
|
await wrapper.vm.$nextTick();
|
|
|
|
// Assert
|
|
expect(mockGeocoder).toHaveBeenCalledTimes(numberOfCalls);
|
|
expect(wrapper.vm.geocoder).toEqual(newGeocoder);
|
|
}
|
|
);
|
|
test.each([
|
|
[null, 0],
|
|
[undefined, 0],
|
|
[[], 0],
|
|
[['p1'], 1],
|
|
[['p1', 'p2', 'p3'], 3]
|
|
])(
|
|
'addMarkersToMap given positions argument %p, creates AdvancedMarkerElement %p time(s)',
|
|
async (positions, numberOfCalls) => {
|
|
// Arrange
|
|
const wrapper = shallowMount(googleMap, {});
|
|
await awaitingSetupTicks(wrapper);
|
|
const map = jest.fn();
|
|
|
|
// Act
|
|
await wrapper.vm.addMarkersToMap(map, positions);
|
|
|
|
// Assert
|
|
expect(mockAdvancedMarkerElement).toHaveBeenCalledTimes(numberOfCalls);
|
|
}
|
|
);
|
|
describe('getLocationsFromAddresses', () => {
|
|
test.each([
|
|
[null, 0],
|
|
[undefined, 0],
|
|
[[], 0],
|
|
[['a1'], 1],
|
|
[['a1', 'a2', 'a3'], 3]
|
|
])(
|
|
'given address(es) %p calls geocode %p times',
|
|
async (addresses, numberOfCallsPostMount) => {
|
|
// Arrange
|
|
const wrapper = shallowMount(googleMap, {});
|
|
await awaitingSetupTicks(wrapper);
|
|
const numberOfCallsFromMount = 1;
|
|
expect(mockGeocode).toHaveBeenCalledTimes(numberOfCallsFromMount);
|
|
|
|
// Act
|
|
await wrapper.vm.getLocationsFromAddresses(addresses?.map((a) => ({ fullAddress: a })));
|
|
await wrapper.vm.$nextTick();
|
|
|
|
// Assert
|
|
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'].map((a) => ({ fullAddress: a }));
|
|
mockGeocode.mockImplementationOnce(() => null)
|
|
.mockImplementationOnce(() => ({ results: null }))
|
|
.mockImplementationOnce(() => ({ results: [] }))
|
|
.mockImplementationOnce(() => ({ results: [{}] }))
|
|
.mockImplementationOnce(() => (
|
|
{ results: [{ geometry: undefined }] }
|
|
))
|
|
.mockImplementationOnce(() => (
|
|
{ results: [{ geometry: {} }] }
|
|
))
|
|
.mockImplementationOnce(() => (
|
|
{
|
|
results: [
|
|
{ geometry: { location: 'some value' } }
|
|
]
|
|
}
|
|
))
|
|
.mockImplementationOnce(() => (
|
|
{
|
|
results: [
|
|
{ geometry: { location: 'some other value' } }
|
|
]
|
|
}
|
|
));
|
|
const expectedResult = ['some value', 'some other value'];
|
|
|
|
// Act
|
|
const result = (await wrapper.vm.getLocationsFromAddresses(addresses)).map((a) => a.position);
|
|
|
|
// Assert
|
|
expect(result.length).toBe(2);
|
|
expect(result).toEqual(expectedResult);
|
|
});
|
|
});
|
|
describe('getBoundsFromAddress', () => {
|
|
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 = {
|
|
results: [
|
|
{
|
|
geometry: { bounds: expectedResult }
|
|
}
|
|
]
|
|
};
|
|
mockGeocode.mockImplementationOnce(() => Promise.resolve(geocodeResult));
|
|
|
|
// Act
|
|
const result = await wrapper.vm.getBoundsFromAddress(address);
|
|
|
|
// Assert
|
|
expect(result).toBe(expectedResult);
|
|
expect(wrapper.vm.geocoder).not.toBeNull();
|
|
});
|
|
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({}));
|
|
|
|
// Act
|
|
const result = await wrapper.vm.getBoundsFromAddress(address);
|
|
|
|
// Assert
|
|
expect(result).toBeNull();
|
|
expect(wrapper.vm.geocoder).not.toBeNull();
|
|
});
|
|
});
|
|
describe('createMapWithMarkersForAddresses', () => {
|
|
test('calls expected when addresses provided', 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 shopGeocodeResult = {
|
|
results: [
|
|
{ geometry: { location: 'valid location' } }
|
|
]
|
|
};
|
|
const zipCode = '00882';
|
|
mockGeocode.mockImplementation((obj) =>
|
|
Promise.resolve(obj.address.includes(zipCode)
|
|
? zipCodeGeocodeResult
|
|
: shopGeocodeResult));
|
|
const addresses = [{ fullAddress: 'a1' }, { fullAddress: 'a2' }];
|
|
const { wrapper } = getMountedComponent({}, { zipCode });
|
|
await awaitingSetupTicks(wrapper);
|
|
|
|
// Act
|
|
await wrapper.vm.createMapWithMarkersForAddresses(addresses);
|
|
await awaitingSetupTicks(wrapper);
|
|
|
|
// Assert
|
|
expect(mockMap).toBeCalledTimes(2);
|
|
expect(mockAdvancedMarkerElement).toBeCalledTimes(2);
|
|
expect(mockGeocoder).toBeCalledTimes(1);
|
|
|
|
expect(mockExtend).toBeCalledTimes(6);
|
|
expect(mockFitBounds).toBeCalledTimes(2);
|
|
|
|
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 mockGetCenter = jest.fn();
|
|
const mockNorthEast = jest.fn();
|
|
const mockSouthWest = jest.fn();
|
|
const zipCodeGeocodeResult = {
|
|
results: [
|
|
{
|
|
geometry: {
|
|
bounds:
|
|
{
|
|
getCenter: mockGetCenter,
|
|
getNorthEast: mockNorthEast,
|
|
getSouthWest: mockSouthWest
|
|
}
|
|
}
|
|
}
|
|
]
|
|
};
|
|
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(2);
|
|
expect(mockAdvancedMarkerElement).toBeCalledTimes(0);
|
|
expect(mockGeocoder).toBeCalledTimes(1);
|
|
|
|
expect(mockExtend).toBeCalledTimes(4);
|
|
expect(mockFitBounds).toBeCalledTimes(2);
|
|
|
|
expect(mockGetCenter).toBeCalledTimes(2);
|
|
expect(mockNorthEast).toBeCalledTimes(2);
|
|
expect(mockSouthWest).toBeCalledTimes(2);
|
|
}
|
|
);
|
|
});
|
|
});
|
|
});
|