Skip to content
Snippets Groups Projects
Commit 22fbec74 authored by mateusz-winiarczyk's avatar mateusz-winiarczyk
Browse files

feat(export): elements download (MIN-157)

parent 2e797ddc
No related branches found
No related tags found
2 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!109feat(export): elements download (MIN-157)
Showing
with 444 additions and 261 deletions
......@@ -39,8 +39,8 @@ export const CheckboxFilter = ({
};
const handleCheckboxChange = (option: CheckboxItem): void => {
const newCheckedCheckboxes = checkedCheckboxes.includes(option)
? checkedCheckboxes.filter(item => item !== option)
const newCheckedCheckboxes = checkedCheckboxes.some(item => item.id === option.id)
? checkedCheckboxes.filter(item => item.id !== option.id)
: [...checkedCheckboxes, option];
setCheckedCheckboxes(newCheckedCheckboxes);
......
/* eslint-disable no-magic-numbers */
import { AppDispatch, RootState } from '@/redux/store';
import { InitialStoreState } from '@/utils/testing/getReduxWrapperWithStore';
import { render, screen } from '@testing-library/react';
import { CONFIGURATION_INITIAL_STORE_MOCK } from '@/redux/configuration/configuration.mock';
import { configurationFixture } from '@/models/fixtures/configurationFixture';
import { act } from 'react-dom/test-utils';
import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
import { compartmentPathwaysDetailsFixture } from '@/models/fixtures/compartmentPathways';
import { MockStoreEnhanced } from 'redux-mock-store';
import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
import { modelsFixture } from '@/models/fixtures/modelsFixture';
import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
import { apiPath } from '@/redux/apiPath';
import { HttpStatusCode } from 'axios';
import { Elements } from './Elements.component';
import { ELEMENTS_COLUMNS } from '../ExportCompound/ExportCompound.constant';
const mockedAxiosClient = mockNetworkNewAPIResponse();
const renderComponent = (
initialStore?: InitialStoreState,
): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => {
const { Wrapper, store } = getReduxStoreWithActionsListener(initialStore);
return (
render(
<Wrapper>
<Elements />
</Wrapper>,
),
{
store,
}
);
};
describe('Elements - component', () => {
it('should render all elements sections', () => {
renderComponent({
configuration: {
...CONFIGURATION_INITIAL_STORE_MOCK,
main: {
...CONFIGURATION_INITIAL_STORE_MOCK.main,
data: {
...configurationFixture,
miriamTypes: {
compartment_label: {
commonName: 'Compartment',
homepage: '',
registryIdentifier: '',
uris: [''],
},
},
},
},
},
statistics: {
data: {
...statisticsFixture,
elementAnnotations: {
compartment_label: 1,
pathway: 0,
},
},
loading: 'succeeded',
error: {
message: '',
name: '',
},
},
compartmentPathways: {
data: compartmentPathwaysDetailsFixture,
loading: 'succeeded',
error: {
message: '',
name: '',
},
},
});
const annotations = screen.getByText('Select annotations');
const includedCompartmentPathways = screen.getByText('Select included compartment / pathways');
const excludedCompartmentPathways = screen.getByText('Select excluded compartment / pathways');
const downloadButton = screen.getByText('Download');
expect(annotations).toBeVisible();
expect(includedCompartmentPathways).toBeVisible();
expect(excludedCompartmentPathways).toBeVisible();
expect(downloadButton).toBeVisible();
});
it('should handle download button click and dispatch proper data', async () => {
mockedAxiosClient.onPost(apiPath.downloadElementsCsv()).reply(HttpStatusCode.Ok, 'test');
const FIRST_COMPARMENT_PATHWAY_NAME = compartmentPathwaysDetailsFixture[0].name;
const FIRST_COMPARMENT_PATHWAY_ID = compartmentPathwaysDetailsFixture[0].id;
const SECOND_COMPARMENT_PATHWAY_NAME = compartmentPathwaysDetailsFixture[1].name;
const SECOND_COMPARMENT_PATHWAY_ID = compartmentPathwaysDetailsFixture[1].id;
const { store } = renderComponent({
configuration: {
...CONFIGURATION_INITIAL_STORE_MOCK,
main: {
...CONFIGURATION_INITIAL_STORE_MOCK.main,
data: {
...configurationFixture,
miriamTypes: {
compartment_label: {
commonName: 'Compartment',
homepage: '',
registryIdentifier: '',
uris: [''],
},
},
},
},
},
statistics: {
data: {
...statisticsFixture,
elementAnnotations: {
compartment_label: 1,
pathway: 0,
},
},
loading: 'succeeded',
error: {
message: '',
name: '',
},
},
compartmentPathways: {
data: compartmentPathwaysDetailsFixture,
loading: 'succeeded',
error: {
message: '',
name: '',
},
},
models: {
data: modelsFixture,
loading: 'succeeded',
error: {
message: '',
name: '',
},
},
});
const annotations = screen.getByText('Select annotations');
await act(() => {
annotations.click();
});
const annotationInput = screen.getByLabelText('Compartment');
await act(() => {
annotationInput.click();
});
expect(annotationInput).toBeChecked();
const includedCompartmentPathways = screen.getByText('Select included compartment / pathways');
await act(() => {
includedCompartmentPathways.click();
});
const includedCompartmentPathwaysInput = screen.getAllByLabelText(
FIRST_COMPARMENT_PATHWAY_NAME,
)[0];
await act(() => {
includedCompartmentPathwaysInput.click();
});
expect(includedCompartmentPathwaysInput).toBeChecked();
const excludedCompartmentPathways = screen.getByText('Select excluded compartment / pathways');
await act(() => {
excludedCompartmentPathways.click();
});
const excludedCompartmentPathwaysInput = screen.getAllByLabelText(
SECOND_COMPARMENT_PATHWAY_NAME,
)[1];
await act(() => {
excludedCompartmentPathwaysInput.click();
});
expect(excludedCompartmentPathwaysInput).toBeChecked();
const downloadButton = screen.getByText('Download');
await act(() => {
downloadButton.click();
});
const actions = store.getActions();
const firstAction = actions[0];
expect(firstAction.meta.arg).toEqual({
columns: ELEMENTS_COLUMNS,
submaps: modelsFixture.map(item => item.idObject),
annotations: ['compartment_label'],
includedCompartmentIds: [FIRST_COMPARMENT_PATHWAY_ID],
excludedCompartmentIds: [SECOND_COMPARMENT_PATHWAY_ID],
});
});
});
import { Export } from '../ExportCompound';
import { ANNOTATIONS_TYPE } from '../ExportCompound/ExportCompound.constant';
export const Elements = (): React.ReactNode => {
return (
<div data-testid="elements-tab">
<Export>
<Export.Types />
<Export.Columns />
<Export.Annotations />
<Export.Annotations type={ANNOTATIONS_TYPE.ELEMENTS} />
<Export.IncludedCompartmentPathways />
<Export.ExcludedCompartmentPathways />
<Export.DownloadElements />
......
......@@ -6,7 +6,10 @@ import {
import { StoreType } from '@/redux/store';
import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
import { act } from 'react-dom/test-utils';
import { CONFIGURATION_INITIAL_STORE_MOCK } from '@/redux/configuration/configuration.mock';
import { configurationFixture } from '@/models/fixtures/configurationFixture';
import { Annotations } from './Annotations.component';
import { ANNOTATIONS_TYPE } from '../ExportCompound.constant';
const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
......@@ -14,7 +17,7 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St
return (
render(
<Wrapper>
<Annotations />
<Annotations type={ANNOTATIONS_TYPE.ELEMENTS} />
</Wrapper>,
),
{
......@@ -26,11 +29,28 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St
describe('Annotations - component', () => {
it('should display annotations checkboxes when fetching data is successful', async () => {
renderComponent({
configuration: {
...CONFIGURATION_INITIAL_STORE_MOCK,
main: {
...CONFIGURATION_INITIAL_STORE_MOCK.main,
data: {
...configurationFixture,
miriamTypes: {
compartment_label: {
commonName: 'Compartment',
homepage: '',
registryIdentifier: '',
uris: [''],
},
},
},
},
},
statistics: {
data: {
...statisticsFixture,
elementAnnotations: {
compartment: 1,
compartment_label: 1,
pathway: 0,
},
},
......@@ -54,7 +74,7 @@ describe('Annotations - component', () => {
await waitFor(() => {
expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument();
expect(screen.getByLabelText('compartment')).toBeInTheDocument();
expect(screen.getByLabelText('Compartment')).toBeInTheDocument();
expect(screen.getByLabelText('search-input')).toBeInTheDocument();
});
});
......
import { useContext } from 'react';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import {
elementAnnotationsSelector,
loadingStatisticsSelector,
statisticsDataSelector,
} from '@/redux/statistics/statistics.selectors';
import { ZERO } from '@/constants/common';
import { miramiTypesSelector } from '@/redux/configuration/configuration.selectors';
import { CheckboxFilter } from '../../CheckboxFilter';
import { CollapsibleSection } from '../../CollapsibleSection';
import { ExportContext } from '../ExportCompound.context';
import { getAnnotationsCheckboxElements } from './Annotations.utils';
import { AnnotationsType } from './Annotations.types';
export const Annotations = (): React.ReactNode => {
type AnnotationsProps = {
type: AnnotationsType;
};
export const Annotations = ({ type }: AnnotationsProps): React.ReactNode => {
const { setAnnotations } = useContext(ExportContext);
const loadingStatistics = useAppSelector(loadingStatisticsSelector);
const elementAnnotations = useAppSelector(elementAnnotationsSelector);
const statistics = useAppSelector(statisticsDataSelector);
const miramiTypes = useAppSelector(miramiTypesSelector);
const isPending = loadingStatistics === 'pending';
const mappedElementAnnotations = elementAnnotations
? Object.keys(elementAnnotations)?.map(el => ({ id: el, label: el }))
: [];
const checkboxElements = getAnnotationsCheckboxElements({ type, statistics, miramiTypes });
return (
<CollapsibleSection title="Select annotations">
{isPending && <p>Loading...</p>}
{!isPending && mappedElementAnnotations && mappedElementAnnotations.length > ZERO && (
<CheckboxFilter options={mappedElementAnnotations} onCheckedChange={setAnnotations} />
{!isPending && checkboxElements && checkboxElements.length > ZERO && (
<CheckboxFilter options={checkboxElements} onCheckedChange={setAnnotations} />
)}
</CollapsibleSection>
);
......
import { ANNOTATIONS_TYPE } from '../ExportCompound.constant';
export type AnnotationsType = (typeof ANNOTATIONS_TYPE)[keyof typeof ANNOTATIONS_TYPE];
import { getAnnotationsCheckboxElements } from './Annotations.utils';
describe('getAnnotationsCheckboxElements', () => {
const statisticsMock = {
elementAnnotations: {
chebi: 2,
mesh: 0,
reactome: 1,
},
publications: 1234,
reactionAnnotations: {
brenda: 0,
reactome: 3,
rhea: 1,
},
};
const miramiTypeMock = {
commonName: 'Name',
homepage: '',
registryIdentifier: '',
uris: [''],
};
const miramiTypesMock = {
chebi: {
...miramiTypeMock,
commonName: 'Chebi',
},
mesh: {
...miramiTypeMock,
commonName: 'MeSH',
},
reactome: {
...miramiTypeMock,
commonName: 'Reactome',
},
rhea: {
...miramiTypeMock,
commonName: 'Rhea',
},
brenda: {
...miramiTypeMock,
commonName: 'BRENDA',
},
gene_ontology: {
...miramiTypeMock,
commonName: 'Gene Ontology',
},
};
it('returns an empty array when statistics or miramiTypes are undefined', () => {
const result = getAnnotationsCheckboxElements({
type: 'Elements',
statistics: undefined,
miramiTypes: undefined,
});
expect(result).toEqual([]);
});
it('returns checkbox elements for element annotations sorted by label', () => {
const result = getAnnotationsCheckboxElements({
type: 'Elements',
statistics: statisticsMock,
miramiTypes: miramiTypesMock,
});
expect(result).toEqual([
{ id: 'chebi', label: 'Chebi' },
{ id: 'reactome', label: 'Reactome' },
]);
});
it('returns checkbox elements for reaction annotations sorted by count', () => {
const result = getAnnotationsCheckboxElements({
type: 'Network',
statistics: statisticsMock,
miramiTypes: miramiTypesMock,
});
expect(result).toEqual([
{ id: 'reactome', label: 'Reactome' },
{ id: 'rhea', label: 'Rhea' },
]);
});
it('returns an empty array when no annotations have count greater than 0', () => {
const statisticsMockEmpty = {
elementAnnotations: { annotation1: 0, annotation2: 0 },
publications: 0,
reactionAnnotations: { annotation1: 0, annotation2: 0 },
};
const result = getAnnotationsCheckboxElements({
type: 'Elements',
statistics: statisticsMockEmpty,
miramiTypes: miramiTypesMock,
});
expect(result).toEqual([]);
});
});
/* eslint-disable no-magic-numbers */
import { ConfigurationMiramiTypes, Statistics } from '@/types/models';
import { ANNOTATIONS_TYPE } from '../ExportCompound.constant';
import { AnnotationsType } from './Annotations.types';
type CheckboxElement = { id: string; label: string };
type CheckboxElements = CheckboxElement[];
type GetAnnotationsCheckboxElements = {
type: AnnotationsType;
statistics: Statistics | undefined;
miramiTypes: ConfigurationMiramiTypes | undefined;
};
const sortByCount = (countA: number, countB: number): number => {
return countA > countB ? -1 : 1;
};
const mapToCheckboxElement = (
annotation: string,
miramiTypes: ConfigurationMiramiTypes,
): CheckboxElement => ({
id: annotation,
label: miramiTypes[annotation].commonName,
});
const filterAnnotationsByCount = (annotations: Record<string, number>): string[] => {
return Object.keys(annotations).filter(annotation => annotations[annotation] > 0);
};
export const getAnnotationsCheckboxElements = ({
type,
statistics,
miramiTypes,
}: GetAnnotationsCheckboxElements): CheckboxElements => {
if (!statistics || !miramiTypes) return [];
const annotations =
type === ANNOTATIONS_TYPE.ELEMENTS
? statistics.elementAnnotations
: statistics.reactionAnnotations;
const availableAnnotations = filterAnnotationsByCount(annotations);
return availableAnnotations
.sort((firstAnnotation, secondAnnotation) =>
sortByCount(annotations[firstAnnotation], annotations[secondAnnotation]),
)
.map(annotation => mapToCheckboxElement(annotation, miramiTypes));
};
import { render, screen } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import { Columns } from './Columns.component';
describe('Columns - component', () => {
it('should display select column accordion', async () => {
render(<Columns />);
expect(screen.getByText('Select column')).toBeInTheDocument();
expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
});
it('should display columns checkboxes', async () => {
render(<Columns />);
expect(screen.getByText('Select column')).toBeInTheDocument();
expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
const navigationButton = screen.getByTestId('accordion-item-button');
act(() => {
navigationButton.click();
});
expect(screen.queryByTestId('checkbox-filter')).toBeVisible();
expect(screen.queryByLabelText('References')).toBeVisible();
});
});
import { useContext } from 'react';
import { CheckboxFilter } from '../../CheckboxFilter';
import { CollapsibleSection } from '../../CollapsibleSection';
import { COLUMNS } from './Columns.constants';
import { ExportContext } from '../ExportCompound.context';
export const Columns = (): React.ReactNode => {
const { setColumns } = useContext(ExportContext);
return (
<CollapsibleSection title="Select column">
<CheckboxFilter options={COLUMNS} isSearchEnabled={false} onCheckedChange={setColumns} />
</CollapsibleSection>
);
};
export const COLUMNS = [
{
id: 'id',
label: 'ID',
},
{
id: 'description',
label: 'Description',
},
{
id: 'modelId',
label: 'Map id',
},
{
id: 'mapName',
label: 'Map name',
},
{
id: 'symbol',
label: 'Symbol',
},
{
id: 'abbreviation',
label: 'Abbreviation',
},
{
id: 'synonyms',
label: 'Synonyms',
},
{
id: 'references',
label: 'References',
},
{
id: 'name',
label: 'Name',
},
{
id: 'type',
label: 'Type',
},
{
id: 'complexId',
label: 'Complex id',
},
{
id: 'complexName',
label: 'Complex name',
},
{
id: 'compartmentId',
label: 'Compartment/Pathway id',
},
{
id: 'compartmentName',
label: 'Compartment/Pathway name',
},
{
id: 'charge',
label: 'Charge',
},
{
id: 'fullName',
label: 'Full name',
},
{
id: 'formula',
label: 'Formula',
},
{
id: 'formerSymbols',
label: 'Former symbols',
},
{
id: 'linkedSubmodelId',
label: 'Linked submap id',
},
{
id: 'elementId',
label: 'Element external id',
},
{
id: 'ALL',
label: 'All',
},
];
export { Columns } from './Columns.component';
......@@ -15,7 +15,7 @@ export const ExcludedCompartmentPathways = (): React.ReactNode => {
const loadingCompartmentPathways = useAppSelector(loadingCompartmentPathwaysSelector);
const isPending = loadingCompartmentPathways === 'pending';
const compartmentPathways = useAppSelector(compartmentPathwaysDataSelector);
const checkboxElements = getCompartmentPathwaysCheckboxElements(compartmentPathways);
const checkboxElements = getCompartmentPathwaysCheckboxElements('excluded', compartmentPathways);
const isCheckboxFilterVisible = !isPending && checkboxElements && checkboxElements.length > ZERO;
return (
......
import { ReactNode, useCallback, useMemo, useState } from 'react';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { modelsIdsSelector } from '@/redux/models/models.selectors';
import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
import { downloadElements } from '@/redux/export/export.thunks';
import { CheckboxItem } from '../CheckboxFilter/CheckboxFilter.component';
import { Types } from './Types';
import { Columns } from './Columns';
import { Annotations } from './Annotations';
import { ExcludedCompartmentPathways } from './ExcludedCompartmentPathways';
import { IncludedCompartmentPathways } from './IncludedCompartmentPathways ';
......@@ -11,14 +11,14 @@ import { DownloadElements } from './DownloadElements/DownloadElements';
import { ExportContext } from './ExportCompound.context';
import { getNetworkDownloadBodyRequest } from './utils/getNetworkBodyRequest';
import { getDownloadElementsBodyRequest } from './utils/getDownloadElementsBodyRequest';
import { ELEMENTS_COLUMNS } from './ExportCompound.constant';
type ExportProps = {
children: ReactNode;
};
export const Export = ({ children }: ExportProps): JSX.Element => {
const [types, setTypes] = useState<CheckboxItem[]>([]);
const [columns, setColumns] = useState<CheckboxItem[]>([]);
const dispatch = useAppDispatch();
const [annotations, setAnnotations] = useState<CheckboxItem[]>([]);
const modelIds = useAppSelector(modelsIdsSelector);
const [includedCompartmentPathways, setIncludedCompartmentPathways] = useState<CheckboxItem[]>(
......@@ -28,23 +28,17 @@ export const Export = ({ children }: ExportProps): JSX.Element => {
[],
);
const handleDownloadElements = useCallback(() => {
getDownloadElementsBodyRequest({
types,
columns,
const handleDownloadElements = useCallback(async () => {
const body = getDownloadElementsBodyRequest({
columns: ELEMENTS_COLUMNS,
modelIds,
annotations,
includedCompartmentPathways,
excludedCompartmentPathways,
});
}, [
types,
columns,
modelIds,
annotations,
includedCompartmentPathways,
excludedCompartmentPathways,
]);
dispatch(downloadElements(body));
}, [modelIds, annotations, includedCompartmentPathways, excludedCompartmentPathways, dispatch]);
const handleDownloadNetwork = useCallback(() => {
getNetworkDownloadBodyRequest();
......@@ -52,8 +46,6 @@ export const Export = ({ children }: ExportProps): JSX.Element => {
const globalContextValue = useMemo(
() => ({
setTypes,
setColumns,
setAnnotations,
setIncludedCompartmentPathways,
setExcludedCompartmentPathways,
......@@ -66,8 +58,6 @@ export const Export = ({ children }: ExportProps): JSX.Element => {
return <ExportContext.Provider value={globalContextValue}>{children}</ExportContext.Provider>;
};
Export.Types = Types;
Export.Columns = Columns;
Export.Annotations = Annotations;
Export.IncludedCompartmentPathways = IncludedCompartmentPathways;
Export.ExcludedCompartmentPathways = ExcludedCompartmentPathways;
......
export const ANNOTATIONS_TYPE = {
ELEMENTS: 'Elements',
NETWORK: 'Network',
} as const;
export const COLUMNS_TYPE = {
ELEMENTS: 'Elements',
NETWORK: 'Network',
} as const;
export const ELEMENTS_COLUMNS = [
'id',
'type',
'name',
'symbol',
'abbreviation',
'fullName',
'synonyms',
'formerSymbols',
'complexId',
'complexName',
'compartmentId',
'compartmentName',
'modelId',
'mapName',
'description',
'references',
'charge',
'formula',
'linkedSubmodelId',
'elementId',
];
......@@ -2,8 +2,6 @@ import { createContext } from 'react';
import { CheckboxItem } from '../CheckboxFilter/CheckboxFilter.component';
export type ExportContextType = {
setTypes: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
setColumns: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
setAnnotations: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
setIncludedCompartmentPathways: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
setExcludedCompartmentPathways: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
......@@ -12,8 +10,6 @@ export type ExportContextType = {
};
export const ExportContext = createContext<ExportContextType>({
setTypes: () => {},
setColumns: () => {},
setAnnotations: () => {},
setIncludedCompartmentPathways: () => {},
setExcludedCompartmentPathways: () => {},
......
......@@ -15,7 +15,7 @@ export const IncludedCompartmentPathways = (): React.ReactNode => {
const loadingCompartmentPathways = useAppSelector(loadingCompartmentPathwaysSelector);
const isPending = loadingCompartmentPathways === 'pending';
const compartmentPathways = useAppSelector(compartmentPathwaysDataSelector);
const checkboxElements = getCompartmentPathwaysCheckboxElements(compartmentPathways);
const checkboxElements = getCompartmentPathwaysCheckboxElements('included', compartmentPathways);
return (
<CollapsibleSection title="Select included compartment / pathways">
......
import { render, screen } from '@testing-library/react';
import {
InitialStoreState,
getReduxWrapperWithStore,
} from '@/utils/testing/getReduxWrapperWithStore';
import { StoreType } from '@/redux/store';
import { Types } from './Types.component';
const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
return (
render(
<Wrapper>
<Types />
</Wrapper>,
),
{
store,
}
);
};
describe('Types Component', () => {
test('renders without crashing', () => {
renderComponent();
expect(screen.getByText('Select types')).toBeInTheDocument();
});
});
import { useContext } from 'react';
import { elementTypesSelector } from '@/redux/configuration/configuration.selectors';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { getCheckboxElements } from './Types.utils';
import { CheckboxFilter } from '../../CheckboxFilter';
import { CollapsibleSection } from '../../CollapsibleSection';
import { ExportContext } from '../ExportCompound.context';
export const Types = (): React.ReactNode => {
const { setTypes } = useContext(ExportContext);
const elementTypes = useAppSelector(elementTypesSelector);
const checkboxElements = getCheckboxElements(elementTypes);
return (
<CollapsibleSection title="Select types">
{checkboxElements && (
<CheckboxFilter
options={checkboxElements}
isSearchEnabled={false}
onCheckedChange={setTypes}
/>
)}
</CollapsibleSection>
);
};
import { getCheckboxElements } from './Types.utils';
describe('getCheckboxElements', () => {
it('should return an empty array when elementTypes is undefined', () => {
const result = getCheckboxElements(undefined);
expect(result).toEqual([]);
});
it('should map elementTypes to MappedElementTypes and exclude duplicates based on name and parentClass', () => {
const elementTypes = [
{ className: 'class1', name: 'type1', parentClass: 'parent1' },
{ className: 'class2', name: 'type2', parentClass: 'parent2' },
{ className: 'class1', name: 'type1', parentClass: 'parent1' },
{ className: 'class3', name: 'type3', parentClass: 'parent3' },
{ className: 'class2', name: 'type2', parentClass: 'parent2' },
];
const result = getCheckboxElements(elementTypes);
expect(result).toEqual([
{ id: 'type1', label: 'type1' },
{ id: 'type2', label: 'type2' },
{ id: 'type3', label: 'type3' },
]);
});
it('should handle an empty array of elementTypes', () => {
const result = getCheckboxElements([]);
expect(result).toEqual([]);
});
it('should return an empty array when elementTypes is undefined', () => {
const result = getCheckboxElements(undefined);
expect(result).toEqual([]);
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment