From ac14c550704d60db1326bfe7e428d1f7dd2c0a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Or=C5=82=C3=B3w?= <adrian.orlow@fishbrain.com> Date: Tue, 17 Oct 2023 23:19:43 +0200 Subject: [PATCH] feat(map): improve hook and tests of useOlMap --- .../Map/MapViewer/utils/useOlMap.test.ts | 88 +++++++++++++++++++ .../Map/MapViewer/utils/useOlMap.ts | 17 ++-- 2 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 src/components/Map/MapViewer/utils/useOlMap.test.ts diff --git a/src/components/Map/MapViewer/utils/useOlMap.test.ts b/src/components/Map/MapViewer/utils/useOlMap.test.ts new file mode 100644 index 00000000..c606b77a --- /dev/null +++ b/src/components/Map/MapViewer/utils/useOlMap.test.ts @@ -0,0 +1,88 @@ +import mapSlice, { setMapData } from '@/redux/map/map.slice'; +import { getReduxWrapperUsingSliceReducer } from '@/utils/testing/getReduxWrapperUsingSliceReducer'; +import { renderHook, waitFor } from '@testing-library/react'; +import { Map } from 'ol'; +import React from 'react'; +import { useOlMap } from './useOlMap'; + +const useRefValue = { + current: null, +}; + +Object.defineProperty(useRefValue, 'current', { + get: jest.fn(() => ({ + innerHTML: '', + appendChild: jest.fn(), + addEventListener: jest.fn(), + getRootNode: jest.fn(), + })), + set: jest.fn(() => ({ + innerHTML: '', + appendChild: jest.fn(), + addEventListener: jest.fn(), + getRootNode: jest.fn(), + })), +}); + +jest.spyOn(React, 'useRef').mockReturnValue(useRefValue); + +describe('useOlMap - util', () => { + const { Wrapper, store } = getReduxWrapperUsingSliceReducer('map', mapSlice); + + describe('when initializing', () => { + it('should set map instance', async () => { + const dummyElement = document.createElement('div'); + const { result } = renderHook(() => useOlMap({ target: dummyElement }), { wrapper: Wrapper }); + await waitFor(() => expect(result.current.mapInstance).toBeInstanceOf(Map)); + }); + + it('should render content inside the target element', async () => { + const FIRST_NODE = 0; + const dummyElement = document.createElement('div'); + renderHook(() => useOlMap({ target: dummyElement }), { wrapper: Wrapper }); + + expect(dummyElement.childNodes[FIRST_NODE]).toHaveClass('ol-viewport'); + }); + }); + + describe('when initialized', () => { + it('should modify view of the map instance on position config change', async () => { + const dummyElement = document.createElement('div'); + const { result } = renderHook(() => useOlMap({ target: dummyElement }), { wrapper: Wrapper }); + const setViewSpy = jest.spyOn(result.current.mapInstance as Map, 'setView'); + const CALLED_ONCE = 1; + + store.dispatch( + setMapData({ + position: { + x: 0, + y: 0, + }, + }), + ); + + await waitFor(() => expect(setViewSpy).toBeCalledTimes(CALLED_ONCE)); + }); + + it('should modify layers of the map instance on size config change', async () => { + const dummyElement = document.createElement('div'); + const { result } = renderHook(() => useOlMap({ target: dummyElement }), { wrapper: Wrapper }); + const setLayersSpy = jest.spyOn(result.current.mapInstance as Map, 'setLayers'); + const CALLED_ONCE = 1; + + store.dispatch( + setMapData({ + size: { + maxZoom: 10, + minZoom: 2, + tileSize: 256, + width: 1000, + height: 1000, + }, + }), + ); + + await waitFor(() => expect(setLayersSpy).toBeCalledTimes(CALLED_ONCE)); + }); + }); +}); diff --git a/src/components/Map/MapViewer/utils/useOlMap.ts b/src/components/Map/MapViewer/utils/useOlMap.ts index f9247726..b7525d19 100644 --- a/src/components/Map/MapViewer/utils/useOlMap.ts +++ b/src/components/Map/MapViewer/utils/useOlMap.ts @@ -1,18 +1,21 @@ import Map from 'ol/Map'; -import { MutableRefObject, useEffect, useRef, useState } from 'react'; +import React, { MutableRefObject, useEffect, useState } from 'react'; import { MapInstance } from '../MapViewer.types'; import { useOlMapConfig } from './useOlMapConfig'; import { useOlMapInit } from './useOlMapInit'; +interface UseOlMapInput { + target?: HTMLElement; +} interface UseOlMapOutput { mapRef: MutableRefObject<null | HTMLDivElement>; mapInstance: MapInstance; } -type UseOlMap = () => UseOlMapOutput; +type UseOlMap = (input?: UseOlMapInput) => UseOlMapOutput; -export const useOlMap: UseOlMap = () => { - const mapRef = useRef<null | HTMLDivElement>(null); +export const useOlMap: UseOlMap = ({ target } = {}) => { + const mapRef = React.useRef<null | HTMLDivElement>(null); const [mapInstance, setMapInstance] = useState<MapInstance>(undefined); const mapConfig = useOlMapConfig(); useOlMapInit(); @@ -24,11 +27,11 @@ export const useOlMap: UseOlMap = () => { } const map = new Map({ - target: mapRef.current, + target: target || mapRef.current, }); - setMapInstance(map); - }, []); + setMapInstance(currentMap => currentMap || map); + }, [target]); useEffect(() => { if (!mapInstance) { -- GitLab