diff --git a/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.test.tsx b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.test.tsx new file mode 100644 index 0000000000000000000000000000000000000000..226bd904950ae5d936b46ff2e47634ecf97ceae6 --- /dev/null +++ b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.test.tsx @@ -0,0 +1,83 @@ +import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; +import { AppDispatch, RootState } from '@/redux/store'; +import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; +import { InitialStoreState } from '@/utils/testing/getReduxWrapperWithStore'; +import { render, screen } from '@testing-library/react'; +import { MockStoreEnhanced } from 'redux-mock-store'; +import { MapAdditionalActions } from './MapAdditionalActions.component'; + +const renderComponent = ( + initialStore?: InitialStoreState, +): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => { + const { Wrapper, store } = getReduxStoreWithActionsListener(initialStore); + return ( + render( + <Wrapper> + <MapAdditionalActions /> + </Wrapper>, + ), + { + store, + } + ); +}; + +describe('MapAdditionalActions - component', () => { + describe('when always', () => { + beforeEach(() => { + renderComponent(); + }); + + it('should render zoom in button', () => { + const image = screen.getByAltText('zoom in button icon'); + const button = image.closest('button'); + expect(button).toBeInTheDocument(); + }); + + it('should render zoom out button', () => { + const image = screen.getByAltText('zoom out button icon'); + const button = image.closest('button'); + expect(button).toBeInTheDocument(); + }); + + it('should render location button', () => { + const image = screen.getByAltText('location button icon'); + const button = image.closest('button'); + expect(button).toBeInTheDocument(); + }); + }); + + describe('when clicked on zoom in button', () => { + it('should dispatch varyPositionZoom action with valid delta', () => { + const { store } = renderComponent(); + const image = screen.getByAltText('zoom in button icon'); + const button = image.closest('button'); + button!.click(); + + const actions = store.getActions(); + expect(actions[FIRST_ARRAY_ELEMENT]).toStrictEqual({ + payload: { delta: 1 }, + type: 'map/varyPositionZoom', + }); + }); + }); + + describe('when clicked on zoom in button', () => { + it('should dispatch varyPositionZoom action with valid delta', () => { + const { store } = renderComponent(); + const image = screen.getByAltText('zoom out button icon'); + const button = image.closest('button'); + button!.click(); + + const actions = store.getActions(); + expect(actions[FIRST_ARRAY_ELEMENT]).toStrictEqual({ + payload: { delta: -1 }, + type: 'map/varyPositionZoom', + }); + }); + }); + + describe.skip('when clicked on location button', () => { + // TODO: implelemnt test + }); +}); diff --git a/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx index 77a7a682bb7881ca4286dbf2c62ada52c0df5fdc..396ec54a4f2b7f97e8209e2a60a428895c4a7ebf 100644 --- a/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx +++ b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx @@ -20,7 +20,7 @@ export const MapAdditionalActions = (): JSX.Element => { className="flex h-[48px] w-[48px] items-center justify-center rounded-full bg-white" onClick={zoomInToBioEntities} > - <Image src={locationIcon} alt="location icon" height={28} width={28} /> + <Image src={locationIcon} alt="location button icon" height={28} width={28} /> </button> <div className="flex h-auto w-[48px] flex-col items-center justify-center rounded-full bg-white py-2"> <button @@ -28,7 +28,7 @@ export const MapAdditionalActions = (): JSX.Element => { className="flex h-[48px] w-[48px] items-center justify-center" onClick={zoomIn} > - <Image src={magnifierZoomInIcon} alt="location icon" height={24} width={24} /> + <Image src={magnifierZoomInIcon} alt="zoom in button icon" height={24} width={24} /> </button> <div className="h-[1px] w-[32px] bg-[#F1F1F1]" /> <button @@ -36,7 +36,7 @@ export const MapAdditionalActions = (): JSX.Element => { className="flex h-[48px] w-[48px] items-center justify-center" onClick={zoomOut} > - <Image src={magnifierZoomOutIcon} alt="location icon" height={24} width={24} /> + <Image src={magnifierZoomOutIcon} alt="zoom out button icon" height={24} width={24} /> </button> </div> </div> diff --git a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..34986a2ecc9a1014912024d286fabd40f7def5ee --- /dev/null +++ b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts @@ -0,0 +1,52 @@ +import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; +import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; +import { renderHook } from '@testing-library/react'; +import { useAddtionalActions } from './useAdditionalActions'; + +describe('useAddtionalActions - hook', () => { + describe('on zoomIn', () => { + it('should dispatch varyPositionZoom action with valid delta', () => { + const { Wrapper, store } = getReduxStoreWithActionsListener(); + const { + result: { + current: { zoomIn }, + }, + } = renderHook(() => useAddtionalActions(), { + wrapper: Wrapper, + }); + + zoomIn(); + + const actions = store.getActions(); + expect(actions[FIRST_ARRAY_ELEMENT]).toStrictEqual({ + payload: { delta: 1 }, + type: 'map/varyPositionZoom', + }); + }); + }); + + describe('on zoomOut', () => { + it('should dispatch varyPositionZoom action with valid delta', () => { + const { Wrapper, store } = getReduxStoreWithActionsListener(); + const { + result: { + current: { zoomOut }, + }, + } = renderHook(() => useAddtionalActions(), { + wrapper: Wrapper, + }); + + zoomOut(); + + const actions = store.getActions(); + expect(actions[FIRST_ARRAY_ELEMENT]).toStrictEqual({ + payload: { delta: -1 }, + type: 'map/varyPositionZoom', + }); + }); + }); + + describe('on zoomInToBioEntities', () => { + // TODO: implelemnt test + }); +}); diff --git a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts index 51d307da5a6a8259ce4e1dda7baee29bec8de1dc..070d37d83be8bcb88a3ad8e509daad18127b10db 100644 --- a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts +++ b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts @@ -1,8 +1,5 @@ /* eslint-disable no-magic-numbers */ -import { searchedBioEntitesSelectorOfCurrentMap } from '@/redux/bioEntity/bioEntity.selectors'; -import { mapDataSizeSelector } from '@/redux/map/map.selectors'; import { useEffect } from 'react'; -import { useSelector } from 'react-redux'; import { MapConfig, MapInstance } from '../../MapViewer.types'; import { useOlMapOverlaysLayer } from './overlaysLayer/useOlMapOverlaysLayer'; import { useOlMapPinsLayer } from './pinsLayer/useOlMapPinsLayer'; @@ -18,8 +15,6 @@ export const useOlMapLayers = ({ mapInstance }: UseOlMapLayersInput): MapConfig[ const pinsLayer = useOlMapPinsLayer(); const reactionsLayer = useOlMapReactionsLayer(); const overlaysLayer = useOlMapOverlaysLayer(); - const contentBioEntites = useSelector(searchedBioEntitesSelectorOfCurrentMap); - const { maxZoom } = useSelector(mapDataSizeSelector); useEffect(() => { if (!mapInstance) { @@ -29,23 +24,5 @@ export const useOlMapLayers = ({ mapInstance }: UseOlMapLayersInput): MapConfig[ mapInstance.setLayers([tileLayer, reactionsLayer, pinsLayer, overlaysLayer]); }, [reactionsLayer, tileLayer, pinsLayer, mapInstance, overlaysLayer]); - useEffect(() => { - /* TODO: remove when poc not needed */ - if (!mapInstance || contentBioEntites.length === 0) { - return; - } - - const source = pinsLayer.getSource(); - if (source === null) { - return; - } - - const extent = source.getExtent(); - mapInstance.getView().fit(extent, { - size: mapInstance.getSize(), - maxZoom, - }); - }, [contentBioEntites, pinsLayer, mapInstance, maxZoom]); - return [tileLayer, pinsLayer, reactionsLayer, overlaysLayer]; }; diff --git a/src/redux/map/map.constants.ts b/src/redux/map/map.constants.ts index 5a4cd08479371a9042648c4ff07fe5bb9c279e98..27a63ef2a593b6e1fd2f031870ae4b489ba6ba25 100644 --- a/src/redux/map/map.constants.ts +++ b/src/redux/map/map.constants.ts @@ -6,7 +6,7 @@ import { DEFAULT_TILE_SIZE, } from '@/constants/map'; import { Point } from '@/types/map'; -import { MapData, OppenedMap } from './map.types'; +import { MapData, MapState, OppenedMap } from './map.types'; export const MAIN_MAP = 'Main map'; @@ -47,3 +47,10 @@ export const OPENED_MAPS_INITIAL_STATE: OppenedMap[] = [ ]; export const MIDDLEWARE_ALLOWED_ACTIONS: string[] = ['map/setMapData']; + +export const MAP_INITIAL_STATE: MapState = { + data: MAP_DATA_INITIAL_STATE, + loading: 'idle', + error: { name: '', message: '' }, + openedMaps: OPENED_MAPS_INITIAL_STATE, +}; diff --git a/src/redux/map/map.reducers.test.ts b/src/redux/map/map.reducers.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d711a41b2833a441d78de8f87362370d1797ef28 --- /dev/null +++ b/src/redux/map/map.reducers.test.ts @@ -0,0 +1,66 @@ +import { DEFAULT_CENTER_POINT, DEFAULT_TILE_SIZE } from '@/constants/map'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { MAP_DATA_INITIAL_STATE, MAP_INITIAL_STATE } from './map.constants'; +import { varyPositionZoom } from './map.slice'; + +describe('map reducers', () => { + describe('varyPositionZoomReducer', () => { + const baseMapSize = { + width: 0, + height: 0, + tileSize: DEFAULT_TILE_SIZE, + }; + + const cases: [ + { + minZoom: number; + maxZoom: number; + currentZ: number; + }, + { delta: number }, + { finalZ: number }, + ][] = [ + [{ minZoom: 1, maxZoom: 1, currentZ: 1 }, { delta: 1 }, { finalZ: 1 }], // exeeds the interval + [{ minZoom: 1, maxZoom: 1, currentZ: 1 }, { delta: -1 }, { finalZ: 1 }], // deceeds the interval + [{ minZoom: 1, maxZoom: 2, currentZ: 1 }, { delta: 1 }, { finalZ: 2 }], // inside the interval (with positive delta) + [{ minZoom: 0, maxZoom: 1, currentZ: 1 }, { delta: -1 }, { finalZ: 0 }], // inside the interval (with negative delta) + ]; + + it.each(cases)( + 'should set valid final z position', + ({ minZoom, maxZoom, currentZ }, { delta }, { finalZ }) => { + const { store } = getReduxWrapperWithStore({ + map: { + ...MAP_INITIAL_STATE, + data: { + ...MAP_DATA_INITIAL_STATE, + size: { + ...baseMapSize, + minZoom, + maxZoom, + }, + position: { + initial: { + ...DEFAULT_CENTER_POINT, + z: currentZ, + }, + last: { + ...DEFAULT_CENTER_POINT, + z: currentZ, + }, + }, + }, + }, + }); + + store.dispatch(varyPositionZoom({ delta })); + const newState = store.getState(); + const newInitialZ = newState.map.data.position.initial.z; + const newLastZ = newState.map.data.position.last.z; + + expect(newInitialZ).toEqual(finalZ); + expect(newLastZ).toEqual(finalZ); + }, + ); + }); +}); diff --git a/src/redux/map/map.slice.ts b/src/redux/map/map.slice.ts index d860047c32be379f34a4df10884991a91227f535..8fc687b9fb29301fc18cc15579ca40b6caef893f 100644 --- a/src/redux/map/map.slice.ts +++ b/src/redux/map/map.slice.ts @@ -1,5 +1,5 @@ import { createSlice } from '@reduxjs/toolkit'; -import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from './map.constants'; +import { MAP_INITIAL_STATE } from './map.constants'; import { closeMapAndSetMainMapActiveReducer, closeMapReducer, @@ -14,18 +14,10 @@ import { setMapPositionReducer, varyPositionZoomReducer, } from './map.reducers'; -import { MapState } from './map.types'; - -const initialState: MapState = { - data: MAP_DATA_INITIAL_STATE, - loading: 'idle', - error: { name: '', message: '' }, - openedMaps: OPENED_MAPS_INITIAL_STATE, -}; const mapSlice = createSlice({ name: 'map', - initialState, + initialState: MAP_INITIAL_STATE, reducers: { setMapData: setMapDataReducer, setActiveMap: setActiveMapReducer,