From 359c31b8a8fffb41047d3972e38599a804f36f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Or=C5=82=C3=B3w?= <adrian.orlow@fishbrain.com> Date: Fri, 2 Feb 2024 01:59:34 +0100 Subject: [PATCH] feat: add rfc changes --- .../ImageSize/utils/useImageSize.ts | 6 +- .../Submap/Submap.component.test.tsx | 116 ++++++++++++++++++ .../Submap/Submap.component.tsx | 4 +- .../utils/getModelExportZoom.ts | 6 + src/redux/apiPath.ts | 2 +- .../configuration/configuration.selectors.ts | 7 +- src/utils/number/numberToInt.ts | 2 +- 7 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.test.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.ts index da0c0c56..f36afdd3 100644 --- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.ts +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.ts @@ -1,5 +1,5 @@ import { MapModel } from '@/types/models'; -import { numberToInt } from '@/utils/number/numberToInt'; +import { numberToSafeInt } from '@/utils/number/numberToInt'; import { useCallback, useContext, useEffect } from 'react'; import { ExportContext } from '../../ExportCompound.context'; import { DEFAULT_IMAGE_HEIGHT, DEFAULT_IMAGE_WIDTH } from '../ImageSize.constants'; @@ -30,8 +30,8 @@ export const useImageSize = (): UseImageSizeResults => { const widthMinMax = Math.min(maxWidth, newWidth); const heightMinMax = Math.min(maxHeight, newHeight); - const widthInt = numberToInt(widthMinMax); - const heightInt = numberToInt(heightMinMax); + const widthInt = numberToSafeInt(widthMinMax); + const heightInt = numberToSafeInt(heightMinMax); return { width: widthInt, diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.test.tsx new file mode 100644 index 00000000..2374285d --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.test.tsx @@ -0,0 +1,116 @@ +/* eslint-disable no-magic-numbers */ +import { modelsFixture } from '@/models/fixtures/modelsFixture'; +import { StoreType } from '@/redux/store'; +import { + InitialStoreState, + getReduxWrapperWithStore, +} from '@/utils/testing/getReduxWrapperWithStore'; +import { render, screen, waitFor } from '@testing-library/react'; +import { act } from 'react-dom/test-utils'; +import { Submap } from './Submap.component'; + +const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { + const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState); + + return ( + render( + <Wrapper> + <Submap /> + </Wrapper>, + ), + { + store, + } + ); +}; + +const CHECKBOX_ELEMENT_NAME = modelsFixture[0].name; + +describe('Submap - component', () => { + it('should display submaps checkboxes when fetching data is successful', async () => { + renderComponent({ + models: { + data: modelsFixture, + loading: 'succeeded', + error: { + message: '', + name: '', + }, + }, + }); + + expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible(); + + const navigationButton = screen.getByTestId('accordion-item-button'); + + act(() => { + navigationButton.click(); + }); + + expect(screen.getByText('Submap')).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument(); + expect(screen.getByLabelText('search-input')).toBeInTheDocument(); + expect(screen.getByLabelText(CHECKBOX_ELEMENT_NAME)).toBeInTheDocument(); + }); + }); + it('should not display submaps checkboxes when fetching data fails', async () => { + renderComponent({ + models: { + data: [], + loading: 'failed', + error: { + message: '', + name: '', + }, + }, + }); + expect(screen.getByText('Submap')).toBeInTheDocument(); + const navigationButton = screen.getByTestId('accordion-item-button'); + act(() => { + navigationButton.click(); + }); + + expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument(); + }); + it('should not display submaps checkboxes when fetched data is empty', async () => { + renderComponent({ + models: { + data: [], + loading: 'succeeded', + error: { + message: '', + name: '', + }, + }, + }); + expect(screen.getByText('Submap')).toBeInTheDocument(); + const navigationButton = screen.getByTestId('accordion-item-button'); + act(() => { + navigationButton.click(); + }); + + expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument(); + }); + + it('should display loading message when fetching data is pending', async () => { + renderComponent({ + models: { + data: [], + loading: 'pending', + error: { + message: '', + name: '', + }, + }, + }); + expect(screen.getByText('Submap')).toBeInTheDocument(); + const navigationButton = screen.getByTestId('accordion-item-button'); + act(() => { + navigationButton.click(); + }); + + expect(screen.getByText('Loading...')).toBeInTheDocument(); + }); +}); diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.tsx index 98546f37..5c5590ce 100644 --- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.tsx @@ -8,7 +8,7 @@ import { ExportContext } from '../ExportCompound.context'; export const Submap = (): React.ReactNode => { const { setModels, data } = useContext(ExportContext); - const currentModels = data.models; + const currentSelectedModels = data.models; const models = useAppSelector(modelsDataSelector); const loadingModels = useAppSelector(loadingModelsSelector); const isPending = loadingModels === 'pending'; @@ -24,7 +24,7 @@ export const Submap = (): React.ReactNode => { {!isPending && mappedElementAnnotations && mappedElementAnnotations.length > ZERO && ( <CheckboxFilter options={mappedElementAnnotations} - currentOptions={currentModels} + currentOptions={currentSelectedModels} onCheckedChange={setModels} type="radio" /> diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.ts index 3f894dc1..c198def1 100644 --- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.ts +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.ts @@ -3,6 +3,12 @@ import { MapModel } from '@/types/models'; const ZOOM_BASE = 6; +/* + * Width of exported image for zoom=1 is 128, for zoom=2 is 256, for zoom=3 is 1024 + * So zoom level holds pattern of log2(width) with base of log2(128)=7 + * Zoom base defined in this file is 6 as we need to provide minumum zoom of 1 + */ + export const getModelExportZoom = (exportWidth: number, model?: MapModel): number => { // log2 of zero is -Infty if (!model || model.width === ZERO) { diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts index 212660e5..c6cb7455 100644 --- a/src/redux/apiPath.ts +++ b/src/redux/apiPath.ts @@ -1,6 +1,6 @@ import { PROJECT_ID } from '@/constants'; -import { PerfectSearchParams } from '@/types/search'; import { Point } from '@/types/map'; +import { PerfectSearchParams } from '@/types/search'; export const apiPath = { getBioEntityContentsStringWithQuery: ({ diff --git a/src/redux/configuration/configuration.selectors.ts b/src/redux/configuration/configuration.selectors.ts index 69942398..25cbfbfa 100644 --- a/src/redux/configuration/configuration.selectors.ts +++ b/src/redux/configuration/configuration.selectors.ts @@ -101,12 +101,7 @@ export const imageFormatsEntriesSelector = createSelector( imageFormatsSelector, (modelFormats): Record<string, ConfigurationFormatSchema> => { return Object.fromEntries( - (modelFormats || []) - .flat() - .filter((format: ConfigurationFormatSchema): format is ConfigurationFormatSchema => - Boolean(format), - ) - .map((format: ConfigurationFormatSchema) => [format.name, format]), + (modelFormats || []).flat().map((format: ConfigurationFormatSchema) => [format.name, format]), ); }, ); diff --git a/src/utils/number/numberToInt.ts b/src/utils/number/numberToInt.ts index 0f69af1e..b57608e0 100644 --- a/src/utils/number/numberToInt.ts +++ b/src/utils/number/numberToInt.ts @@ -1,6 +1,6 @@ import { ZERO } from '@/constants/common'; -export const numberToInt = (num: number): number => { +export const numberToSafeInt = (num: number): number => { // zero or NaN if (!num) { return ZERO; -- GitLab