diff --git a/junit.xml b/junit.xml index 846dab503757c90ed17bb99230b16efe58010219..3b36f09668f0862b35716742613e324ed5a14754 100644 --- a/junit.xml +++ b/junit.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<testsuites name="jest tests" tests="443" failures="0" errors="0" time="7.886"> - <testsuite name="search reducer" errors="0" failures="0" skipped="4" timestamp="2024-01-03T15:35:18" time="0.92" tests="4"> +<testsuites name="jest tests" tests="594" failures="0" errors="0" time="12.487"> + <testsuite name="search reducer" errors="0" failures="0" skipped="4" timestamp="2024-01-12T14:39:36" time="0.696" tests="4"> <testcase classname="search reducer should match initial state" name="search reducer should match initial state" time="0"> <skipped/> </testcase> @@ -14,674 +14,976 @@ <skipped/> </testcase> </testsuite> - <testsuite name="AssociatedSubmap - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:18" time="1.755" tests="4"> - <testcase classname="AssociatedSubmap - component should not display component when can not find asociated map model" name="AssociatedSubmap - component should not display component when can not find asociated map model" time="0.012"> + <testsuite name="LegendImages - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:36" time="1.32" tests="4"> + <testcase classname="LegendImages - component when current images are empty should render empty container" name="LegendImages - component when current images are empty should render empty container" time="0.035"> </testcase> - <testcase classname="AssociatedSubmap - component should render component when associated map model is found" name="AssociatedSubmap - component should render component when associated map model is found" time="0.008"> + <testcase classname="LegendImages - component when current images are present should render img element, partialUrl=url1/image.png" name="LegendImages - component when current images are present should render img element, partialUrl=url1/image.png" time="0.005"> </testcase> - <testcase classname="AssociatedSubmap - component when map is already opened should open submap and set it to active on open submap button click" name="AssociatedSubmap - component when map is already opened should open submap and set it to active on open submap button click" time="0.041"> + <testcase classname="LegendImages - component when current images are present should render img element, partialUrl=url2/image.png" name="LegendImages - component when current images are present should render img element, partialUrl=url2/image.png" time="0.003"> </testcase> - <testcase classname="AssociatedSubmap - component when map is already opened should set map active on open submap button click" name="AssociatedSubmap - component when map is already opened should set map active on open submap button click" time="0.013"> + <testcase classname="LegendImages - component when current images are present should render img element, partialUrl=url3/image.png" name="LegendImages - component when current images are present should render img element, partialUrl=url3/image.png" time="0.003"> </testcase> </testsuite> - <testsuite name="PinsListItem - component " errors="0" failures="0" skipped="1" timestamp="2024-01-03T15:35:18" time="1.751" tests="6"> - <testcase classname="PinsListItem - component should display full name of pin" name="PinsListItem - component should display full name of pin" time="0.023"> + <testsuite name="OverviewImagesModal - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:36" time="1.345" tests="4"> + <testcase classname="OverviewImagesModal - component when currentImage is NOT valid should not render component" name="OverviewImagesModal - component when currentImage is NOT valid should not render component" time="0.018"> </testcase> - <testcase classname="PinsListItem - component should display list of elements for pin for drugs" name="PinsListItem - component should display list of elements for pin for drugs" time="0.005"> + <testcase classname="OverviewImagesModal - component when currentImage is valid should render component" name="OverviewImagesModal - component when currentImage is valid should render component" time="0.036"> </testcase> - <testcase classname="PinsListItem - component should display list of references for pin" name="PinsListItem - component should display list of references for pin" time="0.005"> + <testcase classname="OverviewImagesModal - component when currentImage is valid should render image with valid src" name="OverviewImagesModal - component when currentImage is valid should render image with valid src" time="0.009"> </testcase> - <testcase classname="PinsListItem - component should display list of elements for pin for chemicals" name="PinsListItem - component should display list of elements for pin for chemicals" time="0.005"> + <testcase classname="OverviewImagesModal - component when currentImage is valid should render image wrapper with valid size" name="OverviewImagesModal - component when currentImage is valid should render image wrapper with valid size" time="0.009"> </testcase> - <testcase classname="PinsListItem - component should not display list of elements for pin for bioentities" name="PinsListItem - component should not display list of elements for pin for bioentities" time="0"> - <skipped/> + </testsuite> + <testsuite name="TopBar - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:36" time="1.54" tests="3"> + <testcase classname="TopBar - component Should contain user avatar, search bar" name="TopBar - component Should contain user avatar, search bar" time="0.037"> + </testcase> + <testcase classname="TopBar - component should open submaps drawer on submaps button click" name="TopBar - component should open submaps drawer on submaps button click" time="0.144"> </testcase> - <testcase classname="PinsListItem - component should not display list of available submaps for pin when there aren't any submaps" name="PinsListItem - component should not display list of available submaps for pin when there aren't any submaps" time="0.007"> + <testcase classname="TopBar - component should open overlays drawer on overlays button click" name="TopBar - component should open overlays drawer on overlays button click" time="0.047"> </testcase> </testsuite> - <testsuite name="BioEntitiesSubmapItem - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:18" time="1.813" tests="4"> - <testcase classname="BioEntitiesSubmapItem - component should display map name, number of elements, icon" name="BioEntitiesSubmapItem - component should display map name, number of elements, icon" time="0.022"> + <testsuite name="useInitializeStore - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:36" time="1.683" tests="5"> + <testcase classname="useInitializeStore - hook when fired should fetch project data in store" name="useInitializeStore - hook when fired should fetch project data in store" time="0.169"> + </testcase> + <testcase classname="useInitializeStore - hook when fired should fetch backgrounds data in store" name="useInitializeStore - hook when fired should fetch backgrounds data in store" time="0.058"> </testcase> - <testcase classname="BioEntitiesSubmapItem - component should navigate user to bio enitites results list after clicking button" name="BioEntitiesSubmapItem - component should navigate user to bio enitites results list after clicking button" time="0.06"> + <testcase classname="useInitializeStore - hook when fired should fetch overlays data in store" name="useInitializeStore - hook when fired should fetch overlays data in store" time="0.059"> </testcase> - <testcase classname="BioEntitiesSubmapItem - component should open submap and set it to active if it's not already opened" name="BioEntitiesSubmapItem - component should open submap and set it to active if it's not already opened" time="0.014"> + <testcase classname="useInitializeStore - hook when fired should fetch models data in store" name="useInitializeStore - hook when fired should fetch models data in store" time="0.07"> </testcase> - <testcase classname="BioEntitiesSubmapItem - component should set map active if it's already opened" name="BioEntitiesSubmapItem - component should set map active if it's already opened" time="0.012"> + <testcase classname="useInitializeStore - hook when fired should use valid initialize value" name="useInitializeStore - hook when fired should use valid initialize value" time="0.026"> </testcase> </testsuite> - <testsuite name="BioEntityDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:18" time="1.825" tests="6"> - <testcase classname="BioEntityDrawer - component when there's NO matching bioEntity should not show drawer content" name="BioEntityDrawer - component when there's NO matching bioEntity should not show drawer content" time="0.027"> + <testsuite name="MapNavigation - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:36" time="1.758" tests="4"> + <testcase classname="MapNavigation - component should render list of currently opened maps, main map should not have close button" name="MapNavigation - component should render list of currently opened maps, main map should not have close button" time="0.205"> </testcase> - <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should show drawer header" name="BioEntityDrawer - component when there IS a matching bioEntity should show drawer header" time="0.048"> + <testcase classname="MapNavigation - component all maps should have close button expect main map" name="MapNavigation - component all maps should have close button expect main map" time="0.148"> </testcase> - <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should show drawer bioEntity full name" name="BioEntityDrawer - component when there IS a matching bioEntity should show drawer bioEntity full name" time="0.003"> + <testcase classname="MapNavigation - component should close map tab when clicking on close button while" name="MapNavigation - component should close map tab when clicking on close button while" time="0.044"> </testcase> - <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should not show drawer bioEntity full name if it doesn't exists" name="BioEntityDrawer - component when there IS a matching bioEntity should not show drawer bioEntity full name if it doesn't exists" time="0.004"> + <testcase classname="MapNavigation - component should close map and open main map if closed currently selected map" name="MapNavigation - component should close map and open main map if closed currently selected map" time="0.073"> </testcase> - <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should show list of annotations " name="BioEntityDrawer - component when there IS a matching bioEntity should show list of annotations " time="0.015"> + </testsuite> + <testsuite name="UserOverlayForm - Component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:36" time="1.782" tests="7"> + <testcase classname="UserOverlayForm - Component renders the UserOverlayForm component" name="UserOverlayForm - Component renders the UserOverlayForm component" time="0.068"> </testcase> - <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should display associated submaps if bio entity links to submap" name="BioEntityDrawer - component when there IS a matching bioEntity should display associated submaps if bio entity links to submap" time="0.004"> + <testcase classname="UserOverlayForm - Component should submit the form with elements list when upload button is clicked" name="UserOverlayForm - Component should submit the form with elements list when upload button is clicked" time="0.137"> </testcase> - </testsuite> - <testsuite name="onMapSingleClick - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:18" time="1.864" tests="5"> - <testcase classname="onMapSingleClick - util when always should fire data reset handler" name="onMapSingleClick - util when always should fire data reset handler" time="0.012"> + <testcase classname="UserOverlayForm - Component should create correct name for file which contains elements list as content" name="UserOverlayForm - Component should create correct name for file which contains elements list as content" time="0.031"> </testcase> - <testcase classname="onMapSingleClick - util when searchResults are undefined does not fire search result action" name="onMapSingleClick - util when searchResults are undefined does not fire search result action" time="0.001"> + <testcase classname="UserOverlayForm - Component should update the form inputs based on overlay content provided by elements list" name="UserOverlayForm - Component should update the form inputs based on overlay content provided by elements list" time="0.062"> </testcase> - <testcase classname="onMapSingleClick - util when searchResults are empty does not fire search result action" name="onMapSingleClick - util when searchResults are empty does not fire search result action" time="0.001"> + <testcase classname="UserOverlayForm - Component should display correct filename" name="UserOverlayForm - Component should display correct filename" time="0.087"> </testcase> - <testcase classname="onMapSingleClick - util when searchResults are valid when results type is ALIAS does fire search result action handler" name="onMapSingleClick - util when searchResults are valid when results type is ALIAS does fire search result action handler" time="0.004"> + <testcase classname="UserOverlayForm - Component should not submit when form is not filled" name="UserOverlayForm - Component should not submit when form is not filled" time="0.011"> </testcase> - <testcase classname="onMapSingleClick - util when searchResults are valid when results type is REACTION does fire search result action - handle reaction" name="onMapSingleClick - util when searchResults are valid when results type is REACTION does fire search result action - handle reaction" time="0.003"> + <testcase classname="UserOverlayForm - Component should navigate to overlays after clicking backward button" name="UserOverlayForm - Component should navigate to overlays after clicking backward button" time="0.033"> </testcase> </testsuite> - <testsuite name="MapNavigation - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:18" time="1.979" tests="4"> - <testcase classname="MapNavigation - component should render list of currently opened maps, main map should not have close button" name="MapNavigation - component should render list of currently opened maps, main map should not have close button" time="0.162"> + <testsuite name="useOlMapListeners - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:36" time="2.358" tests="2"> + <testcase classname="useOlMapListeners - util on change:center view event should run onMapPositionChange event" name="useOlMapListeners - util on change:center view event should run onMapPositionChange event" time="0.026"> + </testcase> + <testcase classname="useOlMapListeners - util on singleclick view event should run onMapPositionChange event" name="useOlMapListeners - util on singleclick view event should run onMapPositionChange event" time="0.002"> + </testcase> + </testsuite> + <testsuite name="DownloadSubmap - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:38" time="0.912" tests="5"> + <testcase classname="DownloadSubmap - component should render download button" name="DownloadSubmap - component should render download button" time="0.036"> + </testcase> + <testcase classname="DownloadSubmap - component should open list on button click" name="DownloadSubmap - component should open list on button click" time="0.011"> </testcase> - <testcase classname="MapNavigation - component all maps should have close button expect main map" name="MapNavigation - component all maps should have close button expect main map" time="0.067"> + <testcase classname="DownloadSubmap - component should close list on button click twice" name="DownloadSubmap - component should close list on button click twice" time="0.007"> </testcase> - <testcase classname="MapNavigation - component should close map tab when clicking on close button while" name="MapNavigation - component should close map tab when clicking on close button while" time="0.034"> + <testcase classname="DownloadSubmap - component should not show list when closed (default state)" name="DownloadSubmap - component should not show list when closed (default state)" time="0.003"> </testcase> - <testcase classname="MapNavigation - component should close map and open main map if closed currently selected map" name="MapNavigation - component should close map and open main map if closed currently selected map" time="0.033"> + <testcase classname="DownloadSubmap - component should render list elements with href and names when opened" name="DownloadSubmap - component should render list elements with href and names when opened" time="0.004"> </testcase> </testsuite> - <testsuite name="useInitializeStore - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:18" time="2.036" tests="5"> - <testcase classname="useInitializeStore - hook when fired should fetch project data in store" name="useInitializeStore - hook when fired should fetch project data in store" time="0.158"> + <testsuite name="useOlMapTileLayer - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:36" time="2.449" tests="1"> + <testcase classname="useOlMapTileLayer - util should return valid TileLayer instance" name="useOlMapTileLayer - util should return valid TileLayer instance" time="0.017"> </testcase> - <testcase classname="useInitializeStore - hook when fired should fetch backgrounds data in store" name="useInitializeStore - hook when fired should fetch backgrounds data in store" time="0.083"> + </testsuite> + <testsuite name="SubmapsDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:38" time="0.752" tests="4"> + <testcase classname="SubmapsDrawer - component should display drawer heading and list of submaps" name="SubmapsDrawer - component should display drawer heading and list of submaps" time="0.065"> </testcase> - <testcase classname="useInitializeStore - hook when fired should fetch overlays data in store" name="useInitializeStore - hook when fired should fetch overlays data in store" time="0.081"> + <testcase classname="SubmapsDrawer - component should close drawer after clicking close button" name="SubmapsDrawer - component should close drawer after clicking close button" time="0.02"> </testcase> - <testcase classname="useInitializeStore - hook when fired should fetch models data in store" name="useInitializeStore - hook when fired should fetch models data in store" time="0.056"> + <testcase classname="SubmapsDrawer - component should open submap and set it to active if it's not already opened" name="SubmapsDrawer - component should open submap and set it to active if it's not already opened" time="0.033"> </testcase> - <testcase classname="useInitializeStore - hook when fired should use valid initialize value" name="useInitializeStore - hook when fired should use valid initialize value" time="0.023"> + <testcase classname="SubmapsDrawer - component should set map active if it's already opened" name="SubmapsDrawer - component should set map active if it's already opened" time="0.013"> </testcase> </testsuite> - <testsuite name="Modal - Component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:19" time="1.054" tests="5"> - <testcase classname="Modal - Component when modal is hidden should modal have hidden class" name="Modal - Component when modal is hidden should modal have hidden class" time="0.033"> + <testsuite name="getBioEntitiesFeatures - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:39" time="0.604" tests="3"> + <testcase classname="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=bioEntity" name="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=bioEntity" time="0.023"> </testcase> - <testcase classname="Modal - Component when modal is shown should modal NOT have hidden class" name="Modal - Component when modal is shown should modal NOT have hidden class" time="0.008"> + <testcase classname="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=drugs" name="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=drugs" time="0.005"> </testcase> - <testcase classname="Modal - Component when modal is shown shows modal title" name="Modal - Component when modal is shown shows modal title" time="0.004"> + <testcase classname="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=chemicals" name="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=chemicals" time="0.003"> </testcase> - <testcase classname="Modal - Component when modal is shown shows modal close button" name="Modal - Component when modal is shown shows modal close button" time="0.003"> + </testsuite> + <testsuite name="getPinFeature - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:39" time="0.584" tests="3"> + <testcase classname="getPinFeature - subUtil should return instance of Feature" name="getPinFeature - subUtil should return instance of Feature" time="0.001"> + </testcase> + <testcase classname="getPinFeature - subUtil should return id as name" name="getPinFeature - subUtil should return id as name" time="0"> </testcase> - <testcase classname="Modal - Component when modal is shown closes modal on close button click" name="Modal - Component when modal is shown closes modal on close button click" time="0.037"> + <testcase classname="getPinFeature - subUtil should return point parsed with point to projection" name="getPinFeature - subUtil should return point parsed with point to projection" time="0.001"> </testcase> </testsuite> - <testsuite name="onMapRightClick - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:20" time="0.41" tests="5"> - <testcase classname="onMapRightClick - util when always should fire data reset handler" name="onMapRightClick - util when always should fire data reset handler" time="0.011"> + <testsuite name="Legend - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:39" time="0.486" tests="4"> + <testcase classname="Legend - component when is closed should render the component without translation" name="Legend - component when is closed should render the component without translation" time="0.102"> </testcase> - <testcase classname="onMapRightClick - util when always should fire open context menu handler" name="onMapRightClick - util when always should fire open context menu handler" time="0"> + <testcase classname="Legend - component when is open should render the component with translation" name="Legend - component when is open should render the component with translation" time="0.009"> + </testcase> + <testcase classname="Legend - component when is open should render legend header" name="Legend - component when is open should render legend header" time="0.01"> + </testcase> + <testcase classname="Legend - component when is open should render legend images" name="Legend - component when is open should render legend images" time="0.006"> </testcase> - <testcase classname="onMapRightClick - util when searchResults are undefined does not fire search result action" name="onMapRightClick - util when searchResults are undefined does not fire search result action" time="0.001"> + </testsuite> + <testsuite name="ExportDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:38" time="1.146" tests="4"> + <testcase classname="ExportDrawer - component should display drawer heading and tab names" name="ExportDrawer - component should display drawer heading and tab names" time="0.128"> + </testcase> + <testcase classname="ExportDrawer - component should close drawer after clicking close button" name="ExportDrawer - component should close drawer after clicking close button" time="0.041"> </testcase> - <testcase classname="onMapRightClick - util when searchResults are valid when results type is ALIAS does fire search result for right click action handler" name="onMapRightClick - util when searchResults are valid when results type is ALIAS does fire search result for right click action handler" time="0.002"> + <testcase classname="ExportDrawer - component should set elements as initial tab" name="ExportDrawer - component should set elements as initial tab" time="0.033"> </testcase> - <testcase classname="onMapRightClick - util when searchResults are valid when results type is REACTION does fire search result for right click action - handle reaction" name="onMapRightClick - util when searchResults are valid when results type is REACTION does fire search result for right click action - handle reaction" time="0.006"> + <testcase classname="ExportDrawer - component should set correct tab on tab change" name="ExportDrawer - component should set correct tab on tab change" time="0.03"> </testcase> </testsuite> - <testsuite name="undefined" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:20" time="0.431" tests="3"> - <testcase classname=" renders LoginModal component" name=" renders LoginModal component" time="0.023"> + <testsuite name="useOlMap - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:37" time="2.239" tests="2"> + <testcase classname="useOlMap - util when initializing should set map instance" name="useOlMap - util when initializing should set map instance" time="0.07"> </testcase> - <testcase classname=" handles input change correctly" name=" handles input change correctly" time="0.008"> + <testcase classname="useOlMap - util when initializing should render content inside the target element" name="useOlMap - util when initializing should render content inside the target element" time="0.015"> + </testcase> + </testsuite> + <testsuite name="useOlMapLayers - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:38" time="1.244" tests="4"> + <testcase classname="useOlMapLayers - util should modify layers of the map instance on init" name="useOlMapLayers - util should modify layers of the map instance on init" time="0.047"> </testcase> - <testcase classname=" submits form" name=" submits form" time="0.057"> + <testcase classname="useOlMapLayers - util should return valid TileLayer instance [1]" name="useOlMapLayers - util should return valid TileLayer instance [1]" time="0.026"> + </testcase> + <testcase classname="useOlMapLayers - util should return valid VectorLayer instance [2]" name="useOlMapLayers - util should return valid VectorLayer instance [2]" time="0.018"> + </testcase> + <testcase classname="useOlMapLayers - util should return valid VectorLayer instance [3]" name="useOlMapLayers - util should return valid VectorLayer instance [3]" time="0.008"> </testcase> </testsuite> - <testsuite name="TopBar - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:20" time="0.553" tests="3"> - <testcase classname="TopBar - component Should contain user avatar, search bar" name="TopBar - component Should contain user avatar, search bar" time="0.021"> + <testsuite name="MapViewer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:38" time="1.057" tests="2"> + <testcase classname="MapViewer - component should render component container" name="MapViewer - component should render component container" time="0.057"> </testcase> - <testcase classname="TopBar - component should open submaps drawer on submaps button click" name="TopBar - component should open submaps drawer on submaps button click" time="0.094"> + <testcase classname="MapViewer - component should render openlayers map inside the component" name="MapViewer - component should render openlayers map inside the component" time="0.015"> </testcase> - <testcase classname="TopBar - component should open overlays drawer on overlays button click" name="TopBar - component should open overlays drawer on overlays button click" time="0.047"> + </testsuite> + <testsuite name="getLineFeature" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:41" time="0.37" tests="2"> + <testcase classname="getLineFeature should return valid Feature object" name="getLineFeature should return valid Feature object" time="0.003"> + </testcase> + <testcase classname="getLineFeature should return valid Feature object with LineString geometry" name="getLineFeature should return valid Feature object with LineString geometry" time="0.003"> </testcase> </testsuite> - <testsuite name="ResultsList - component " errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:20" time="0.425" tests="2"> - <testcase classname="ResultsList - component should render results and navigation panel" name="ResultsList - component should render results and navigation panel" time="0.056"> + <testsuite name="Drawer - component" errors="0" failures="0" skipped="1" timestamp="2024-01-12T14:39:38" time="1.584" tests="7"> + <testcase classname="Drawer - component should render Drawer" name="Drawer - component should render Drawer" time="0.034"> + </testcase> + <testcase classname="Drawer - component should not display drawer when its not open" name="Drawer - component should not display drawer when its not open" time="0.009"> + </testcase> + <testcase classname="Drawer - component search drawer should open drawer and display search drawer content" name="Drawer - component search drawer should open drawer and display search drawer content" time="0.026"> </testcase> - <testcase classname="ResultsList - component should navigate to grouped search results after backward button click" name="ResultsList - component should navigate to grouped search results after backward button click" time="0.037"> + <testcase classname="Drawer - component search drawer should close drawer after pressing close button" name="Drawer - component search drawer should close drawer after pressing close button" time="0.053"> + </testcase> + <testcase classname="Drawer - component submap drawer should open drawer and display submaps" name="Drawer - component submap drawer should open drawer and display submaps" time="0.004"> + </testcase> + <testcase classname="Drawer - component reaction drawer should open drawer and display reaction" name="Drawer - component reaction drawer should open drawer and display reaction" time="0.069"> + </testcase> + <testcase classname="Drawer - component bioEntity drawer should open drawer and display bioEntity" name="Drawer - component bioEntity drawer should open drawer and display bioEntity" time="0"> + <skipped/> </testcase> </testsuite> - <testsuite name="handleReactionResults - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:20" time="0.337" tests="4"> - <testcase classname="handleReactionResults - util should run getReactionsByIds as first action" name="handleReactionResults - util should run getReactionsByIds as first action" time="0.011"> + <testsuite name="Modal - Component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:41" time="0.456" tests="5"> + <testcase classname="Modal - Component when modal is hidden should modal have hidden class" name="Modal - Component when modal is hidden should modal have hidden class" time="0.032"> </testcase> - <testcase classname="handleReactionResults - util should run openReactionDrawerById to empty array as second action" name="handleReactionResults - util should run openReactionDrawerById to empty array as second action" time="0.001"> + <testcase classname="Modal - Component when modal is shown should modal NOT have hidden class" name="Modal - Component when modal is shown should modal NOT have hidden class" time="0.008"> </testcase> - <testcase classname="handleReactionResults - util should run setBioEntityContent to empty array as third action" name="handleReactionResults - util should run setBioEntityContent to empty array as third action" time="0"> + <testcase classname="Modal - Component when modal is shown shows modal title" name="Modal - Component when modal is shown shows modal title" time="0.004"> </testcase> - <testcase classname="handleReactionResults - util should run getBioEntity as fourth action" name="handleReactionResults - util should run getBioEntity as fourth action" time="0"> + <testcase classname="Modal - Component when modal is shown shows modal close button" name="Modal - Component when modal is shown shows modal close button" time="0.003"> + </testcase> + <testcase classname="Modal - Component when modal is shown closes modal on close button click" name="Modal - Component when modal is shown closes modal on close button click" time="0.026"> </testcase> </testsuite> - <testsuite name="BioEntitiesPinsList - component " errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:20" time="0.396" tests="1"> - <testcase classname="BioEntitiesPinsList - component should display list of bio entites elements" name="BioEntitiesPinsList - component should display list of bio entites elements" time="0.053"> + <testsuite name="BioEntityDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:41" time="0.386" tests="6"> + <testcase classname="BioEntityDrawer - component when there's NO matching bioEntity should not show drawer content" name="BioEntityDrawer - component when there's NO matching bioEntity should not show drawer content" time="0.013"> + </testcase> + <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should show drawer header" name="BioEntityDrawer - component when there IS a matching bioEntity should show drawer header" time="0.025"> + </testcase> + <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should show drawer bioEntity full name" name="BioEntityDrawer - component when there IS a matching bioEntity should show drawer bioEntity full name" time="0.004"> + </testcase> + <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should not show drawer bioEntity full name if it doesn't exists" name="BioEntityDrawer - component when there IS a matching bioEntity should not show drawer bioEntity full name if it doesn't exists" time="0.004"> + </testcase> + <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should show list of annotations " name="BioEntityDrawer - component when there IS a matching bioEntity should show list of annotations " time="0.015"> + </testcase> + <testcase classname="BioEntityDrawer - component when there IS a matching bioEntity should display associated submaps if bio entity links to submap" name="BioEntityDrawer - component when there IS a matching bioEntity should display associated submaps if bio entity links to submap" time="0.004"> </testcase> </testsuite> - <testsuite name="SearchBar - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:20" time="0.397" tests="5"> - <testcase classname="SearchBar - component should let user type text" name="SearchBar - component should let user type text" time="0.02"> + <testsuite name="AccordionsDetails - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:42" time="0.481" tests="5"> + <testcase classname="AccordionsDetails - component should display name of drug" name="AccordionsDetails - component should display name of drug" time="0.035"> </testcase> - <testcase classname="SearchBar - component should disable button when the user clicks the lens button" name="SearchBar - component should disable button when the user clicks the lens button" time="0.058"> + <testcase classname="AccordionsDetails - component should display description of drug" name="AccordionsDetails - component should display description of drug" time="0.009"> </testcase> - <testcase classname="SearchBar - component should disable input when the user clicks the Enter" name="SearchBar - component should disable input when the user clicks the Enter" time="0.017"> + <testcase classname="AccordionsDetails - component should display synonyms of drug" name="AccordionsDetails - component should display synonyms of drug" time="0.005"> </testcase> - <testcase classname="SearchBar - component should set initial search value to match searchValue query param" name="SearchBar - component should set initial search value to match searchValue query param" time="0.003"> + <testcase classname="AccordionsDetails - component should display blood brain barrier for drug" name="AccordionsDetails - component should display blood brain barrier for drug" time="0.014"> </testcase> - <testcase classname="SearchBar - component should change selected search element when user search another" name="SearchBar - component should change selected search element when user search another" time="0.018"> + <testcase classname="AccordionsDetails - component should display direct evidence publications for chemicals" name="AccordionsDetails - component should display direct evidence publications for chemicals" time="0.007"> </testcase> </testsuite> - <testsuite name="SearchDrawerWrapper - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:20" time="0.685" tests="3"> - <testcase classname="SearchDrawerWrapper - component should display the first step for search" name="SearchDrawerWrapper - component should display the first step for search" time="0.027"> + <testsuite name="getBioEntitySingleFeature - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:42" time="0.519" tests="6"> + <testcase classname="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=bioEntity" name="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=bioEntity" time="0.006"> + </testcase> + <testcase classname="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=drugs" name="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=drugs" time="0.001"> + </testcase> + <testcase classname="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=chemicals" name="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=chemicals" time="0.001"> + </testcase> + <testcase classname="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=bioEntity" name="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=bioEntity" time="0.001"> </testcase> - <testcase classname="SearchDrawerWrapper - component should display the second step for value type bioEntity" name="SearchDrawerWrapper - component should display the second step for value type bioEntity" time="0.015"> + <testcase classname="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=drugs" name="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=drugs" time="0.001"> </testcase> - <testcase classname="SearchDrawerWrapper - component should display the second step for value type drugs" name="SearchDrawerWrapper - component should display the second step for value type drugs" time="0.01"> + <testcase classname="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=chemicals" name="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=chemicals" time="0.001"> </testcase> </testsuite> - <testsuite name="Drawer - component" errors="0" failures="0" skipped="1" timestamp="2024-01-03T15:35:18" time="2.682" tests="7"> - <testcase classname="Drawer - component should render Drawer" name="Drawer - component should render Drawer" time="0.03"> + <testsuite name="undefined" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:42" time="0.502" tests="3"> + <testcase classname=" renders LoginModal component" name=" renders LoginModal component" time="0.021"> </testcase> - <testcase classname="Drawer - component should not display drawer when its not open" name="Drawer - component should not display drawer when its not open" time="0.006"> + <testcase classname=" handles input change correctly" name=" handles input change correctly" time="0.013"> </testcase> - <testcase classname="Drawer - component search drawer should open drawer and display search drawer content" name="Drawer - component search drawer should open drawer and display search drawer content" time="0.029"> + <testcase classname=" submits form" name=" submits form" time="0.064"> </testcase> - <testcase classname="Drawer - component search drawer should close drawer after pressing close button" name="Drawer - component search drawer should close drawer after pressing close button" time="0.03"> + </testsuite> + <testsuite name="AssociatedSubmap - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:42" time="0.496" tests="4"> + <testcase classname="AssociatedSubmap - component should not display component when can not find asociated map model" name="AssociatedSubmap - component should not display component when can not find asociated map model" time="0.016"> </testcase> - <testcase classname="Drawer - component submap drawer should open drawer and display submaps" name="Drawer - component submap drawer should open drawer and display submaps" time="0.003"> + <testcase classname="AssociatedSubmap - component should render component when associated map model is found" name="AssociatedSubmap - component should render component when associated map model is found" time="0.017"> </testcase> - <testcase classname="Drawer - component reaction drawer should open drawer and display reaction" name="Drawer - component reaction drawer should open drawer and display reaction" time="0.079"> + <testcase classname="AssociatedSubmap - component when map is already opened should open submap and set it to active on open submap button click" name="AssociatedSubmap - component when map is already opened should open submap and set it to active on open submap button click" time="0.038"> </testcase> - <testcase classname="Drawer - component bioEntity drawer should open drawer and display bioEntity" name="Drawer - component bioEntity drawer should open drawer and display bioEntity" time="0"> - <skipped/> + <testcase classname="AssociatedSubmap - component when map is already opened should set map active on open submap button click" name="AssociatedSubmap - component when map is already opened should set map active on open submap button click" time="0.012"> </testcase> </testsuite> - <testsuite name="CookieBanner component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.357" tests="3"> - <testcase classname="CookieBanner component renders cookie banner correctly first time" name="CookieBanner component renders cookie banner correctly first time" time="0.017"> + <testsuite name="useGetSubmapDownloadUrl - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:42" time="0.409" tests="5"> + <testcase classname="useGetSubmapDownloadUrl - hook when not all params valid should return empty string" name="useGetSubmapDownloadUrl - hook when not all params valid should return empty string" time="0.01"> + </testcase> + <testcase classname="useGetSubmapDownloadUrl - hook when not all params valid should return empty string" name="useGetSubmapDownloadUrl - hook when not all params valid should return empty string" time="0.002"> </testcase> - <testcase classname="CookieBanner component hides the banner after accepting cookies" name="CookieBanner component hides the banner after accepting cookies" time="0.005"> + <testcase classname="useGetSubmapDownloadUrl - hook when not all params valid should return empty string" name="useGetSubmapDownloadUrl - hook when not all params valid should return empty string" time="0.001"> </testcase> - <testcase classname="CookieBanner component does not render the cookies banner when cookies are accepted" name="CookieBanner component does not render the cookies banner when cookies are accepted" time="0.005"> + <testcase classname="useGetSubmapDownloadUrl - hook when not all params valid should return empty string" name="useGetSubmapDownloadUrl - hook when not all params valid should return empty string" time="0.009"> + </testcase> + <testcase classname="useGetSubmapDownloadUrl - hook when all params valid should return valid string" name="useGetSubmapDownloadUrl - hook when all params valid should return valid string" time="0.001"> </testcase> </testsuite> - <testsuite name="PerfectMatchSwitch - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.385" tests="4"> - <testcase classname="PerfectMatchSwitch - component should initialy be set to false when perfectMatch is not in query or set to false" name="PerfectMatchSwitch - component should initialy be set to false when perfectMatch is not in query or set to false" time="0.026"> + <testsuite name="BioEntitiesSubmapItem - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:42" time="0.542" tests="4"> + <testcase classname="BioEntitiesSubmapItem - component should display map name, number of elements, icon" name="BioEntitiesSubmapItem - component should display map name, number of elements, icon" time="0.016"> + </testcase> + <testcase classname="BioEntitiesSubmapItem - component should navigate user to bio enitites results list after clicking button" name="BioEntitiesSubmapItem - component should navigate user to bio enitites results list after clicking button" time="0.081"> </testcase> - <testcase classname="PerfectMatchSwitch - component should initialy be set to true when perfectMatch query is set to true" name="PerfectMatchSwitch - component should initialy be set to true when perfectMatch query is set to true" time="0.008"> + <testcase classname="BioEntitiesSubmapItem - component should open submap and set it to active if it's not already opened" name="BioEntitiesSubmapItem - component should open submap and set it to active if it's not already opened" time="0.017"> </testcase> - <testcase classname="PerfectMatchSwitch - component should set checkbox to true and update store" name="PerfectMatchSwitch - component should set checkbox to true and update store" time="0.015"> + <testcase classname="BioEntitiesSubmapItem - component should set map active if it's already opened" name="BioEntitiesSubmapItem - component should set map active if it's already opened" time="0.028"> + </testcase> + </testsuite> + <testsuite name="useOlMapView - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:42" time="0.618" tests="2"> + <testcase classname="useOlMapView - util should modify view of the map instance on INITIAL position config change" name="useOlMapView - util should modify view of the map instance on INITIAL position config change" time="0.048"> </testcase> - <testcase classname="PerfectMatchSwitch - component should set checkbox to false and update store" name="PerfectMatchSwitch - component should set checkbox to false and update store" time="0.006"> + <testcase classname="useOlMapView - util should return valid View instance" name="useOlMapView - util should return valid View instance" time="0.019"> </testcase> </testsuite> - <testsuite name="handleAliasResults - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.372" tests="2"> - <testcase classname="handleAliasResults - util should run openBioEntityDrawerById as first action" name="handleAliasResults - util should run openBioEntityDrawerById as first action" time="0.019"> + <testsuite name="IncludedCompartmentPathways - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.545" tests="4"> + <testcase classname="IncludedCompartmentPathways - component should display compartment / pathways checkboxes when fetching data is successful" name="IncludedCompartmentPathways - component should display compartment / pathways checkboxes when fetching data is successful" time="0.082"> </testcase> - <testcase classname="handleAliasResults - util should run getMultiBioEntity as second action" name="handleAliasResults - util should run getMultiBioEntity as second action" time="0.003"> + <testcase classname="IncludedCompartmentPathways - component should not display compartment / pathways checkboxes when fetching data fails" name="IncludedCompartmentPathways - component should not display compartment / pathways checkboxes when fetching data fails" time="0.004"> + </testcase> + <testcase classname="IncludedCompartmentPathways - component should not display compartment / pathways checkboxes when fetched data is empty" name="IncludedCompartmentPathways - component should not display compartment / pathways checkboxes when fetched data is empty" time="0.005"> + </testcase> + <testcase classname="IncludedCompartmentPathways - component should display loading message when fetching data is pending" name="IncludedCompartmentPathways - component should display loading message when fetching data is pending" time="0.004"> </testcase> </testsuite> - <testsuite name="OverlayListItem - component" errors="0" failures="0" skipped="1" timestamp="2024-01-03T15:35:21" time="0.43" tests="3"> + <testsuite name="OverlayListItem - component" errors="0" failures="0" skipped="1" timestamp="2024-01-12T14:39:43" time="0.587" tests="4"> <testcase classname="OverlayListItem - component should render component with correct properties" name="OverlayListItem - component should render component with correct properties" time="0.089"> </testcase> - <testcase classname="OverlayListItem - component should trigger view overlays on view button click and switch background to Empty if available" name="OverlayListItem - component should trigger view overlays on view button click and switch background to Empty if available" time="0.044"> + <testcase classname="OverlayListItem - component view overlays should trigger view overlays on view button click and switch background to Empty if available" name="OverlayListItem - component view overlays should trigger view overlays on view button click and switch background to Empty if available" time="0.019"> + </testcase> + <testcase classname="OverlayListItem - component view overlays should disable overlay on view button click if overlay is active" name="OverlayListItem - component view overlays should disable overlay on view button click if overlay is active" time="0.038"> </testcase> <testcase classname="OverlayListItem - component should trigger download overlay to PC on download button click" name="OverlayListItem - component should trigger download overlay to PC on download button click" time="0"> <skipped/> </testcase> </testsuite> - <testsuite name="BioEntitiesPinsListItem - component " errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.367" tests="6"> - <testcase classname="BioEntitiesPinsListItem - component should display name of bio entity element" name="BioEntitiesPinsListItem - component should display name of bio entity element" time="0.018"> + <testsuite name="PinsList - component " errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.638" tests="5"> + <testcase classname="PinsList - component should display list of drug targets" name="PinsList - component should display list of drug targets" time="0.041"> </testcase> - <testcase classname="BioEntitiesPinsListItem - component should display symbol of bio entity element" name="BioEntitiesPinsListItem - component should display symbol of bio entity element" time="0.004"> + <testcase classname="PinsList - component should display drug details when drug is searched" name="PinsList - component should display drug details when drug is searched" time="0.012"> </testcase> - <testcase classname="BioEntitiesPinsListItem - component should display empty string when symbol does not exist" name="BioEntitiesPinsListItem - component should display empty string when symbol does not exist" time="0.003"> + <testcase classname="PinsList - component should display list of chemicals targets" name="PinsList - component should display list of chemicals targets" time="0.009"> </testcase> - <testcase classname="BioEntitiesPinsListItem - component should display string type of bio entity element" name="BioEntitiesPinsListItem - component should display string type of bio entity element" time="0.003"> + <testcase classname="PinsList - component should display chemicals details when chemical is searched" name="PinsList - component should display chemicals details when chemical is searched" time="0.012"> </testcase> - <testcase classname="BioEntitiesPinsListItem - component should display synonyms of bio entity element" name="BioEntitiesPinsListItem - component should display synonyms of bio entity element" time="0.009"> + <testcase classname="PinsList - component should not display list of bio enities when bioEntity is searched" name="PinsList - component should not display list of bio enities when bioEntity is searched" time="0.001"> </testcase> - <testcase classname="BioEntitiesPinsListItem - component should display list of references for pin" name="BioEntitiesPinsListItem - component should display list of references for pin" time="0.005"> + </testsuite> + <testsuite name="SearchBar - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.606" tests="5"> + <testcase classname="SearchBar - component should let user type text" name="SearchBar - component should let user type text" time="0.06"> + </testcase> + <testcase classname="SearchBar - component should disable button when the user clicks the lens button" name="SearchBar - component should disable button when the user clicks the lens button" time="0.054"> + </testcase> + <testcase classname="SearchBar - component should disable input when the user clicks the Enter" name="SearchBar - component should disable input when the user clicks the Enter" time="0.014"> + </testcase> + <testcase classname="SearchBar - component should set initial search value to match searchValue query param" name="SearchBar - component should set initial search value to match searchValue query param" time="0.003"> + </testcase> + <testcase classname="SearchBar - component should change selected search element when user search another" name="SearchBar - component should change selected search element when user search another" time="0.033"> </testcase> </testsuite> - <testsuite name="BioEntitiesAccordion - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.436" tests="2"> - <testcase classname="BioEntitiesAccordion - component should display loading indicator when bioEntity search is pending" name="BioEntitiesAccordion - component should display loading indicator when bioEntity search is pending" time="0.044"> + <testsuite name="PinsListItem - component " errors="0" failures="0" skipped="1" timestamp="2024-01-12T14:39:43" time="0.562" tests="6"> + <testcase classname="PinsListItem - component should display full name of pin" name="PinsListItem - component should display full name of pin" time="0.04"> </testcase> - <testcase classname="BioEntitiesAccordion - component should render list of maps with number of entities after succeeded bio entity search" name="BioEntitiesAccordion - component should render list of maps with number of entities after succeeded bio entity search" time="0.009"> + <testcase classname="PinsListItem - component should display list of elements for pin for drugs" name="PinsListItem - component should display list of elements for pin for drugs" time="0.006"> + </testcase> + <testcase classname="PinsListItem - component should display list of references for pin" name="PinsListItem - component should display list of references for pin" time="0.004"> + </testcase> + <testcase classname="PinsListItem - component should display list of elements for pin for chemicals" name="PinsListItem - component should display list of elements for pin for chemicals" time="0.004"> + </testcase> + <testcase classname="PinsListItem - component should not display list of elements for pin for bioentities" name="PinsListItem - component should not display list of elements for pin for bioentities" time="0"> + <skipped/> + </testcase> + <testcase classname="PinsListItem - component should not display list of available submaps for pin when there aren't any submaps" name="PinsListItem - component should not display list of available submaps for pin when there aren't any submaps" time="0.003"> </testcase> </testsuite> - <testsuite name="SubmapsDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.447" tests="4"> - <testcase classname="SubmapsDrawer - component should display drawer heading and list of submaps" name="SubmapsDrawer - component should display drawer heading and list of submaps" time="0.021"> + <testsuite name="DrugsAccordion - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.633" tests="5"> + <testcase classname="DrugsAccordion - component should display drugs number after succesfull chemicals search" name="DrugsAccordion - component should display drugs number after succesfull chemicals search" time="0.019"> </testcase> - <testcase classname="SubmapsDrawer - component should close drawer after clicking close button" name="SubmapsDrawer - component should close drawer after clicking close button" time="0.018"> + <testcase classname="DrugsAccordion - component should display loading indicator while waiting for chemicals search response" name="DrugsAccordion - component should display loading indicator while waiting for chemicals search response" time="0.009"> </testcase> - <testcase classname="SubmapsDrawer - component should open submap and set it to active if it's not already opened" name="SubmapsDrawer - component should open submap and set it to active if it's not already opened" time="0.061"> + <testcase classname="DrugsAccordion - component should navigate user to chemical results list after clicking button" name="DrugsAccordion - component should navigate user to chemical results list after clicking button" time="0.004"> </testcase> - <testcase classname="SubmapsDrawer - component should set map active if it's already opened" name="SubmapsDrawer - component should set map active if it's already opened" time="0.011"> + <testcase classname="DrugsAccordion - component should disable navigation button when there is no chemicals" name="DrugsAccordion - component should disable navigation button when there is no chemicals" time="0.004"> + </testcase> + <testcase classname="DrugsAccordion - component should disable navigation button when waiting for api response" name="DrugsAccordion - component should disable navigation button when waiting for api response" time="0.003"> </testcase> </testsuite> - <testsuite name="BackgroundSelector - component" errors="0" failures="0" skipped="1" timestamp="2024-01-03T15:35:21" time="0.4" tests="6"> - <testcase classname="BackgroundSelector - component should initialy display default value" name="BackgroundSelector - component should initialy display default value" time="0.017"> + <testsuite name="Annotations - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.594" tests="4"> + <testcase classname="Annotations - component should display annotations checkboxes when fetching data is successful" name="Annotations - component should display annotations checkboxes when fetching data is successful" time="0.091"> </testcase> - <testcase classname="BackgroundSelector - component should display selected value name when it's not main background" name="BackgroundSelector - component should display selected value name when it's not main background" time="0.018"> + <testcase classname="Annotations - component should not display annotations checkboxes when fetching data fails" name="Annotations - component should not display annotations checkboxes when fetching data fails" time="0.008"> </testcase> - <testcase classname="BackgroundSelector - component should change redux map state on selecting background" name="BackgroundSelector - component should change redux map state on selecting background" time="0.02"> + <testcase classname="Annotations - component should not display annotations checkboxes when fetched data is empty object" name="Annotations - component should not display annotations checkboxes when fetched data is empty object" time="0.009"> </testcase> - <testcase classname="BackgroundSelector - component query params should display default value when main background id is in query params" name="BackgroundSelector - component query params should display default value when main background id is in query params" time="0.009"> + <testcase classname="Annotations - component should display loading message when fetching data is pending" name="Annotations - component should display loading message when fetching data is pending" time="0.013"> </testcase> - <testcase classname="BackgroundSelector - component query params should display correct background when background id is in query params" name="BackgroundSelector - component query params should display correct background when background id is in query params" time="0.003"> + </testsuite> + <testsuite name="Annotations - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.586" tests="4"> + <testcase classname="Annotations - component should display annotations checkboxes when fetching data is successful" name="Annotations - component should display annotations checkboxes when fetching data is successful" time="0.058"> </testcase> - <testcase classname="BackgroundSelector - component query params should set backgroundid in query on selecting background" name="BackgroundSelector - component query params should set backgroundid in query on selecting background" time="0"> - <skipped/> + <testcase classname="Annotations - component should not display annotations checkboxes when fetching data fails" name="Annotations - component should not display annotations checkboxes when fetching data fails" time="0.005"> + </testcase> + <testcase classname="Annotations - component should not display annotations checkboxes when fetched data is empty object" name="Annotations - component should not display annotations checkboxes when fetched data is empty object" time="0.004"> + </testcase> + <testcase classname="Annotations - component should display loading message when fetching data is pending" name="Annotations - component should display loading message when fetching data is pending" time="0.005"> </testcase> </testsuite> - <testsuite name="AccordionsDetails - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.452" tests="5"> - <testcase classname="AccordionsDetails - component should display name of drug" name="AccordionsDetails - component should display name of drug" time="0.046"> + <testsuite name="SearchDrawerWrapper - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.617" tests="3"> + <testcase classname="SearchDrawerWrapper - component should display the first step for search" name="SearchDrawerWrapper - component should display the first step for search" time="0.028"> </testcase> - <testcase classname="AccordionsDetails - component should display description of drug" name="AccordionsDetails - component should display description of drug" time="0.009"> + <testcase classname="SearchDrawerWrapper - component should display the second step for value type bioEntity" name="SearchDrawerWrapper - component should display the second step for value type bioEntity" time="0.018"> + </testcase> + <testcase classname="SearchDrawerWrapper - component should display the second step for value type drugs" name="SearchDrawerWrapper - component should display the second step for value type drugs" time="0.018"> + </testcase> + </testsuite> + <testsuite name="chemicals reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.305" tests="4"> + <testcase classname="chemicals reducer should match initial state" name="chemicals reducer should match initial state" time="0.003"> </testcase> - <testcase classname="AccordionsDetails - component should display synonyms of drug" name="AccordionsDetails - component should display synonyms of drug" time="0.011"> + <testcase classname="chemicals reducer should update store after succesfull getChemicals query" name="chemicals reducer should update store after succesfull getChemicals query" time="0.027"> </testcase> - <testcase classname="AccordionsDetails - component should display blood brain barrier for drug" name="AccordionsDetails - component should display blood brain barrier for drug" time="0.007"> + <testcase classname="chemicals reducer should update store after failed getChemicals query" name="chemicals reducer should update store after failed getChemicals query" time="0.071"> </testcase> - <testcase classname="AccordionsDetails - component should display direct evidence publications for chemicals" name="AccordionsDetails - component should display direct evidence publications for chemicals" time="0.008"> + <testcase classname="chemicals reducer should update store on loading getChemicals query" name="chemicals reducer should update store on loading getChemicals query" time="0.017"> </testcase> </testsuite> - <testsuite name="PinsList - component " errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.464" tests="5"> - <testcase classname="PinsList - component should display list of drug targets" name="PinsList - component should display list of drug targets" time="0.057"> + <testsuite name="CollapsibleSection - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.325" tests="2"> + <testcase classname="CollapsibleSection - component should render with title and content" name="CollapsibleSection - component should render with title and content" time="0.023"> </testcase> - <testcase classname="PinsList - component should display drug details when drug is searched" name="PinsList - component should display drug details when drug is searched" time="0.009"> + <testcase classname="CollapsibleSection - component should collapse and expands on button click" name="CollapsibleSection - component should collapse and expands on button click" time="0.042"> </testcase> - <testcase classname="PinsList - component should display list of chemicals targets" name="PinsList - component should display list of chemicals targets" time="0.066"> + </testsuite> + <testsuite name="usePointToProjection - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.33" tests="3"> + <testcase classname="usePointToProjection - util when mapSize arg is undefined in redux should return fallback value on function call" name="usePointToProjection - util when mapSize arg is undefined in redux should return fallback value on function call" time="0.03"> </testcase> - <testcase classname="PinsList - component should display chemicals details when chemical is searched" name="PinsList - component should display chemicals details when chemical is searched" time="0.02"> + <testcase classname="usePointToProjection - util when mapSize arg is invalid in redux should return fallback value on function call" name="usePointToProjection - util when mapSize arg is invalid in redux should return fallback value on function call" time="0.004"> </testcase> - <testcase classname="PinsList - component should not display list of bio enities when bioEntity is searched" name="PinsList - component should not display list of bio enities when bioEntity is searched" time="0.002"> + <testcase classname="usePointToProjection - util when all args are valid in redux should return valid lat lng value on function call" name="usePointToProjection - util when all args are valid in redux should return valid lat lng value on function call" time="0.003"> </testcase> </testsuite> - <testsuite name="useReduxBusQueryManager - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.367" tests="3"> - <testcase classname="useReduxBusQueryManager - util on init when data is NOT loaded should not update query" name="useReduxBusQueryManager - util on init when data is NOT loaded should not update query" time="0.032"> + <testsuite name="onMapRightClick - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.38" tests="5"> + <testcase classname="onMapRightClick - util when always should fire data reset handler" name="onMapRightClick - util when always should fire data reset handler" time="0.02"> + </testcase> + <testcase classname="onMapRightClick - util when always should fire open context menu handler" name="onMapRightClick - util when always should fire open context menu handler" time="0"> + </testcase> + <testcase classname="onMapRightClick - util when searchResults are undefined does not fire search result action" name="onMapRightClick - util when searchResults are undefined does not fire search result action" time="0.002"> </testcase> - <testcase classname="useReduxBusQueryManager - util on init when data is loaded should update query" name="useReduxBusQueryManager - util on init when data is loaded should update query" time="0.011"> + <testcase classname="onMapRightClick - util when searchResults are valid when results type is ALIAS does fire search result for right click action handler" name="onMapRightClick - util when searchResults are valid when results type is ALIAS does fire search result for right click action handler" time="0.006"> </testcase> - <testcase classname="useReduxBusQueryManager - util on init when data is loaded should update query params to valid ones" name="useReduxBusQueryManager - util on init when data is loaded should update query params to valid ones" time="0.011"> + <testcase classname="onMapRightClick - util when searchResults are valid when results type is REACTION does fire search result for right click action - handle reaction" name="onMapRightClick - util when searchResults are valid when results type is REACTION does fire search result for right click action - handle reaction" time="0.003"> </testcase> </testsuite> - <testsuite name="DrugsAccordion - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.386" tests="5"> - <testcase classname="DrugsAccordion - component should display drugs number after succesfull chemicals search" name="DrugsAccordion - component should display drugs number after succesfull chemicals search" time="0.017"> + <testsuite name="DrawerHeadingBackwardButton - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.425" tests="3"> + <testcase classname="DrawerHeadingBackwardButton - component should render passed values" name="DrawerHeadingBackwardButton - component should render passed values" time="0.043"> </testcase> - <testcase classname="DrugsAccordion - component should display loading indicator while waiting for chemicals search response" name="DrugsAccordion - component should display loading indicator while waiting for chemicals search response" time="0.007"> + <testcase classname="DrawerHeadingBackwardButton - component should call backward function on back button click" name="DrawerHeadingBackwardButton - component should call backward function on back button click" time="0.007"> </testcase> - <testcase classname="DrugsAccordion - component should navigate user to chemical results list after clicking button" name="DrugsAccordion - component should navigate user to chemical results list after clicking button" time="0.003"> + <testcase classname="DrawerHeadingBackwardButton - component should call class drawer on close button click" name="DrawerHeadingBackwardButton - component should call class drawer on close button click" time="0.013"> </testcase> - <testcase classname="DrugsAccordion - component should disable navigation button when there is no chemicals" name="DrugsAccordion - component should disable navigation button when there is no chemicals" time="0.024"> + </testsuite> + <testsuite name="handleAliasResults - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.453" tests="2"> + <testcase classname="handleAliasResults - util should run openBioEntityDrawerById as first action" name="handleAliasResults - util should run openBioEntityDrawerById as first action" time="0.01"> </testcase> - <testcase classname="DrugsAccordion - component should disable navigation button when waiting for api response" name="DrugsAccordion - component should disable navigation button when waiting for api response" time="0.009"> + <testcase classname="handleAliasResults - util should run getMultiBioEntity as second action" name="handleAliasResults - util should run getMultiBioEntity as second action" time="0.001"> </testcase> </testsuite> - <testsuite name="handleBioEntityResults - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.425" tests="2"> - <testcase classname="handleBioEntityResults - util should run setCurrentSelectedBioEntityId as first action" name="handleBioEntityResults - util should run setCurrentSelectedBioEntityId as first action" time="0.005"> + <testsuite name="ReactionDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:43" time="0.407" tests="6"> + <testcase classname="ReactionDrawer - component when there's NO matching reaction should not show drawer content" name="ReactionDrawer - component when there's NO matching reaction should not show drawer content" time="0.015"> </testcase> - <testcase classname="handleBioEntityResults - util should run getMultiBioEntity as second action" name="handleBioEntityResults - util should run getMultiBioEntity as second action" time="0.001"> + <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer header" name="ReactionDrawer - component when there IS a matching reaction should show drawer header" time="0.012"> + </testcase> + <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer reaction type" name="ReactionDrawer - component when there IS a matching reaction should show drawer reaction type" time="0.012"> + </testcase> + <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer reaction annotations title" name="ReactionDrawer - component when there IS a matching reaction should show drawer reaction annotations title" time="0.008"> + </testcase> + <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer reaction source for source=-xkkfqwc--djxqb" name="ReactionDrawer - component when there IS a matching reaction should show drawer reaction source for source=-xkkfqwc--djxqb" time="0.003"> + </testcase> + <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer reaction reference with text=ajixclmqaiovkqs (-79.90823308937252), href=https://ut.com" name="ReactionDrawer - component when there IS a matching reaction should show drawer reaction reference with text=ajixclmqaiovkqs (-79.90823308937252), href=https://ut.com" time="0.005"> </testcase> </testsuite> - <testsuite name="ReactionDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:21" time="0.362" tests="6"> - <testcase classname="ReactionDrawer - component when there's NO matching reaction should not show drawer content" name="ReactionDrawer - component when there's NO matching reaction should not show drawer content" time="0.01"> + <testsuite name="BioEntitiesPinsListItem - component " errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.493" tests="6"> + <testcase classname="BioEntitiesPinsListItem - component should display name of bio entity element" name="BioEntitiesPinsListItem - component should display name of bio entity element" time="0.022"> </testcase> - <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer header" name="ReactionDrawer - component when there IS a matching reaction should show drawer header" time="0.01"> + <testcase classname="BioEntitiesPinsListItem - component should display symbol of bio entity element" name="BioEntitiesPinsListItem - component should display symbol of bio entity element" time="0.004"> </testcase> - <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer reaction type" name="ReactionDrawer - component when there IS a matching reaction should show drawer reaction type" time="0.005"> + <testcase classname="BioEntitiesPinsListItem - component should display empty string when symbol does not exist" name="BioEntitiesPinsListItem - component should display empty string when symbol does not exist" time="0.004"> </testcase> - <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer reaction annotations title" name="ReactionDrawer - component when there IS a matching reaction should show drawer reaction annotations title" time="0.003"> + <testcase classname="BioEntitiesPinsListItem - component should display string type of bio entity element" name="BioEntitiesPinsListItem - component should display string type of bio entity element" time="0.003"> </testcase> - <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer reaction source for source=-xkkfqwc--djxqb" name="ReactionDrawer - component when there IS a matching reaction should show drawer reaction source for source=-xkkfqwc--djxqb" time="0.004"> + <testcase classname="BioEntitiesPinsListItem - component should display synonyms of bio entity element" name="BioEntitiesPinsListItem - component should display synonyms of bio entity element" time="0.004"> </testcase> - <testcase classname="ReactionDrawer - component when there IS a matching reaction should show drawer reaction reference with text=ajixclmqaiovkqs (-79.90823308937252), href=https://ut.com" name="ReactionDrawer - component when there IS a matching reaction should show drawer reaction reference with text=ajixclmqaiovkqs (-79.90823308937252), href=https://ut.com" time="0.004"> + <testcase classname="BioEntitiesPinsListItem - component should display list of references for pin" name="BioEntitiesPinsListItem - component should display list of references for pin" time="0.005"> </testcase> </testsuite> - <testsuite name="ReactionDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.336" tests="3"> - <testcase classname="ReactionDrawer - component should show reference group with source=" name="ReactionDrawer - component should show reference group with source=" time="0.013"> + <testsuite name="useOlMapReactionsLayer - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.54" tests="2"> + <testcase classname="useOlMapReactionsLayer - util should return VectorLayer" name="useOlMapReactionsLayer - util should return VectorLayer" time="0.025"> </testcase> - <testcase classname="ReactionDrawer - component should show reference group with source=source1" name="ReactionDrawer - component should show reference group with source=source1" time="0.004"> + <testcase classname="useOlMapReactionsLayer - util should return VectorLayer with valid Style" name="useOlMapReactionsLayer - util should return VectorLayer with valid Style" time="0.002"> </testcase> - <testcase classname="ReactionDrawer - component should show reference group with source=source2" name="ReactionDrawer - component should show reference group with source=source2" time="0.003"> + </testsuite> + <testsuite name="BioEntitiesPinsList - component " errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.598" tests="1"> + <testcase classname="BioEntitiesPinsList - component should display list of bio entites elements" name="BioEntitiesPinsList - component should display list of bio entites elements" time="0.07"> </testcase> </testsuite> - <testsuite name="GeneralOverlays - component" errors="0" failures="0" skipped="1" timestamp="2024-01-03T15:35:21" time="0.392" tests="6"> - <testcase classname="GeneralOverlays - component render should display PD substantia nigra overlay item" name="GeneralOverlays - component render should display PD substantia nigra overlay item" time="0.018"> + <testsuite name="UserOverlays component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.441" tests="4"> + <testcase classname="UserOverlays component renders loading message when user is loading" name="UserOverlays component renders loading message when user is loading" time="0.017"> </testcase> - <testcase classname="GeneralOverlays - component render should display Ageing brain overlay item" name="GeneralOverlays - component render should display Ageing brain overlay item" time="0.004"> + <testcase classname="UserOverlays component renders login button when user is not authenticated" name="UserOverlays component renders login button when user is not authenticated" time="0.011"> </testcase> - <testcase classname="GeneralOverlays - component render should display PRKN variants example overlay item" name="GeneralOverlays - component render should display PRKN variants example overlay item" time="0.004"> + <testcase classname="UserOverlays component dispatches openLoginModal action when Login button is clicked" name="UserOverlays component dispatches openLoginModal action when Login button is clicked" time="0.019"> </testcase> - <testcase classname="GeneralOverlays - component render should display PRKN variants doubled overlay item" name="GeneralOverlays - component render should display PRKN variants doubled overlay item" time="0.003"> + <testcase classname="UserOverlays component renders add overlay button when user is authenticated" name="UserOverlays component renders add overlay button when user is authenticated" time="0.012"> </testcase> - <testcase classname="GeneralOverlays - component render should display Generic advanced format overlay overlay item" name="GeneralOverlays - component render should display Generic advanced format overlay overlay item" time="0.003"> + </testsuite> + <testsuite name="BioEntitiesAccordion - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.536" tests="2"> + <testcase classname="BioEntitiesAccordion - component should display loading indicator when bioEntity search is pending" name="BioEntitiesAccordion - component should display loading indicator when bioEntity search is pending" time="0.054"> </testcase> - <testcase classname="GeneralOverlays - component view overlays should allow to turn on more then one overlay" name="GeneralOverlays - component view overlays should allow to turn on more then one overlay" time="0"> - <skipped/> + <testcase classname="BioEntitiesAccordion - component should render list of maps with number of entities after succeeded bio entity search" name="BioEntitiesAccordion - component should render list of maps with number of entities after succeeded bio entity search" time="0.018"> </testcase> </testsuite> - <testsuite name="DrugsAccordion - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.38" tests="5"> - <testcase classname="DrugsAccordion - component should display drugs number after succesfull drug search" name="DrugsAccordion - component should display drugs number after succesfull drug search" time="0.018"> + <testsuite name="ContextMenu - Component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.591" tests="6"> + <testcase classname="ContextMenu - Component when context menu is hidden should context menu has hidden class" name="ContextMenu - Component when context menu is hidden should context menu has hidden class" time="0.035"> </testcase> - <testcase classname="DrugsAccordion - component should display loading indicator while waiting for drug search response" name="DrugsAccordion - component should display loading indicator while waiting for drug search response" time="0.014"> + <testcase classname="ContextMenu - Component when context menu is shown should display context menu" name="ContextMenu - Component when context menu is shown should display context menu" time="0.003"> </testcase> - <testcase classname="DrugsAccordion - component should navigate user to drugs results list after clicking button" name="DrugsAccordion - component should navigate user to drugs results list after clicking button" time="0.003"> + <testcase classname="ContextMenu - Component when context menu is shown should display proper text when uniprot is not provided" name="ContextMenu - Component when context menu is shown should display proper text when uniprot is not provided" time="0.002"> </testcase> - <testcase classname="DrugsAccordion - component should disable navigation button when there is no drugs" name="DrugsAccordion - component should disable navigation button when there is no drugs" time="0.009"> + <testcase classname="ContextMenu - Component when context menu is shown should display proper text when uniprot is not provided" name="ContextMenu - Component when context menu is shown should display proper text when uniprot is not provided" time="0.005"> </testcase> - <testcase classname="DrugsAccordion - component should disable navigation button when waiting for api response" name="DrugsAccordion - component should disable navigation button when waiting for api response" time="0.002"> + <testcase classname="ContextMenu - Component when context menu is shown should display uniprot id as option if it is provided" name="ContextMenu - Component when context menu is shown should display uniprot id as option if it is provided" time="0.008"> + </testcase> + <testcase classname="ContextMenu - Component when context menu is shown should open molart modal when clicking on uniprot" name="ContextMenu - Component when context menu is shown should open molart modal when clicking on uniprot" time="0.012"> </testcase> </testsuite> - <testsuite name="useOverviewImageLinkActions - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.408" tests="9"> - <testcase classname="useOverviewImageLinkActions - hook when clicked on image link when image id is NOT valid should NOT fire action set overview image id" name="useOverviewImageLinkActions - hook when clicked on image link when image id is NOT valid should NOT fire action set overview image id" time="0.007"> + <testsuite name="useOverviewImageLinkActions - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.459" tests="9"> + <testcase classname="useOverviewImageLinkActions - hook when clicked on image link when image id is NOT valid should NOT fire action set overview image id" name="useOverviewImageLinkActions - hook when clicked on image link when image id is NOT valid should NOT fire action set overview image id" time="0.005"> </testcase> - <testcase classname="useOverviewImageLinkActions - hook when clicked on image link when image id is valid should fire action set overview image id" name="useOverviewImageLinkActions - hook when clicked on image link when image id is valid should fire action set overview image id" time="0"> + <testcase classname="useOverviewImageLinkActions - hook when clicked on image link when image id is valid should fire action set overview image id" name="useOverviewImageLinkActions - hook when clicked on image link when image id is valid should fire action set overview image id" time="0.001"> </testcase> - <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should set active map" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should set active map" time="0.006"> + <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should set active map" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should set active map" time="0.004"> </testcase> - <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should set map position" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should set map position" time="0.002"> + <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should set map position" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should set map position" time="0.001"> </testcase> <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should close modal" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is already opened should close modal" time="0"> </testcase> <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is not opened should open map and set as active" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is not opened should open map and set as active" time="0.001"> </testcase> - <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is not opened should set map position" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is not opened should set map position" time="0"> + <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is not opened should set map position" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is not opened should set map position" time="0.001"> </testcase> <testcase classname="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is not opened should close modal" name="useOverviewImageLinkActions - hook when clicked on model link when model is available when map is not opened should close modal" time="0.001"> </testcase> - <testcase classname="useOverviewImageLinkActions - hook when clicked on unsupported link should noop" name="useOverviewImageLinkActions - hook when clicked on unsupported link should noop" time="0.001"> + <testcase classname="useOverviewImageLinkActions - hook when clicked on unsupported link should noop" name="useOverviewImageLinkActions - hook when clicked on unsupported link should noop" time="0"> </testcase> </testsuite> - <testsuite name="useOverviewImageLinkConfigs - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.291" tests="3"> - <testcase classname="useOverviewImageLinkConfigs - hook when currentImage is undefined should return empty array" name="useOverviewImageLinkConfigs - hook when currentImage is undefined should return empty array" time="0.002"> + <testsuite name="ExcludedCompartmentPathways - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.524" tests="4"> + <testcase classname="ExcludedCompartmentPathways - component should display compartment / pathways checkboxes when fetching data is successful" name="ExcludedCompartmentPathways - component should display compartment / pathways checkboxes when fetching data is successful" time="0.074"> </testcase> - <testcase classname="useOverviewImageLinkConfigs - hook when sizeFactor is zero should return empty array" name="useOverviewImageLinkConfigs - hook when sizeFactor is zero should return empty array" time="0"> + <testcase classname="ExcludedCompartmentPathways - component should not display compartment / pathways checkboxes when fetching data fails" name="ExcludedCompartmentPathways - component should not display compartment / pathways checkboxes when fetching data fails" time="0.005"> </testcase> - <testcase classname="useOverviewImageLinkConfigs - hook when all args are valid should return correct value" name="useOverviewImageLinkConfigs - hook when all args are valid should return correct value" time="0.001"> + <testcase classname="ExcludedCompartmentPathways - component should not display compartment / pathways checkboxes when fetched data is empty" name="ExcludedCompartmentPathways - component should not display compartment / pathways checkboxes when fetched data is empty" time="0.005"> + </testcase> + <testcase classname="ExcludedCompartmentPathways - component should display loading message when fetching data is pending" name="ExcludedCompartmentPathways - component should display loading message when fetching data is pending" time="0.013"> </testcase> </testsuite> - <testsuite name="useOverviewImage - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.379" tests="3"> - <testcase classname="useOverviewImage - hook when image data is invalid should return default size of image and empty imageUrl" name="useOverviewImage - hook when image data is invalid should return default size of image and empty imageUrl" time="0.009"> + <testsuite name="DrugsAccordion - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.542" tests="5"> + <testcase classname="DrugsAccordion - component should display drugs number after succesfull drug search" name="DrugsAccordion - component should display drugs number after succesfull drug search" time="0.039"> + </testcase> + <testcase classname="DrugsAccordion - component should display loading indicator while waiting for drug search response" name="DrugsAccordion - component should display loading indicator while waiting for drug search response" time="0.015"> </testcase> - <testcase classname="useOverviewImage - hook when containerReact is undefined should return default size of image and valid imageUrl" name="useOverviewImage - hook when containerReact is undefined should return default size of image and valid imageUrl" time="0.001"> + <testcase classname="DrugsAccordion - component should navigate user to drugs results list after clicking button" name="DrugsAccordion - component should navigate user to drugs results list after clicking button" time="0.009"> </testcase> - <testcase classname="useOverviewImage - hook when containerReact is valid should return size of image and valid imageUrl" name="useOverviewImage - hook when containerReact is valid should return size of image and valid imageUrl" time="0.004"> + <testcase classname="DrugsAccordion - component should disable navigation button when there is no drugs" name="DrugsAccordion - component should disable navigation button when there is no drugs" time="0.004"> + </testcase> + <testcase classname="DrugsAccordion - component should disable navigation button when waiting for api response" name="DrugsAccordion - component should disable navigation button when waiting for api response" time="0.002"> </testcase> </testsuite> - <testsuite name="useOverviewImageSize - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.347" tests="3"> - <testcase classname="useOverviewImageSize - hook when currentImage is not valid should return default value" name="useOverviewImageSize - hook when currentImage is not valid should return default value" time="0.005"> + <testsuite name="GeneralOverlays - component" errors="0" failures="0" skipped="1" timestamp="2024-01-12T14:39:44" time="0.539" tests="6"> + <testcase classname="GeneralOverlays - component render should display PD substantia nigra overlay item" name="GeneralOverlays - component render should display PD substantia nigra overlay item" time="0.021"> </testcase> - <testcase classname="useOverviewImageSize - hook when containerRect is not valid should return default value" name="useOverviewImageSize - hook when containerRect is not valid should return default value" time="0"> + <testcase classname="GeneralOverlays - component render should display Ageing brain overlay item" name="GeneralOverlays - component render should display Ageing brain overlay item" time="0.017"> </testcase> - <testcase classname="useOverviewImageSize - hook when data is valid should return calculated height, width, sizeFactor" name="useOverviewImageSize - hook when data is valid should return calculated height, width, sizeFactor" time="0.001"> + <testcase classname="GeneralOverlays - component render should display PRKN variants example overlay item" name="GeneralOverlays - component render should display PRKN variants example overlay item" time="0.005"> </testcase> - </testsuite> - <testsuite name="DrawerHeadingBackwardButton - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.335" tests="3"> - <testcase classname="DrawerHeadingBackwardButton - component should render passed values" name="DrawerHeadingBackwardButton - component should render passed values" time="0.03"> + <testcase classname="GeneralOverlays - component render should display PRKN variants doubled overlay item" name="GeneralOverlays - component render should display PRKN variants doubled overlay item" time="0.003"> </testcase> - <testcase classname="DrawerHeadingBackwardButton - component should call backward function on back button click" name="DrawerHeadingBackwardButton - component should call backward function on back button click" time="0.007"> + <testcase classname="GeneralOverlays - component render should display Generic advanced format overlay overlay item" name="GeneralOverlays - component render should display Generic advanced format overlay overlay item" time="0.01"> </testcase> - <testcase classname="DrawerHeadingBackwardButton - component should call class drawer on close button click" name="DrawerHeadingBackwardButton - component should call class drawer on close button click" time="0.018"> + <testcase classname="GeneralOverlays - component view overlays should allow to turn on more then one overlay" name="GeneralOverlays - component view overlays should allow to turn on more then one overlay" time="0"> + <skipped/> </testcase> </testsuite> - <testsuite name="MapAdditionalOptions - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.324" tests="3"> - <testcase classname="MapAdditionalOptions - component should display background selector" name="MapAdditionalOptions - component should display background selector" time="0.016"> + <testsuite name="OverlaysLegends - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.489" tests="6"> + <testcase classname="OverlaysLegends - component when active overlays are empty should not render list of overlays legends" name="OverlaysLegends - component when active overlays are empty should not render list of overlays legends" time="0.012"> </testcase> - <testcase classname="MapAdditionalOptions - component should render browse overview images button" name="MapAdditionalOptions - component should render browse overview images button" time="0.003"> + <testcase classname="OverlaysLegends - component when active overlays are present should render overlay legend" name="OverlaysLegends - component when active overlays are present should render overlay legend" time="0.006"> + </testcase> + <testcase classname="OverlaysLegends - component when active overlays are present should render overlay legend" name="OverlaysLegends - component when active overlays are present should render overlay legend" time="0.008"> </testcase> - <testcase classname="MapAdditionalOptions - component should open overview image modal on button click" name="MapAdditionalOptions - component should open overview image modal on button click" time="0.004"> + <testcase classname="OverlaysLegends - component when active overlays are present should render overlay legend" name="OverlaysLegends - component when active overlays are present should render overlay legend" time="0.002"> + </testcase> + <testcase classname="OverlaysLegends - component when active overlays are present should render overlay legend" name="OverlaysLegends - component when active overlays are present should render overlay legend" time="0.003"> + </testcase> + <testcase classname="OverlaysLegends - component when active overlays are present should render overlay legend" name="OverlaysLegends - component when active overlays are present should render overlay legend" time="0.005"> </testcase> </testsuite> - <testsuite name="SearchDrawerTabs - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.312" tests="2"> - <testcase classname="SearchDrawerTabs - component should display tabs with search values" name="SearchDrawerTabs - component should display tabs with search values" time="0.016"> + <testsuite name="CheckboxFilter - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.298" tests="11"> + <testcase classname="CheckboxFilter - component should render CheckboxFilter properly" name="CheckboxFilter - component should render CheckboxFilter properly" time="0.018"> + </testcase> + <testcase classname="CheckboxFilter - component should filter options based on search term" name="CheckboxFilter - component should filter options based on search term" time="0.012"> + </testcase> + <testcase classname="CheckboxFilter - component should handle checkbox value change" name="CheckboxFilter - component should handle checkbox value change" time="0.008"> </testcase> - <testcase classname="SearchDrawerTabs - component second test" name="SearchDrawerTabs - component second test" time="0.007"> + <testcase classname="CheckboxFilter - component should call onFilterChange when searching new term" name="CheckboxFilter - component should call onFilterChange when searching new term" time="0.005"> + </testcase> + <testcase classname="CheckboxFilter - component should display message when no elements are found" name="CheckboxFilter - component should display message when no elements are found" time="0.004"> + </testcase> + <testcase classname="CheckboxFilter - component should display message when options are empty" name="CheckboxFilter - component should display message when options are empty" time="0.003"> + </testcase> + <testcase classname="CheckboxFilter - component should handle multiple checkbox selection" name="CheckboxFilter - component should handle multiple checkbox selection" time="0.006"> + </testcase> + <testcase classname="CheckboxFilter - component should handle unchecking a checkbox" name="CheckboxFilter - component should handle unchecking a checkbox" time="0.009"> + </testcase> + <testcase classname="CheckboxFilter - component should render search input when isSearchEnabled is true" name="CheckboxFilter - component should render search input when isSearchEnabled is true" time="0.02"> + </testcase> + <testcase classname="CheckboxFilter - component should not render search input when isSearchEnabled is false" name="CheckboxFilter - component should not render search input when isSearchEnabled is false" time="0.002"> + </testcase> + <testcase classname="CheckboxFilter - component should not filter options based on search input when isSearchEnabled is false" name="CheckboxFilter - component should not filter options based on search input when isSearchEnabled is false" time="0.002"> </testcase> </testsuite> - <testsuite name="useEmptyBackground - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.273" tests="2"> - <testcase classname="useEmptyBackground - hook returns setEmptyBackground function should not set background to "Empty" if its not available" name="useEmptyBackground - hook returns setEmptyBackground function should not set background to "Empty" if its not available" time="0.009"> + <testsuite name="useUserOverlayForm" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.358" tests="4"> + <testcase classname="useUserOverlayForm should update state when form fields are changed" name="useUserOverlayForm should update state when form fields are changed" time="0.017"> </testcase> - <testcase classname="useEmptyBackground - hook returns setEmptyBackground function should set background to "Empty" if its available" name="useEmptyBackground - hook returns setEmptyBackground function should set background to "Empty" if its available" time="0.004"> + <testcase classname="useUserOverlayForm should update overlayContent when handleChangeOverlayContent is called" name="useUserOverlayForm should update overlayContent when handleChangeOverlayContent is called" time="0.003"> + </testcase> + <testcase classname="useUserOverlayForm should update elementsList and overlayContent when handleChangeElementsList is called" name="useUserOverlayForm should update elementsList and overlayContent when handleChangeElementsList is called" time="0.012"> + </testcase> + <testcase classname="useUserOverlayForm should update state variables based on updateUserOverlayForm" name="useUserOverlayForm should update state variables based on updateUserOverlayForm" time="0.005"> </testcase> </testsuite> - <testsuite name="OverviewImagesModal - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.337" tests="4"> - <testcase classname="OverviewImagesModal - component when currentImage is NOT valid should not render component" name="OverviewImagesModal - component when currentImage is NOT valid should not render component" time="0.01"> + <testsuite name="onMapSingleClick - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.393" tests="5"> + <testcase classname="onMapSingleClick - util when always should fire data reset handler" name="onMapSingleClick - util when always should fire data reset handler" time="0.029"> + </testcase> + <testcase classname="onMapSingleClick - util when searchResults are undefined does not fire search result action" name="onMapSingleClick - util when searchResults are undefined does not fire search result action" time="0.001"> </testcase> - <testcase classname="OverviewImagesModal - component when currentImage is valid should render component" name="OverviewImagesModal - component when currentImage is valid should render component" time="0.033"> + <testcase classname="onMapSingleClick - util when searchResults are empty does not fire search result action" name="onMapSingleClick - util when searchResults are empty does not fire search result action" time="0"> </testcase> - <testcase classname="OverviewImagesModal - component when currentImage is valid should render image with valid src" name="OverviewImagesModal - component when currentImage is valid should render image with valid src" time="0.003"> + <testcase classname="onMapSingleClick - util when searchResults are valid when results type is ALIAS does fire search result action handler" name="onMapSingleClick - util when searchResults are valid when results type is ALIAS does fire search result action handler" time="0.009"> </testcase> - <testcase classname="OverviewImagesModal - component when currentImage is valid should render image wrapper with valid size" name="OverviewImagesModal - component when currentImage is valid should render image wrapper with valid size" time="0.005"> + <testcase classname="onMapSingleClick - util when searchResults are valid when results type is REACTION does fire search result action - handle reaction" name="onMapSingleClick - util when searchResults are valid when results type is REACTION does fire search result action - handle reaction" time="0.002"> </testcase> </testsuite> - <testsuite name="usePointToProjection - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.288" tests="3"> - <testcase classname="usePointToProjection - util when mapSize arg is undefined in redux should return fallback value on function call" name="usePointToProjection - util when mapSize arg is undefined in redux should return fallback value on function call" time="0.035"> + <testsuite name="handleBioEntityResults - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.405" tests="2"> + <testcase classname="handleBioEntityResults - util should run setCurrentSelectedBioEntityId as first action" name="handleBioEntityResults - util should run setCurrentSelectedBioEntityId as first action" time="0.003"> </testcase> - <testcase classname="usePointToProjection - util when mapSize arg is invalid in redux should return fallback value on function call" name="usePointToProjection - util when mapSize arg is invalid in redux should return fallback value on function call" time="0.002"> + <testcase classname="handleBioEntityResults - util should run getMultiBioEntity as second action" name="handleBioEntityResults - util should run getMultiBioEntity as second action" time="0.001"> + </testcase> + </testsuite> + <testsuite name="ResultsList - component " errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:44" time="0.472" tests="2"> + <testcase classname="ResultsList - component should render results and navigation panel" name="ResultsList - component should render results and navigation panel" time="0.053"> </testcase> - <testcase classname="usePointToProjection - util when all args are valid in redux should return valid lat lng value on function call" name="usePointToProjection - util when all args are valid in redux should return valid lat lng value on function call" time="0.002"> + <testcase classname="ResultsList - component should navigate to grouped search results after backward button click" name="ResultsList - component should navigate to grouped search results after backward button click" time="0.039"> </testcase> </testsuite> - <testsuite name="useOverviewImageUrl - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.285" tests="2"> - <testcase classname="useOverviewImageUrl - hook when currentImage data is valid should return valid url" name="useOverviewImageUrl - hook when currentImage data is valid should return valid url" time="0.019"> + <testsuite name="overlays reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.37" tests="7"> + <testcase classname="overlays reducer should match initial state" name="overlays reducer should match initial state" time="0.002"> </testcase> - <testcase classname="useOverviewImageUrl - hook when currentImage data is valid should return valid url" name="useOverviewImageUrl - hook when currentImage data is valid should return valid url" time="0.002"> + <testcase classname="overlays reducer should update store after successful getAllPublicOverlaysByProjectId query" name="overlays reducer should update store after successful getAllPublicOverlaysByProjectId query" time="0.004"> + </testcase> + <testcase classname="overlays reducer should update store after failed getAllPublicOverlaysByProjectId query" name="overlays reducer should update store after failed getAllPublicOverlaysByProjectId query" time="0.078"> + </testcase> + <testcase classname="overlays reducer should update store on loading getAllPublicOverlaysByProjectId query" name="overlays reducer should update store on loading getAllPublicOverlaysByProjectId query" time="0.002"> + </testcase> + <testcase classname="overlays reducer should update store when addOverlay is pending" name="overlays reducer should update store when addOverlay is pending" time="0.006"> + </testcase> + <testcase classname="overlays reducer should update store after successful addOverlay" name="overlays reducer should update store after successful addOverlay" time="0.005"> + </testcase> + <testcase classname="overlays reducer should update store after failed addOverlay" name="overlays reducer should update store after failed addOverlay" time="0.001"> + </testcase> + </testsuite> + <testsuite name="useOlMapPinsLayer - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.45" tests="1"> + <testcase classname="useOlMapPinsLayer - util should return VectorLayer" name="useOlMapPinsLayer - util should return VectorLayer" time="0.012"> </testcase> </testsuite> - <testsuite name="DrawerHeading - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.304" tests="2"> - <testcase classname="DrawerHeading - component should display passed title" name="DrawerHeading - component should display passed title" time="0.029"> + <testsuite name="SearchDrawerTabs - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.394" tests="2"> + <testcase classname="SearchDrawerTabs - component should display tabs with search values" name="SearchDrawerTabs - component should display tabs with search values" time="0.02"> </testcase> - <testcase classname="DrawerHeading - component should call class drawer on close button click" name="DrawerHeading - component should call class drawer on close button click" time="0.027"> + <testcase classname="SearchDrawerTabs - component second test" name="SearchDrawerTabs - component second test" time="0.012"> </testcase> </testsuite> - <testsuite name="map thunks - utils" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.269" tests="10"> - <testcase classname="map thunks - utils getBackgroundId should return backgroundId value from queryData" name="map thunks - utils getBackgroundId should return backgroundId value from queryData" time="0.001"> + <testsuite name="BackgroundSelector - component" errors="0" failures="0" skipped="1" timestamp="2024-01-12T14:39:45" time="0.521" tests="6"> + <testcase classname="BackgroundSelector - component should initialy display default value" name="BackgroundSelector - component should initialy display default value" time="0.028"> </testcase> - <testcase classname="map thunks - utils getBackgroundId should return main map background id if query param does not include background id" name="map thunks - utils getBackgroundId should return main map background id if query param does not include background id" time="0"> + <testcase classname="BackgroundSelector - component should display selected value name when it's not main background" name="BackgroundSelector - component should display selected value name when it's not main background" time="0.033"> </testcase> - <testcase classname="map thunks - utils getBackgroundId should return default value (0) if query data does not include backgroundId and could not find main background in the store" name="map thunks - utils getBackgroundId should return default value (0) if query data does not include backgroundId and could not find main background in the store" time="0"> + <testcase classname="BackgroundSelector - component should change redux map state on selecting background" name="BackgroundSelector - component should change redux map state on selecting background" time="0.013"> </testcase> - <testcase classname="map thunks - utils getInitMapPosition should return valid map position from query params " name="map thunks - utils getInitMapPosition should return valid map position from query params " time="0"> + <testcase classname="BackgroundSelector - component query params should display default value when main background id is in query params" name="BackgroundSelector - component query params should display default value when main background id is in query params" time="0.006"> </testcase> - <testcase classname="map thunks - utils getInitMapPosition should return valid map position if query params do not include position" name="map thunks - utils getInitMapPosition should return valid map position if query params do not include position" time="0"> + <testcase classname="BackgroundSelector - component query params should display correct background when background id is in query params" name="BackgroundSelector - component query params should display correct background when background id is in query params" time="0.002"> </testcase> - <testcase classname="map thunks - utils getInitMapPosition should return default map position" name="map thunks - utils getInitMapPosition should return default map position" time="0.001"> + <testcase classname="BackgroundSelector - component query params should set backgroundid in query on selecting background" name="BackgroundSelector - component query params should set backgroundid in query on selecting background" time="0"> + <skipped/> </testcase> - <testcase classname="map thunks - utils getInitMapSizeAndModelId should return correct mapsize and modelid when modelId is provided in queryData" name="map thunks - utils getInitMapSizeAndModelId should return correct mapsize and modelid when modelId is provided in queryData" time="0"> + </testsuite> + <testsuite name="LegendHeader - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.444" tests="3"> + <testcase classname="LegendHeader - component should render legend title" name="LegendHeader - component should render legend title" time="0.023"> </testcase> - <testcase classname="map thunks - utils getInitMapSizeAndModelId should return correct mapsize and modelId if query params do not include modelId" name="map thunks - utils getInitMapSizeAndModelId should return correct mapsize and modelId if query params do not include modelId" time="0"> + <testcase classname="LegendHeader - component should render legend close button" name="LegendHeader - component should render legend close button" time="0.01"> </testcase> - <testcase classname="map thunks - utils getOpenedMaps should return main map only" name="map thunks - utils getOpenedMaps should return main map only" time="0"> + <testcase classname="LegendHeader - component should close legend on close button click" name="LegendHeader - component should close legend on close button click" time="0.022"> + </testcase> + </testsuite> + <testsuite name="Columns - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.356" tests="2"> + <testcase classname="Columns - component should display select column accordion" name="Columns - component should display select column accordion" time="0.048"> </testcase> - <testcase classname="map thunks - utils getOpenedMaps should return main map and opened submap" name="map thunks - utils getOpenedMaps should return main map and opened submap" time="0"> + <testcase classname="Columns - component should display columns checkboxes" name="Columns - component should display columns checkboxes" time="0.041"> </testcase> </testsuite> - <testsuite name="onMapPositionChange - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.277" tests="2"> - <testcase classname="onMapPositionChange - util should set map data position to valid one" name="onMapPositionChange - util should set map data position to valid one" time="0.011"> + <testsuite name="useOverviewImageLinkConfigs - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.379" tests="3"> + <testcase classname="useOverviewImageLinkConfigs - hook when currentImage is undefined should return empty array" name="useOverviewImageLinkConfigs - hook when currentImage is undefined should return empty array" time="0.002"> + </testcase> + <testcase classname="useOverviewImageLinkConfigs - hook when sizeFactor is zero should return empty array" name="useOverviewImageLinkConfigs - hook when sizeFactor is zero should return empty array" time="0"> </testcase> - <testcase classname="onMapPositionChange - util should set map data position to valid one" name="onMapPositionChange - util should set map data position to valid one" time="0.002"> + <testcase classname="useOverviewImageLinkConfigs - hook when all args are valid should return correct value" name="useOverviewImageLinkConfigs - hook when all args are valid should return correct value" time="0"> </testcase> </testsuite> - <testsuite name="NavBar - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.311" tests="1"> - <testcase classname="NavBar - component Should contain navigation buttons and logos with powered by info" name="NavBar - component Should contain navigation buttons and logos with powered by info" time="0.026"> + <testsuite name="OverlaySelector component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.334" tests="2"> + <testcase classname="OverlaySelector component renders the component with initial values" name="OverlaySelector component renders the component with initial values" time="0.031"> + </testcase> + <testcase classname="OverlaySelector component opens the dropdown and selects an item" name="OverlaySelector component opens the dropdown and selects an item" time="0.033"> </testcase> </testsuite> - <testsuite name="bioEntity reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.33" tests="4"> - <testcase classname="bioEntity reducer should match initial state" name="bioEntity reducer should match initial state" time="0.003"> + <testsuite name="handleReactionResults - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.46" tests="4"> + <testcase classname="handleReactionResults - util should run getReactionsByIds as first action" name="handleReactionResults - util should run getReactionsByIds as first action" time="0.003"> </testcase> - <testcase classname="bioEntity reducer should update store after succesfull getBioEntity query" name="bioEntity reducer should update store after succesfull getBioEntity query" time="0.013"> + <testcase classname="handleReactionResults - util should run openReactionDrawerById to empty array as second action" name="handleReactionResults - util should run openReactionDrawerById to empty array as second action" time="0.001"> </testcase> - <testcase classname="bioEntity reducer should update store after failed getBioEntity query" name="bioEntity reducer should update store after failed getBioEntity query" time="0.079"> + <testcase classname="handleReactionResults - util should run setBioEntityContent to empty array as third action" name="handleReactionResults - util should run setBioEntityContent to empty array as third action" time="0"> </testcase> - <testcase classname="bioEntity reducer should update store on loading getBioEntity query" name="bioEntity reducer should update store on loading getBioEntity query" time="0.008"> + <testcase classname="handleReactionResults - util should run getBioEntity as fourth action" name="handleReactionResults - util should run getBioEntity as fourth action" time="0"> </testcase> </testsuite> - <testsuite name="backgrounds reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.246" tests="4"> - <testcase classname="backgrounds reducer should match initial state" name="backgrounds reducer should match initial state" time="0.011"> + <testsuite name="MapAdditionalOptions - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.466" tests="3"> + <testcase classname="MapAdditionalOptions - component should display background selector" name="MapAdditionalOptions - component should display background selector" time="0.039"> </testcase> - <testcase classname="backgrounds reducer should update store after succesfull getAllBackgroundsByProjectId query" name="backgrounds reducer should update store after succesfull getAllBackgroundsByProjectId query" time="0.005"> + <testcase classname="MapAdditionalOptions - component should render browse overview images button" name="MapAdditionalOptions - component should render browse overview images button" time="0.003"> </testcase> - <testcase classname="backgrounds reducer should update store after failed getAllBackgroundsByProjectId query" name="backgrounds reducer should update store after failed getAllBackgroundsByProjectId query" time="0.077"> + <testcase classname="MapAdditionalOptions - component should open overview image modal on button click" name="MapAdditionalOptions - component should open overview image modal on button click" time="0.005"> </testcase> - <testcase classname="backgrounds reducer should update store on loading getAllBackgroundsByProjectId query" name="backgrounds reducer should update store on loading getAllBackgroundsByProjectId query" time="0.001"> + </testsuite> + <testsuite name="useReduxBusQueryManager - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.399" tests="3"> + <testcase classname="useReduxBusQueryManager - util on init when data is NOT loaded should not update query" name="useReduxBusQueryManager - util on init when data is NOT loaded should not update query" time="0.01"> + </testcase> + <testcase classname="useReduxBusQueryManager - util on init when data is loaded should update query" name="useReduxBusQueryManager - util on init when data is loaded should update query" time="0.007"> + </testcase> + <testcase classname="useReduxBusQueryManager - util on init when data is loaded should update query params to valid ones" name="useReduxBusQueryManager - util on init when data is loaded should update query params to valid ones" time="0.004"> </testcase> </testsuite> - <testsuite name="drugs reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.314" tests="4"> - <testcase classname="drugs reducer should match initial state" name="drugs reducer should match initial state" time="0.002"> + <testsuite name="Types Component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.433" tests="1"> + <testcase classname="Types Component renders without crashing" name="Types Component renders without crashing" time="0.038"> </testcase> - <testcase classname="drugs reducer should update store after succesfull getDrugs query" name="drugs reducer should update store after succesfull getDrugs query" time="0.016"> + </testsuite> + <testsuite name="IconButton - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.284" tests="3"> + <testcase classname="IconButton - component should render IconButton" name="IconButton - component should render IconButton" time="0.034"> </testcase> - <testcase classname="drugs reducer should update store after failed getDrugs query" name="drugs reducer should update store after failed getDrugs query" time="0.099"> + <testcase classname="IconButton - component should render IconButton with plugin icon" name="IconButton - component should render IconButton with plugin icon" time="0.002"> </testcase> - <testcase classname="drugs reducer should update store on loading getDrugs query" name="drugs reducer should update store on loading getDrugs query" time="0.014"> + <testcase classname="IconButton - component should render IconButton as active" name="IconButton - component should render IconButton as active" time="0.002"> </testcase> </testsuite> - <testsuite name="IconButton - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.232" tests="3"> - <testcase classname="IconButton - component should render IconButton" name="IconButton - component should render IconButton" time="0.013"> + <testsuite name="statistics reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.404" tests="3"> + <testcase classname="statistics reducer should match initial state" name="statistics reducer should match initial state" time="0.002"> + </testcase> + <testcase classname="statistics reducer should update store after successful getStatisticById query" name="statistics reducer should update store after successful getStatisticById query" time="0.005"> </testcase> - <testcase classname="IconButton - component should render IconButton with plugin icon" name="IconButton - component should render IconButton with plugin icon" time="0.01"> + <testcase classname="statistics reducer should update store after failed getStatisticById query" name="statistics reducer should update store after failed getStatisticById query" time="0.119"> </testcase> - <testcase classname="IconButton - component should render IconButton as active" name="IconButton - component should render IconButton as active" time="0.004"> + </testsuite> + <testsuite name="useOverviewImageUrl - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.381" tests="2"> + <testcase classname="useOverviewImageUrl - hook when currentImage data is valid should return valid url" name="useOverviewImageUrl - hook when currentImage data is valid should return valid url" time="0.008"> + </testcase> + <testcase classname="useOverviewImageUrl - hook when currentImage data is valid should return valid url" name="useOverviewImageUrl - hook when currentImage data is valid should return valid url" time="0.004"> </testcase> </testsuite> - <testsuite name="chemicals reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:22" time="0.279" tests="4"> - <testcase classname="chemicals reducer should match initial state" name="chemicals reducer should match initial state" time="0.004"> + <testsuite name="PerfectMatchSwitch - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.459" tests="4"> + <testcase classname="PerfectMatchSwitch - component should initialy be set to false when perfectMatch is not in query or set to false" name="PerfectMatchSwitch - component should initialy be set to false when perfectMatch is not in query or set to false" time="0.036"> </testcase> - <testcase classname="chemicals reducer should update store after succesfull getChemicals query" name="chemicals reducer should update store after succesfull getChemicals query" time="0.025"> + <testcase classname="PerfectMatchSwitch - component should initialy be set to true when perfectMatch query is set to true" name="PerfectMatchSwitch - component should initialy be set to true when perfectMatch query is set to true" time="0.018"> </testcase> - <testcase classname="chemicals reducer should update store after failed getChemicals query" name="chemicals reducer should update store after failed getChemicals query" time="0.077"> + <testcase classname="PerfectMatchSwitch - component should set checkbox to true and update store" name="PerfectMatchSwitch - component should set checkbox to true and update store" time="0.014"> </testcase> - <testcase classname="chemicals reducer should update store on loading getChemicals query" name="chemicals reducer should update store on loading getChemicals query" time="0.011"> + <testcase classname="PerfectMatchSwitch - component should set checkbox to false and update store" name="PerfectMatchSwitch - component should set checkbox to false and update store" time="0.02"> </testcase> </testsuite> - <testsuite name="handleDataReset" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.226" tests="1"> - <testcase classname="handleDataReset should dispatch reset actions" name="handleDataReset should dispatch reset actions" time="0.006"> + <testsuite name="DrawerHeading - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.401" tests="2"> + <testcase classname="DrawerHeading - component should display passed title" name="DrawerHeading - component should display passed title" time="0.02"> + </testcase> + <testcase classname="DrawerHeading - component should call class drawer on close button click" name="DrawerHeading - component should call class drawer on close button click" time="0.023"> </testcase> </testsuite> - <testsuite name="overlays reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.249" tests="4"> - <testcase classname="overlays reducer should match initial state" name="overlays reducer should match initial state" time="0.002"> + <testsuite name="useEmptyBackground - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:45" time="0.464" tests="2"> + <testcase classname="useEmptyBackground - hook returns setEmptyBackground function should not set background to "Empty" if its not available" name="useEmptyBackground - hook returns setEmptyBackground function should not set background to "Empty" if its not available" time="0.012"> </testcase> - <testcase classname="overlays reducer should update store after succesfull getAllPublicOverlaysByProjectId query" name="overlays reducer should update store after succesfull getAllPublicOverlaysByProjectId query" time="0.005"> + <testcase classname="useEmptyBackground - hook returns setEmptyBackground function should set background to "Empty" if its available" name="useEmptyBackground - hook returns setEmptyBackground function should set background to "Empty" if its available" time="0.004"> </testcase> - <testcase classname="overlays reducer should update store after failed getAllPublicOverlaysByProjectId query" name="overlays reducer should update store after failed getAllPublicOverlaysByProjectId query" time="0.092"> + </testsuite> + <testsuite name="onMapPositionChange - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.449" tests="2"> + <testcase classname="onMapPositionChange - util should set map data position to valid one" name="onMapPositionChange - util should set map data position to valid one" time="0.022"> </testcase> - <testcase classname="overlays reducer should update store on loading getAllPublicOverlaysByProjectId query" name="overlays reducer should update store on loading getAllPublicOverlaysByProjectId query" time="0.007"> + <testcase classname="onMapPositionChange - util should set map data position to valid one" name="onMapPositionChange - util should set map data position to valid one" time="0.007"> </testcase> </testsuite> - <testsuite name="models reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.242" tests="4"> - <testcase classname="models reducer should match initial state" name="models reducer should match initial state" time="0.002"> + <testsuite name="NavBar - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.387" tests="1"> + <testcase classname="NavBar - component Should contain navigation buttons and logos with powered by info" name="NavBar - component Should contain navigation buttons and logos with powered by info" time="0.067"> </testcase> - <testcase classname="models reducer should update store after succesfull getModels query" name="models reducer should update store after succesfull getModels query" time="0.007"> + </testsuite> + <testsuite name="CookieBanner component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.373" tests="3"> + <testcase classname="CookieBanner component renders cookie banner correctly first time" name="CookieBanner component renders cookie banner correctly first time" time="0.029"> </testcase> - <testcase classname="models reducer should update store after failed getModels query" name="models reducer should update store after failed getModels query" time="0.074"> + <testcase classname="CookieBanner component hides the banner after accepting cookies" name="CookieBanner component hides the banner after accepting cookies" time="0.013"> </testcase> - <testcase classname="models reducer should update store on loading getModels query" name="models reducer should update store on loading getModels query" time="0.003"> + <testcase classname="CookieBanner component does not render the cookies banner when cookies are accepted" name="CookieBanner component does not render the cookies banner when cookies are accepted" time="0.004"> </testcase> </testsuite> - <testsuite name="UserAvatar - component " errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.245" tests="1"> - <testcase classname="UserAvatar - component should render placeholder image" name="UserAvatar - component should render placeholder image" time="0.014"> + <testsuite name="drugs reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.387" tests="4"> + <testcase classname="drugs reducer should match initial state" name="drugs reducer should match initial state" time="0.011"> + </testcase> + <testcase classname="drugs reducer should update store after succesfull getDrugs query" name="drugs reducer should update store after succesfull getDrugs query" time="0.027"> + </testcase> + <testcase classname="drugs reducer should update store after failed getDrugs query" name="drugs reducer should update store after failed getDrugs query" time="0.106"> + </testcase> + <testcase classname="drugs reducer should update store on loading getDrugs query" name="drugs reducer should update store on loading getDrugs query" time="0.025"> </testcase> </testsuite> - <testsuite name="map middleware" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.244" tests="3"> - <testcase classname="map middleware on listen when model is valid and different than current should dispatch setMapData, map/setMapData" name="map middleware on listen when model is valid and different than current should dispatch setMapData, map/setMapData" time="0.002"> + <testsuite name="OverlaySingleLegend - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.374" tests="2"> + <testcase classname="OverlaySingleLegend - component should render title with overlay name" name="OverlaySingleLegend - component should render title with overlay name" time="0.031"> </testcase> - <testcase classname="map middleware on listen when model is valid and identical with current should NOT dispatch setMapData" name="map middleware on listen when model is valid and identical with current should NOT dispatch setMapData" time="0.001"> + <testcase classname="OverlaySingleLegend - component should render image with valid src and alt" name="OverlaySingleLegend - component should render image with valid src and alt" time="0.003"> </testcase> - <testcase classname="map middleware on listen when model is NOT valid should NOT dispatch setMapData" name="map middleware on listen when model is NOT valid should NOT dispatch setMapData" time="0"> + </testsuite> + <testsuite name="Button - component " errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.327" tests="1"> + <testcase classname="Button - component should render name Button" name="Button - component should render name Button" time="0.032"> </testcase> </testsuite> - <testsuite name="Button - component " errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.252" tests="1"> - <testcase classname="Button - component should render name Button" name="Button - component should render name Button" time="0.014"> + <testsuite name="useOverviewImage - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.436" tests="3"> + <testcase classname="useOverviewImage - hook when image data is invalid should return default size of image and empty imageUrl" name="useOverviewImage - hook when image data is invalid should return default size of image and empty imageUrl" time="0.003"> + </testcase> + <testcase classname="useOverviewImage - hook when containerReact is undefined should return default size of image and valid imageUrl" name="useOverviewImage - hook when containerReact is undefined should return default size of image and valid imageUrl" time="0"> + </testcase> + <testcase classname="useOverviewImage - hook when containerReact is valid should return size of image and valid imageUrl" name="useOverviewImage - hook when containerReact is valid should return size of image and valid imageUrl" time="0.001"> </testcase> </testsuite> - <testsuite name="bioEntityContents thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.252" tests="2"> - <testcase classname="bioEntityContents thunks getBioEntityContents should return data when data response from API is valid" name="bioEntityContents thunks getBioEntityContents should return data when data response from API is valid" time="0.014"> + <testsuite name="Input - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.268" tests="8"> + <testcase classname="Input - component should render with proper testid" name="Input - component should render with proper testid" time="0.012"> + </testcase> + <testcase classname="Input - component should apply the default style and size variants when none are provided" name="Input - component should apply the default style and size variants when none are provided" time="0.001"> + </testcase> + <testcase classname="Input - component should apply the specified style variant" name="Input - component should apply the specified style variant" time="0.001"> + </testcase> + <testcase classname="Input - component should apply the specified size variant" name="Input - component should apply the specified size variant" time="0.001"> + </testcase> + <testcase classname="Input - component should merge custom class with style and size variant classes" name="Input - component should merge custom class with style and size variant classes" time="0.001"> </testcase> - <testcase classname="bioEntityContents thunks getBioEntityContents should return undefined when data response from API is not valid " name="bioEntityContents thunks getBioEntityContents should return undefined when data response from API is not valid " time="0.018"> + <testcase classname="Input - component should handle onChange event" name="Input - component should handle onChange event" time="0.003"> + </testcase> + <testcase classname="Input - component should render with a placeholder" name="Input - component should render with a placeholder" time="0.002"> + </testcase> + <testcase classname="Input - component should render with a default value" name="Input - component should render with a default value" time="0.001"> </testcase> </testsuite> - <testsuite name="reactions thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.181" tests="3"> - <testcase classname="reactions thunks getReactionsByIds should return data when data response from API is valid" name="reactions thunks getReactionsByIds should return data when data response from API is valid" time="0.008"> + <testsuite name="Textarea - Component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.308" tests="7"> + <testcase classname="Textarea - Component should render with proper testid" name="Textarea - Component should render with proper testid" time="0.015"> + </testcase> + <testcase classname="Textarea - Component should apply the default style variant when none is provided" name="Textarea - Component should apply the default style variant when none is provided" time="0.002"> + </testcase> + <testcase classname="Textarea - Component should apply the specified style variant" name="Textarea - Component should apply the specified style variant" time="0.001"> </testcase> - <testcase classname="reactions thunks getReactionsByIds should return undefined when data response from API is not valid " name="reactions thunks getReactionsByIds should return undefined when data response from API is not valid " time="0.007"> + <testcase classname="Textarea - Component should merge custom class with style variant classes" name="Textarea - Component should merge custom class with style variant classes" time="0.001"> </testcase> - <testcase classname="reactions thunks getReactionsByIds should return empty array when data response from API is empty" name="reactions thunks getReactionsByIds should return empty array when data response from API is empty" time="0.013"> + <testcase classname="Textarea - Component should handle onChange event" name="Textarea - Component should handle onChange event" time="0.007"> + </testcase> + <testcase classname="Textarea - Component should render with a placeholder" name="Textarea - Component should render with a placeholder" time="0.001"> + </testcase> + <testcase classname="Textarea - Component should render with a default value" name="Textarea - Component should render with a default value" time="0.001"> </testcase> </testsuite> - <testsuite name="user reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.188" tests="4"> - <testcase classname="user reducer should match initial state" name="user reducer should match initial state" time="0.003"> + <testsuite name="useOverviewImageSize - hook" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.414" tests="3"> + <testcase classname="useOverviewImageSize - hook when currentImage is not valid should return default value" name="useOverviewImageSize - hook when currentImage is not valid should return default value" time="0.002"> </testcase> - <testcase classname="user reducer should update store after successful login query" name="user reducer should update store after successful login query" time="0.003"> + <testcase classname="useOverviewImageSize - hook when containerRect is not valid should return default value" name="useOverviewImageSize - hook when containerRect is not valid should return default value" time="0"> </testcase> - <testcase classname="user reducer should update store on loading login query" name="user reducer should update store on loading login query" time="0.002"> + <testcase classname="useOverviewImageSize - hook when data is valid should return calculated height, width, sizeFactor" name="useOverviewImageSize - hook when data is valid should return calculated height, width, sizeFactor" time="0"> </testcase> - <testcase classname="user reducer should update store after successful getSessionValid query" name="user reducer should update store after successful getSessionValid query" time="0.001"> + </testsuite> + <testsuite name="TabNavigator - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.34" tests="3"> + <testcase classname="TabNavigator - component should render TabNavigator with correct tabs" name="TabNavigator - component should render TabNavigator with correct tabs" time="0.019"> + </testcase> + <testcase classname="TabNavigator - component should change tabs correctly" name="TabNavigator - component should change tabs correctly" time="0.005"> + </testcase> + <testcase classname="TabNavigator - component should set initial active tab" name="TabNavigator - component should set initial active tab" time="0.028"> </testcase> </testsuite> - <testsuite name="drugs thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.236" tests="2"> - <testcase classname="drugs thunks getDrugs should return data when data response from API is valid" name="drugs thunks getDrugs should return data when data response from API is valid" time="0.033"> + <testsuite name="models reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.319" tests="4"> + <testcase classname="models reducer should match initial state" name="models reducer should match initial state" time="0.004"> + </testcase> + <testcase classname="models reducer should update store after succesfull getModels query" name="models reducer should update store after succesfull getModels query" time="0.006"> </testcase> - <testcase classname="drugs thunks getDrugs should return undefined when data response from API is not valid " name="drugs thunks getDrugs should return undefined when data response from API is not valid " time="0.006"> + <testcase classname="models reducer should update store after failed getModels query" name="models reducer should update store after failed getModels query" time="0.097"> + </testcase> + <testcase classname="models reducer should update store on loading getModels query" name="models reducer should update store on loading getModels query" time="0.005"> </testcase> </testsuite> - <testsuite name="project reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.276" tests="4"> - <testcase classname="project reducer should match initial state" name="project reducer should match initial state" time="0.002"> + <testsuite name="TabButton - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.278" tests="4"> + <testcase classname="TabButton - component should render TabButton with custom label" name="TabButton - component should render TabButton with custom label" time="0.021"> </testcase> - <testcase classname="project reducer should update store after succesfull getProjectById query" name="project reducer should update store after succesfull getProjectById query" time="0.005"> + <testcase classname="TabButton - component should handle click event" name="TabButton - component should handle click event" time="0.006"> </testcase> - <testcase classname="project reducer should update store after failed getProjectById query" name="project reducer should update store after failed getProjectById query" time="0.089"> + <testcase classname="TabButton - component should indicate active tab correctly" name="TabButton - component should indicate active tab correctly" time="0.015"> </testcase> - <testcase classname="project reducer should update store on loading getProjectById query" name="project reducer should update store on loading getProjectById query" time="0.002"> + <testcase classname="TabButton - component should indicate not active tab correctly" name="TabButton - component should indicate not active tab correctly" time="0.004"> </testcase> </testsuite> - <testsuite name="login thunk" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.148" tests="2"> - <testcase classname="login thunk dispatches closeModal action on successful login with valid data" name="login thunk dispatches closeModal action on successful login with valid data" time="0.002"> + <testsuite name="bioEntity reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.334" tests="4"> + <testcase classname="bioEntity reducer should match initial state" name="bioEntity reducer should match initial state" time="0.002"> </testcase> - <testcase classname="login thunk does not dispatch closeModal action on failed login with invalid data" name="login thunk does not dispatch closeModal action on failed login with invalid data" time="0"> + <testcase classname="bioEntity reducer should update store after succesfull getBioEntity query" name="bioEntity reducer should update store after succesfull getBioEntity query" time="0.022"> + </testcase> + <testcase classname="bioEntity reducer should update store after failed getBioEntity query" name="bioEntity reducer should update store after failed getBioEntity query" time="0.093"> + </testcase> + <testcase classname="bioEntity reducer should update store on loading getBioEntity query" name="bioEntity reducer should update store on loading getBioEntity query" time="0.01"> </testcase> </testsuite> - <testsuite name="getHexTricolorGradientColorWithAlpha" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.258" tests="9"> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: -1 } should return #FF0000ff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: -1 } should return #FF0000ff" time="0.002"> + <testsuite name="FileUpload component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.309" tests="2"> + <testcase classname="FileUpload component renders correctly with default state" name="FileUpload component renders correctly with default state" time="0.019"> </testcase> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 0.8, position: -0.75 } should return #BF4000cc" name="getHexTricolorGradientColorWithAlpha and position { alpha: 0.8, position: -0.75 } should return #BF4000cc" time="0"> + <testcase classname="FileUpload component renders filename when file type is correct" name="FileUpload component renders filename when file type is correct" time="0.002"> </testcase> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 0.5, position: -0.5 } should return #80800080" name="getHexTricolorGradientColorWithAlpha and position { alpha: 0.5, position: -0.5 } should return #80800080" time="0"> + </testsuite> + <testsuite name="ReactionDrawer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.463" tests="3"> + <testcase classname="ReactionDrawer - component should show reference group with source=" name="ReactionDrawer - component should show reference group with source=" time="0.023"> </testcase> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 0, position: -0.25 } should return #40BF0000" name="getHexTricolorGradientColorWithAlpha and position { alpha: 0, position: -0.25 } should return #40BF0000" time="0.001"> + <testcase classname="ReactionDrawer - component should show reference group with source=source1" name="ReactionDrawer - component should show reference group with source=source1" time="0.006"> </testcase> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0 } should return #00FF00ff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0 } should return #00FF00ff" time="0"> + <testcase classname="ReactionDrawer - component should show reference group with source=source2" name="ReactionDrawer - component should show reference group with source=source2" time="0.002"> </testcase> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.25 } should return #00BF40ff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.25 } should return #00BF40ff" time="0"> + </testsuite> + <testsuite name="getCompartmentPathwaysCheckboxElements" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.153" tests="5"> + <testcase classname="getCompartmentPathwaysCheckboxElements should return an empty array when given an empty items array" name="getCompartmentPathwaysCheckboxElements should return an empty array when given an empty items array" time="0.003"> </testcase> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.5 } should return #008080ff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.5 } should return #008080ff" time="0"> + <testcase classname="getCompartmentPathwaysCheckboxElements should correctly extract unique names and corresponding ids from items" name="getCompartmentPathwaysCheckboxElements should correctly extract unique names and corresponding ids from items" time="0.001"> </testcase> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.75 } should return #0040BFff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.75 } should return #0040BFff" time="0"> + <testcase classname="getCompartmentPathwaysCheckboxElements should correctly extract unique names and corresponding ids from items and sorts them alphabetically" name="getCompartmentPathwaysCheckboxElements should correctly extract unique names and corresponding ids from items and sorts them alphabetically" time="0"> + </testcase> + <testcase classname="getModelsIds should return an empty array if models are not provided" name="getModelsIds should return an empty array if models are not provided" time="0"> </testcase> - <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 1 } should return #0000FFff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 1 } should return #0000FFff" time="0.001"> + <testcase classname="getModelsIds should return an array of model IDs" name="getModelsIds should return an array of model IDs" time="0.001"> </testcase> </testsuite> - <testsuite name="getElementsByPoint - utils" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.181" tests="3"> - <testcase classname="getElementsByPoint - utils should return data when data response from API is valid" name="getElementsByPoint - utils should return data when data response from API is valid" time="0.004"> + <testsuite name="getPolygonLatitudeCoordinates" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.149" tests="3"> + <testcase classname="getPolygonLatitudeCoordinates should return the correct latitude coordinates for width=80, nOverlays=3, xMin=2137.5, and overlayIndexBasedOnOrder=2" name="getPolygonLatitudeCoordinates should return the correct latitude coordinates for width=80, nOverlays=3, xMin=2137.5, and overlayIndexBasedOnOrder=2" time="0.001"> </testcase> - <testcase classname="getElementsByPoint - utils should return undefined when data response from API is not valid " name="getElementsByPoint - utils should return undefined when data response from API is not valid " time="0.006"> + <testcase classname="getPolygonLatitudeCoordinates should return the correct latitude coordinates for width=120, nOverlays=6, xMin=2137.5, and overlayIndexBasedOnOrder=5" name="getPolygonLatitudeCoordinates should return the correct latitude coordinates for width=120, nOverlays=6, xMin=2137.5, and overlayIndexBasedOnOrder=5" time="0"> </testcase> - <testcase classname="getElementsByPoint - utils should return empty array when data response from API is empty" name="getElementsByPoint - utils should return empty array when data response from API is empty" time="0.001"> + <testcase classname="getPolygonLatitudeCoordinates should return the correct latitude coordinates for width=40, nOverlays=1, xMin=2137.5, and overlayIndexBasedOnOrder=0" name="getPolygonLatitudeCoordinates should return the correct latitude coordinates for width=40, nOverlays=1, xMin=2137.5, and overlayIndexBasedOnOrder=0" time="0"> </testcase> </testsuite> - <testsuite name="chemicals thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.223" tests="2"> - <testcase classname="chemicals thunks getChemiclas should return data when data response from API is valid" name="chemicals thunks getChemiclas should return data when data response from API is valid" time="0.019"> + <testsuite name="map middleware" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.348" tests="3"> + <testcase classname="map middleware on listen when model is valid and different than current should dispatch setMapData, map/setMapData" name="map middleware on listen when model is valid and different than current should dispatch setMapData, map/setMapData" time="0.002"> + </testcase> + <testcase classname="map middleware on listen when model is valid and identical with current should NOT dispatch setMapData" name="map middleware on listen when model is valid and identical with current should NOT dispatch setMapData" time="0"> </testcase> - <testcase classname="chemicals thunks getChemiclas should return undefined when data response from API is not valid " name="chemicals thunks getChemiclas should return undefined when data response from API is not valid " time="0.007"> + <testcase classname="map middleware on listen when model is NOT valid should NOT dispatch setMapData" name="map middleware on listen when model is NOT valid should NOT dispatch setMapData" time="0"> </testcase> </testsuite> - <testsuite name="getUpdatedMapData - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.17" tests="3"> - <testcase classname="getUpdatedMapData - util when model does not have default values should return correct value" name="getUpdatedMapData - util when model does not have default values should return correct value" time="0.001"> + <testsuite name="UserAvatar - component " errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.287" tests="1"> + <testcase classname="UserAvatar - component should render placeholder image" name="UserAvatar - component should render placeholder image" time="0.014"> </testcase> - <testcase classname="getUpdatedMapData - util when model has default falsy values should return correct value" name="getUpdatedMapData - util when model has default falsy values should return correct value" time="0"> + </testsuite> + <testsuite name="checkIfIsActionValid - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.141" tests="3"> + <testcase classname="checkIfIsActionValid - util when action payload has model id equal to current should return false" name="checkIfIsActionValid - util when action payload has model id equal to current should return false" time="0.001"> </testcase> - <testcase classname="getUpdatedMapData - util when model has default truthy values should return correct value" name="getUpdatedMapData - util when model has default truthy values should return correct value" time="0"> + <testcase classname="checkIfIsActionValid - util when action payload has model id different than current should return true" name="checkIfIsActionValid - util when action payload has model id different than current should return true" time="0"> + </testcase> + <testcase classname="checkIfIsActionValid - util when action payload has NOT model id should return true" name="checkIfIsActionValid - util when action payload has NOT model id should return true" time="0"> + </testcase> + </testsuite> + <testsuite name="compartmentPathways reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:46" time="0.264" tests="4"> + <testcase classname="compartmentPathways reducer should match initial state" name="compartmentPathways reducer should match initial state" time="0.002"> + </testcase> + <testcase classname="compartmentPathways reducer should update store on loading getCompartmentPathways query" name="compartmentPathways reducer should update store on loading getCompartmentPathways query" time="0.002"> + </testcase> + <testcase classname="compartmentPathways reducer should update store after succesful getCompartmentPathways query" name="compartmentPathways reducer should update store after succesful getCompartmentPathways query" time="0.006"> + </testcase> + <testcase classname="compartmentPathways reducer should update store after failed getCompartmentPathways query" name="compartmentPathways reducer should update store after failed getCompartmentPathways query" time="0.073"> + </testcase> + </testsuite> + <testsuite name="roundToTwoDiggits" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.13" tests="5"> + <testcase classname="roundToTwoDiggits should round a positive number with more than two decimal places to two decimal places" name="roundToTwoDiggits should round a positive number with more than two decimal places to two decimal places" time="0.013"> + </testcase> + <testcase classname="roundToTwoDiggits should round a negative number with more than two decimal places to two decimal places" name="roundToTwoDiggits should round a negative number with more than two decimal places to two decimal places" time="0"> + </testcase> + <testcase classname="roundToTwoDiggits should round a number with exactly two decimal places to two decimal places" name="roundToTwoDiggits should round a number with exactly two decimal places to two decimal places" time="0.001"> + </testcase> + <testcase classname="roundToTwoDiggits should round a number with less than two decimal places to two decimal places" name="roundToTwoDiggits should round a number with less than two decimal places to two decimal places" time="0"> + </testcase> + <testcase classname="roundToTwoDiggits should round zero to two decimal places" name="roundToTwoDiggits should round zero to two decimal places" time="0"> </testcase> </testsuite> - <testsuite name="getCanvasIcon - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.256" tests="13"> + <testsuite name="getCanvasIcon - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.13" tests="13"> <testcase classname="getCanvasIcon - util getTextWidth - subUtil on value=1 should return 6.25" name="getCanvasIcon - util getTextWidth - subUtil on value=1 should return 6.25" time="0.001"> </testcase> <testcase classname="getCanvasIcon - util getTextWidth - subUtil on value=7 should return 8.333" name="getCanvasIcon - util getTextWidth - subUtil on value=7 should return 8.333" time="0"> @@ -694,13 +996,13 @@ </testcase> <testcase classname="getCanvasIcon - util getTextPosition - subUtil on textWidth=532 textHeight=443 should return x=-253.5 y=-164.4" name="getCanvasIcon - util getTextPosition - subUtil on textWidth=532 textHeight=443 should return x=-253.5 y=-164.4" time="0"> </testcase> - <testcase classname="getCanvasIcon - util getTextPosition - subUtil on textWidth=10 textHeight=0 should return x=7.5 y=12.8" name="getCanvasIcon - util getTextPosition - subUtil on textWidth=10 textHeight=0 should return x=7.5 y=12.8" time="0.001"> + <testcase classname="getCanvasIcon - util getTextPosition - subUtil on textWidth=10 textHeight=0 should return x=7.5 y=12.8" name="getCanvasIcon - util getTextPosition - subUtil on textWidth=10 textHeight=0 should return x=7.5 y=12.8" time="0"> </testcase> <testcase classname="getCanvasIcon - util getTextPosition - subUtil on textWidth=0 textHeight=10 should return x=12.5 y=8.8" name="getCanvasIcon - util getTextPosition - subUtil on textWidth=0 textHeight=10 should return x=12.5 y=8.8" time="0.001"> </testcase> <testcase classname="getCanvasIcon - util getTextPosition - subUtil on textWidth=0 textHeight=0 should return x=12.5 y=12.8" name="getCanvasIcon - util getTextPosition - subUtil on textWidth=0 textHeight=0 should return x=12.5 y=12.8" time="0"> </testcase> - <testcase classname="getCanvasIcon - util drawPinOnCanvas - subUtil should run set fillStyle with color" name="getCanvasIcon - util drawPinOnCanvas - subUtil should run set fillStyle with color" time="0.004"> + <testcase classname="getCanvasIcon - util drawPinOnCanvas - subUtil should run set fillStyle with color" name="getCanvasIcon - util drawPinOnCanvas - subUtil should run set fillStyle with color" time="0.001"> </testcase> <testcase classname="getCanvasIcon - util drawPinOnCanvas - subUtil should run fill method with valid arguments" name="getCanvasIcon - util drawPinOnCanvas - subUtil should run fill method with valid arguments" time="0.001"> </testcase> @@ -709,53 +1011,61 @@ <testcase classname="getCanvasIcon - util drawNumberOnCanvas - subUtil should run fillText once with valid args" name="getCanvasIcon - util drawNumberOnCanvas - subUtil should run fillText once with valid args" time="0"> </testcase> </testsuite> - <testsuite name="expandHexToFullFormatIfItsShorthanded" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.128" tests="11"> - <testcase classname="expandHexToFullFormatIfItsShorthanded should expand short-handed hex string to full format" name="expandHexToFullFormatIfItsShorthanded should expand short-handed hex string to full format" time="0.002"> + <testsuite name="chemicals thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.189" tests="2"> + <testcase classname="chemicals thunks getChemiclas should return data when data response from API is valid" name="chemicals thunks getChemiclas should return data when data response from API is valid" time="0.029"> </testcase> - <testcase classname="expandHexToFullFormatIfItsShorthanded should not modify full-format hex string" name="expandHexToFullFormatIfItsShorthanded should not modify full-format hex string" time="0"> + <testcase classname="chemicals thunks getChemiclas should return undefined when data response from API is not valid " name="chemicals thunks getChemiclas should return undefined when data response from API is not valid " time="0.005"> </testcase> - <testcase classname="expandHexToFullFormatIfItsShorthanded should handle hex string without leading #" name="expandHexToFullFormatIfItsShorthanded should handle hex string without leading #" time="0"> + </testsuite> + <testsuite name="bioEntityContents thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.272" tests="2"> + <testcase classname="bioEntityContents thunks getBioEntityContents should return data when data response from API is valid" name="bioEntityContents thunks getBioEntityContents should return data when data response from API is valid" time="0.016"> </testcase> - <testcase classname="expandHexToFullFormatIfItsShorthanded should return original string if it does not match short-hand regex" name="expandHexToFullFormatIfItsShorthanded should return original string if it does not match short-hand regex" time="0"> + <testcase classname="bioEntityContents thunks getBioEntityContents should return undefined when data response from API is not valid " name="bioEntityContents thunks getBioEntityContents should return undefined when data response from API is not valid " time="0.013"> </testcase> - <testcase classname="hexToRgb should convert valid hex string to RGB object" name="hexToRgb should convert valid hex string to RGB object" time="0"> + </testsuite> + <testsuite name="calculateOverlaysOrder" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.144" tests="5"> + <testcase classname="calculateOverlaysOrder should return valid overlays order" name="calculateOverlaysOrder should return valid overlays order" time="0.011"> </testcase> - <testcase classname="hexToRgb should return null for invalid hex string" name="hexToRgb should return null for invalid hex string" time="0.001"> + <testcase classname="calculateOverlaysOrder should return valid overlays order" name="calculateOverlaysOrder should return valid overlays order" time="0.001"> </testcase> - <testcase classname="hexToRgb should handle hex string without leading #" name="hexToRgb should handle hex string without leading #" time="0"> + <testcase classname="calculateOverlaysOrder should return valid overlays order" name="calculateOverlaysOrder should return valid overlays order" time="0"> </testcase> - <testcase classname="hexToRgb should return null for hex string with invalid characters" name="hexToRgb should return null for hex string with invalid characters" time="0"> + <testcase classname="calculateOverlaysOrder should return valid overlays order" name="calculateOverlaysOrder should return valid overlays order" time="0"> </testcase> - <testcase classname="hexToRgb should convert short-handed RGB hex string without leading # to RGB object" name="hexToRgb should convert short-handed RGB hex string without leading # to RGB object" time="0"> + <testcase classname="calculateOverlaysOrder should return valid overlays order" name="calculateOverlaysOrder should return valid overlays order" time="0"> </testcase> - <testcase classname="hexToRgb should handle short-handed RGB hex string with invalid characters" name="hexToRgb should handle short-handed RGB hex string with invalid characters" time="0"> + </testsuite> + <testsuite name="processOverlayContentChange" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.128" tests="2"> + <testcase classname="processOverlayContentChange should parse overlay file content and invoke the handleOverlayChange callback for valid lines" name="processOverlayContentChange should parse overlay file content and invoke the handleOverlayChange callback for valid lines" time="0.006"> </testcase> - <testcase classname="hexToRgb should handle short-handed RGB hex string with invalid characters and without leading #" name="hexToRgb should handle short-handed RGB hex string with invalid characters and without leading #" time="0.001"> + <testcase classname="processOverlayContentChange should handle lines with invalid format without calling handleOverlayChange" name="processOverlayContentChange should handle lines with invalid format without calling handleOverlayChange" time="0"> </testcase> </testsuite> - <testsuite name="drawer reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.187" tests="10"> - <testcase classname="drawer reducer should match initial state" name="drawer reducer should match initial state" time="0.002"> - </testcase> - <testcase classname="drawer reducer should update the store after openDrawer action" name="drawer reducer should update the store after openDrawer action" time="0.002"> + <testsuite name="reactions thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.196" tests="3"> + <testcase classname="reactions thunks getReactionsByIds should return data when data response from API is valid" name="reactions thunks getReactionsByIds should return data when data response from API is valid" time="0.017"> </testcase> - <testcase classname="drawer reducer should update the store after openSearchDrawerWithSelectedTab action" name="drawer reducer should update the store after openSearchDrawerWithSelectedTab action" time="0.001"> + <testcase classname="reactions thunks getReactionsByIds should return undefined when data response from API is not valid " name="reactions thunks getReactionsByIds should return undefined when data response from API is not valid " time="0.006"> </testcase> - <testcase classname="drawer reducer should update the store after openSubmapsDrawer action" name="drawer reducer should update the store after openSubmapsDrawer action" time="0"> + <testcase classname="reactions thunks getReactionsByIds should return empty array when data response from API is empty" name="reactions thunks getReactionsByIds should return empty array when data response from API is empty" time="0.001"> </testcase> - <testcase classname="drawer reducer should update the store after selectTab action" name="drawer reducer should update the store after selectTab action" time="0.001"> + </testsuite> + <testsuite name="degreesToRadians - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.137" tests="3"> + <testcase classname="degreesToRadians - util coverts positive degree to close positive radians" name="degreesToRadians - util coverts positive degree to close positive radians" time="0.001"> </testcase> - <testcase classname="drawer reducer should update the store after closeDrawerReducer action" name="drawer reducer should update the store after closeDrawerReducer action" time="0.001"> + <testcase classname="degreesToRadians - util coverts negative degree to close negative radians" name="degreesToRadians - util coverts negative degree to close negative radians" time="0.001"> </testcase> - <testcase classname="drawer reducer should update the store after displayDrugsList action" name="drawer reducer should update the store after displayDrugsList action" time="0.001"> + <testcase classname="degreesToRadians - util coverts zero degree to zero radians" name="degreesToRadians - util coverts zero degree to zero radians" time="0"> </testcase> - <testcase classname="drawer reducer should update the store after displayChemicalsList action" name="drawer reducer should update the store after displayChemicalsList action" time="0.001"> + </testsuite> + <testsuite name="compartmentPathways thunk" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.232" tests="3"> + <testcase classname="compartmentPathways thunk should handle query getCompartmentPathways properly when models are undefined" name="compartmentPathways thunk should handle query getCompartmentPathways properly when models are undefined" time="0.004"> </testcase> - <testcase classname="drawer reducer should update the store after displayGroupedSearchResults action" name="drawer reducer should update the store after displayGroupedSearchResults action" time="0"> + <testcase classname="compartmentPathways thunk should handle sendCompartmentPathwaysIds request properly if it is more than 100 ids" name="compartmentPathways thunk should handle sendCompartmentPathwaysIds request properly if it is more than 100 ids" time="0.009"> </testcase> - <testcase classname="drawer reducer should update the store after displayEntityDetails action" name="drawer reducer should update the store after displayEntityDetails action" time="0.002"> + <testcase classname="compartmentPathways thunk should not do a network request sendCompartmentPathwaysIds if it is less than 100 ids" name="compartmentPathways thunk should not do a network request sendCompartmentPathwaysIds if it is less than 100 ids" time="0.002"> </testcase> </testsuite> - <testsuite name="getSearchResults - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.195" tests="3"> + <testsuite name="getSearchResults - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.189" tests="3"> <testcase classname="getSearchResults - util when results type is ALIAS returns valid array of objects" name="getSearchResults - util when results type is ALIAS returns valid array of objects" time="0.003"> </testcase> <testcase classname="getSearchResults - util when results type is REACTION returns valid array of objects" name="getSearchResults - util when results type is REACTION returns valid array of objects" time="0.001"> @@ -763,256 +1073,300 @@ <testcase classname="getSearchResults - util when results type is invalid should return undefined" name="getSearchResults - util when results type is invalid should return undefined" time="0.005"> </testcase> </testsuite> - <testsuite name="models thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.178" tests="2"> - <testcase classname="models thunks getModels should return data when data response from API is valid" name="models thunks getModels should return data when data response from API is valid" time="0.008"> + <testsuite name="handleDataReset" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.267" tests="1"> + <testcase classname="handleDataReset should dispatch reset actions" name="handleDataReset should dispatch reset actions" time="0.002"> </testcase> - <testcase classname="models thunks getModels should return undefined when data response from API is not valid " name="models thunks getModels should return undefined when data response from API is not valid " time="0.009"> + </testsuite> + <testsuite name="drugs thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.253" tests="2"> + <testcase classname="drugs thunks getDrugs should return data when data response from API is valid" name="drugs thunks getDrugs should return data when data response from API is valid" time="0.025"> + </testcase> + <testcase classname="drugs thunks getDrugs should return undefined when data response from API is not valid " name="drugs thunks getDrugs should return undefined when data response from API is not valid " time="0.005"> </testcase> </testsuite> - <testsuite name="getColorByAvailableProperties" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.169" tests="4"> - <testcase classname="getColorByAvailableProperties should return the result of getHexTricolorGradientColorWithAlpha if entity has a value equal to 0" name="getColorByAvailableProperties should return the result of getHexTricolorGradientColorWithAlpha if entity has a value equal to 0" time="0.005"> + <testsuite name="backgrounds reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.303" tests="4"> + <testcase classname="backgrounds reducer should match initial state" name="backgrounds reducer should match initial state" time="0.002"> </testcase> - <testcase classname="getColorByAvailableProperties should return the result of getHexTricolorGradientColorWithAlpha if entity has a value" name="getColorByAvailableProperties should return the result of getHexTricolorGradientColorWithAlpha if entity has a value" time="0"> + <testcase classname="backgrounds reducer should update store after succesfull getAllBackgroundsByProjectId query" name="backgrounds reducer should update store after succesfull getAllBackgroundsByProjectId query" time="0.005"> </testcase> - <testcase classname="getColorByAvailableProperties should return the result of convertDecimalToHex if entity has a color" name="getColorByAvailableProperties should return the result of convertDecimalToHex if entity has a color" time="0"> + <testcase classname="backgrounds reducer should update store after failed getAllBackgroundsByProjectId query" name="backgrounds reducer should update store after failed getAllBackgroundsByProjectId query" time="0.09"> </testcase> - <testcase classname="getColorByAvailableProperties should return the default color if entity has neither a value nor a color" name="getColorByAvailableProperties should return the default color if entity has neither a value nor a color" time="0"> + <testcase classname="backgrounds reducer should update store on loading getAllBackgroundsByProjectId query" name="backgrounds reducer should update store on loading getAllBackgroundsByProjectId query" time="0.003"> </testcase> </testsuite> - <testsuite name="interpolateColor" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.156" tests="5"> - <testcase classname="interpolateColor should return color1 for position 0" name="interpolateColor should return color1 for position 0" time="0.003"> - </testcase> - <testcase classname="interpolateColor should return color2 for position 1" name="interpolateColor should return color2 for position 1" time="0"> + <testsuite name="models thunks" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.212" tests="2"> + <testcase classname="models thunks getModels should return data when data response from API is valid" name="models thunks getModels should return data when data response from API is valid" time="0.011"> </testcase> - <testcase classname="interpolateColor should interpolate colors for position 0.25" name="interpolateColor should interpolate colors for position 0.25" time="0.001"> + <testcase classname="models thunks getModels should return undefined when data response from API is not valid " name="models thunks getModels should return undefined when data response from API is not valid " time="0.008"> </testcase> - <testcase classname="interpolateColor should interpolate colors for position 0.5" name="interpolateColor should interpolate colors for position 0.5" time="0"> + </testsuite> + <testsuite name="createOverlayGeometryFeature" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.212" tests="2"> + <testcase classname="createOverlayGeometryFeature should create a feature with the correct geometry and style" name="createOverlayGeometryFeature should create a feature with the correct geometry and style" time="0.003"> </testcase> - <testcase classname="interpolateColor should interpolate colors for position 0.75" name="interpolateColor should interpolate colors for position 0.75" time="0"> + <testcase classname="createOverlayGeometryFeature should create a feature with the correct geometry and style when using a different color" name="createOverlayGeometryFeature should create a feature with the correct geometry and style when using a different color" time="0.001"> </testcase> </testsuite> - <testsuite name="getUpdatedModel - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.15" tests="3"> - <testcase classname="getUpdatedModel - util when payload has valid modelId returns model object" name="getUpdatedModel - util when payload has valid modelId returns model object" time="0.002"> + <testsuite name="project reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.311" tests="4"> + <testcase classname="project reducer should match initial state" name="project reducer should match initial state" time="0.004"> </testcase> - <testcase classname="getUpdatedModel - util when payload has invalid modelId returns undefined" name="getUpdatedModel - util when payload has invalid modelId returns undefined" time="0"> + <testcase classname="project reducer should update store after succesfull getProjectById query" name="project reducer should update store after succesfull getProjectById query" time="0.006"> </testcase> - <testcase classname="getUpdatedModel - util when payload does not have modelId returns undefined" name="getUpdatedModel - util when payload does not have modelId returns undefined" time="0"> + <testcase classname="project reducer should update store after failed getProjectById query" name="project reducer should update store after failed getProjectById query" time="0.1"> + </testcase> + <testcase classname="project reducer should update store on loading getProjectById query" name="project reducer should update store on loading getProjectById query" time="0.006"> </testcase> </testsuite> - <testsuite name="rgbToHex - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.16" tests="2"> - <testcase classname="rgbToHex - util should convert RGB values to hex format" name="rgbToHex - util should convert RGB values to hex format" time="0.001"> + <testsuite name="drawer reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.236" tests="10"> + <testcase classname="drawer reducer should match initial state" name="drawer reducer should match initial state" time="0.008"> </testcase> - <testcase classname="rgbToHex - util should handle invalid input values" name="rgbToHex - util should handle invalid input values" time="0.005"> + <testcase classname="drawer reducer should update the store after openDrawer action" name="drawer reducer should update the store after openDrawer action" time="0.002"> </testcase> - </testsuite> - <testsuite name="getFilteredReferences - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.171" tests="3"> - <testcase classname="getFilteredReferences - subUtil should return valid filtered references" name="getFilteredReferences - subUtil should return valid filtered references" time="0.001"> + <testcase classname="drawer reducer should update the store after openSearchDrawerWithSelectedTab action" name="drawer reducer should update the store after openSearchDrawerWithSelectedTab action" time="0.001"> </testcase> - <testcase classname="getFilteredReferences - subUtil should return valid filtered references" name="getFilteredReferences - subUtil should return valid filtered references" time="0"> + <testcase classname="drawer reducer should update the store after openSubmapsDrawer action" name="drawer reducer should update the store after openSubmapsDrawer action" time="0.001"> </testcase> - <testcase classname="getFilteredReferences - subUtil should return valid filtered references" name="getFilteredReferences - subUtil should return valid filtered references" time="0.001"> + <testcase classname="drawer reducer should update the store after selectTab action" name="drawer reducer should update the store after selectTab action" time="0"> </testcase> - </testsuite> - <testsuite name="getFinalImageSize - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.138" tests="4"> - <testcase classname="getFinalImageSize - util should return valid size and size factor" name="getFinalImageSize - util should return valid size and size factor" time="0.001"> + <testcase classname="drawer reducer should update the store after closeDrawerReducer action" name="drawer reducer should update the store after closeDrawerReducer action" time="0.001"> </testcase> - <testcase classname="getFinalImageSize - util should return valid size and size factor" name="getFinalImageSize - util should return valid size and size factor" time="0.001"> + <testcase classname="drawer reducer should update the store after displayDrugsList action" name="drawer reducer should update the store after displayDrugsList action" time="0"> </testcase> - <testcase classname="getFinalImageSize - util should return valid size and size factor" name="getFinalImageSize - util should return valid size and size factor" time="0"> + <testcase classname="drawer reducer should update the store after displayChemicalsList action" name="drawer reducer should update the store after displayChemicalsList action" time="0.001"> </testcase> - <testcase classname="getFinalImageSize - util should return valid size and size factor" name="getFinalImageSize - util should return valid size and size factor" time="0"> + <testcase classname="drawer reducer should update the store after displayGroupedSearchResults action" name="drawer reducer should update the store after displayGroupedSearchResults action" time="0.001"> + </testcase> + <testcase classname="drawer reducer should update the store after displayEntityDetails action" name="drawer reducer should update the store after displayEntityDetails action" time="0.002"> </testcase> </testsuite> - <testsuite name="validateDataUsingZodSchema - utils" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.163" tests="2"> - <testcase classname="validateDataUsingZodSchema - utils should return true for given cases" name="validateDataUsingZodSchema - utils should return true for given cases" time="0.002"> + <testsuite name="getPointOffset - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.158" tests="3"> + <testcase classname="getPointOffset - util when all args are valid should return valid point origin and shifted values" name="getPointOffset - util when all args are valid should return valid point origin and shifted values" time="0.002"> </testcase> - <testcase classname="validateDataUsingZodSchema - utils should return false for given cases" name="validateDataUsingZodSchema - utils should return false for given cases" time="0.005"> + <testcase classname="getPointOffset - util when all args are valid should not throw error" name="getPointOffset - util when all args are valid should not throw error" time="0"> + </testcase> + <testcase classname="getPointOffset - util when mapSize arg is invalid should throw error" name="getPointOffset - util when mapSize arg is invalid should throw error" time="0.008"> </testcase> </testsuite> - <testsuite name="handleSearchResultAction - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.125" tests="2"> - <testcase classname="handleSearchResultAction - util on ALIAS search results should fire handleAliasResults" name="handleSearchResultAction - util on ALIAS search results should fire handleAliasResults" time="0.001"> + <testsuite name="convertDecimalToHexColor - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.127" tests="2"> + <testcase classname="convertDecimalToHexColor - util should convert small decimal" name="convertDecimalToHexColor - util should convert small decimal" time="0.001"> </testcase> - <testcase classname="handleSearchResultAction - util on REACTION search results should fire handleReactionResults" name="handleSearchResultAction - util on REACTION search results should fire handleReactionResults" time="0"> + <testcase classname="convertDecimalToHexColor - util should convert negative decimal" name="convertDecimalToHexColor - util should convert negative decimal" time="0"> </testcase> </testsuite> - <testsuite name="cookieBanner reducers" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.138" tests="4"> - <testcase classname="cookieBanner reducers should match initial state" name="cookieBanner reducers should match initial state" time="0.003"> + <testsuite name="getCanvas" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.108" tests="1"> + <testcase classname="getCanvas should return HTMLCanvasElement with valid size on positive params" name="getCanvas should return HTMLCanvasElement with valid size on positive params" time="0.002"> </testcase> - <testcase classname="cookieBanner reducers should handle showBanner action" name="cookieBanner reducers should handle showBanner action" time="0.001"> + </testsuite> + <testsuite name="map thunks - utils" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.275" tests="10"> + <testcase classname="map thunks - utils getBackgroundId should return backgroundId value from queryData" name="map thunks - utils getBackgroundId should return backgroundId value from queryData" time="0.001"> </testcase> - <testcase classname="cookieBanner reducers should handle hideBanner action" name="cookieBanner reducers should handle hideBanner action" time="0"> + <testcase classname="map thunks - utils getBackgroundId should return main map background id if query param does not include background id" name="map thunks - utils getBackgroundId should return main map background id if query param does not include background id" time="0"> </testcase> - <testcase classname="cookieBanner reducers should handle acceptCookies action" name="cookieBanner reducers should handle acceptCookies action" time="0"> + <testcase classname="map thunks - utils getBackgroundId should return default value (0) if query data does not include backgroundId and could not find main background in the store" name="map thunks - utils getBackgroundId should return default value (0) if query data does not include backgroundId and could not find main background in the store" time="0"> </testcase> - </testsuite> - <testsuite name="getMapTileUrl - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.14" tests="2"> - <testcase classname="getMapTileUrl - util when projectDirectory is empty should return empty value" name="getMapTileUrl - util when projectDirectory is empty should return empty value" time="0"> + <testcase classname="map thunks - utils getInitMapPosition should return valid map position from query params " name="map thunks - utils getInitMapPosition should return valid map position from query params " time="0"> </testcase> - <testcase classname="getMapTileUrl - util when all args are valid should return correct value" name="getMapTileUrl - util when all args are valid should return correct value" time="0"> + <testcase classname="map thunks - utils getInitMapPosition should return valid map position if query params do not include position" name="map thunks - utils getInitMapPosition should return valid map position if query params do not include position" time="0"> </testcase> - </testsuite> - <testsuite name="getGroupedReferences - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.123" tests="3"> - <testcase classname="getGroupedReferences - util should return correct grouped references" name="getGroupedReferences - util should return correct grouped references" time="0.001"> + <testcase classname="map thunks - utils getInitMapPosition should return default map position" name="map thunks - utils getInitMapPosition should return default map position" time="0.001"> </testcase> - <testcase classname="getGroupedReferences - util should return correct grouped references" name="getGroupedReferences - util should return correct grouped references" time="0"> + <testcase classname="map thunks - utils getInitMapSizeAndModelId should return correct mapsize and modelid when modelId is provided in queryData" name="map thunks - utils getInitMapSizeAndModelId should return correct mapsize and modelid when modelId is provided in queryData" time="0"> </testcase> - <testcase classname="getGroupedReferences - util should return correct grouped references" name="getGroupedReferences - util should return correct grouped references" time="0"> + <testcase classname="map thunks - utils getInitMapSizeAndModelId should return correct mapsize and modelId if query params do not include modelId" name="map thunks - utils getInitMapSizeAndModelId should return correct mapsize and modelId if query params do not include modelId" time="0"> + </testcase> + <testcase classname="map thunks - utils getOpenedMaps should return main map only" name="map thunks - utils getOpenedMaps should return main map only" time="0"> + </testcase> + <testcase classname="map thunks - utils getOpenedMaps should return main map and opened submap" name="map thunks - utils getOpenedMaps should return main map and opened submap" time="0.001"> </testcase> </testsuite> - <testsuite name="checkIfIsActionValid - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.117" tests="3"> - <testcase classname="checkIfIsActionValid - util when action payload has model id equal to current should return false" name="checkIfIsActionValid - util when action payload has model id equal to current should return false" time="0.001"> + <testsuite name="interpolateThreeColors - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.123" tests="9"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -1 should return { r: 255, g: 0, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -1 should return { r: 255, g: 0, b: 0 }" time="0.001"> </testcase> - <testcase classname="checkIfIsActionValid - util when action payload has model id different than current should return true" name="checkIfIsActionValid - util when action payload has model id different than current should return true" time="0"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.75 should return { r: 191, g: 64, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.75 should return { r: 191, g: 64, b: 0 }" time="0"> </testcase> - <testcase classname="checkIfIsActionValid - util when action payload has NOT model id should return true" name="checkIfIsActionValid - util when action payload has NOT model id should return true" time="0"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.5 should return { r: 128, g: 128, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.5 should return { r: 128, g: 128, b: 0 }" time="0"> </testcase> - </testsuite> - <testsuite name="getSearchValuesArray - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.126" tests="6"> - <testcase classname="getSearchValuesArray - util should return array of values when string has ; separator" name="getSearchValuesArray - util should return array of values when string has ; separator" time="0.001"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.25 should return { r: 64, g: 191, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.25 should return { r: 64, g: 191, b: 0 }" time="0"> </testcase> - <testcase classname="getSearchValuesArray - util should trim values to seven if more values are provided" name="getSearchValuesArray - util should trim values to seven if more values are provided" time="0"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0 should return { r: 0, g: 255, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0 should return { r: 0, g: 255, b: 0 }" time="0"> </testcase> - <testcase classname="getSearchValuesArray - util should return single value in array if no ; was passed in string" name="getSearchValuesArray - util should return single value in array if no ; was passed in string" time="0.001"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.25 should return { r: 0, g: 191, b: 64 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.25 should return { r: 0, g: 191, b: 64 }" time="0"> </testcase> - <testcase classname="getDefaultSearchTab for [ 'nadh', 'o2', 'mp3' ] should return nadh" name="getDefaultSearchTab for [ 'nadh', 'o2', 'mp3' ] should return nadh" time="0"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.5 should return { r: 0, g: 128, b: 128 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.5 should return { r: 0, g: 128, b: 128 }" time="0"> </testcase> - <testcase classname="getDefaultSearchTab for [ 'o2' ] should return o2" name="getDefaultSearchTab for [ 'o2' ] should return o2" time="0"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.75 should return { r: 0, g: 64, b: 191 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.75 should return { r: 0, g: 64, b: 191 }" time="0"> </testcase> - <testcase classname="getDefaultSearchTab for [ '' ] should return " name="getDefaultSearchTab for [ '' ] should return " time="0"> + <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 1 should return { r: 0, g: 0, b: 255 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 1 should return { r: 0, g: 0, b: 255 }" time="0"> </testcase> </testsuite> - <testsuite name="boundNumber - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.116" tests="3"> - <testcase classname="boundNumber - util should return valid bounded number | v = 1, minMax = (0, 2), final = 1" name="boundNumber - util should return valid bounded number | v = 1, minMax = (0, 2), final = 1" time="0.001"> + <testsuite name="radiansToDegrees - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.103" tests="3"> + <testcase classname="radiansToDegrees - util coverts positive radian to close positive degrees" name="radiansToDegrees - util coverts positive radian to close positive degrees" time="0.001"> </testcase> - <testcase classname="boundNumber - util should return valid bounded number | v = 1, minMax = (2, 2), final = 2" name="boundNumber - util should return valid bounded number | v = 1, minMax = (2, 2), final = 2" time="0"> + <testcase classname="radiansToDegrees - util coverts negative radian to close negative degrees" name="radiansToDegrees - util coverts negative radian to close negative degrees" time="0"> </testcase> - <testcase classname="boundNumber - util should return valid bounded number | v = 2, minMax = (0, 1), final = 1" name="boundNumber - util should return valid bounded number | v = 2, minMax = (0, 1), final = 1" time="0"> + <testcase classname="radiansToDegrees - util coverts zero radian to zero degrees" name="radiansToDegrees - util coverts zero radian to zero degrees" time="0"> </testcase> </testsuite> - <testsuite name="getCanvas" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.111" tests="1"> - <testcase classname="getCanvas should return HTMLCanvasElement with valid size on positive params" name="getCanvas should return HTMLCanvasElement with valid size on positive params" time="0.003"> + <testsuite name="parseQueryToTypes" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.124" tests="1"> + <testcase classname="parseQueryToTypes should return valid data" name="parseQueryToTypes should return valid data" time="0.002"> </testcase> </testsuite> - <testsuite name="getTruthyObjectOrUndefined - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.124" tests="4"> - <testcase classname="getTruthyObjectOrUndefined - util shoud return a truthy object if the object is truthy" name="getTruthyObjectOrUndefined - util shoud return a truthy object if the object is truthy" time="0.001"> + <testsuite name="cookieBanner reducers" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.109" tests="4"> + <testcase classname="cookieBanner reducers should match initial state" name="cookieBanner reducers should match initial state" time="0.003"> </testcase> - <testcase classname="getTruthyObjectOrUndefined - util shoud return a truthy object if the object is empty" name="getTruthyObjectOrUndefined - util shoud return a truthy object if the object is empty" time="0"> + <testcase classname="cookieBanner reducers should handle showBanner action" name="cookieBanner reducers should handle showBanner action" time="0"> </testcase> - <testcase classname="getTruthyObjectOrUndefined - util shoud return undefined if the object is partially truthy" name="getTruthyObjectOrUndefined - util shoud return undefined if the object is partially truthy" time="0"> + <testcase classname="cookieBanner reducers should handle hideBanner action" name="cookieBanner reducers should handle hideBanner action" time="0"> </testcase> - <testcase classname="getTruthyObjectOrUndefined - util shoud return undefined if the objects's nested objects is partially truthy" name="getTruthyObjectOrUndefined - util shoud return undefined if the objects's nested objects is partially truthy" time="0"> + <testcase classname="cookieBanner reducers should handle acceptCookies action" name="cookieBanner reducers should handle acceptCookies action" time="0.001"> </testcase> </testsuite> - <testsuite name="pointToLatLng - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.149" tests="3"> - <testcase classname="pointToLatLng - util when mapSize arg is undefined should return fallback value" name="pointToLatLng - util when mapSize arg is undefined should return fallback value" time="0.018"> + <testsuite name="groupBy - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.099" tests="2"> + <testcase classname="groupBy - util should return valid data basing on predicate" name="groupBy - util should return valid data basing on predicate" time="0.002"> </testcase> - <testcase classname="pointToLatLng - util when mapSize arg is invalid should return fallback value" name="pointToLatLng - util when mapSize arg is invalid should return fallback value" time="0.001"> + <testcase classname="groupBy - util should return valid data basing on predicate" name="groupBy - util should return valid data basing on predicate" time="0"> </testcase> - <testcase classname="pointToLatLng - util when all args are valid should return valid lat lng value" name="pointToLatLng - util when all args are valid should return valid lat lng value" time="0"> + </testsuite> + <testsuite name="getElementsByPoint - utils" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.16" tests="3"> + <testcase classname="getElementsByPoint - utils should return data when data response from API is valid" name="getElementsByPoint - utils should return data when data response from API is valid" time="0.003"> + </testcase> + <testcase classname="getElementsByPoint - utils should return undefined when data response from API is not valid " name="getElementsByPoint - utils should return undefined when data response from API is not valid " time="0.004"> + </testcase> + <testcase classname="getElementsByPoint - utils should return empty array when data response from API is empty" name="getElementsByPoint - utils should return empty array when data response from API is empty" time="0.014"> </testcase> </testsuite> - <testsuite name="getPointOffset - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.125" tests="3"> - <testcase classname="getPointOffset - util when all args are valid should return valid point origin and shifted values" name="getPointOffset - util when all args are valid should return valid point origin and shifted values" time="0.002"> + <testsuite name="validateDataUsingZodSchema - utils" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.129" tests="2"> + <testcase classname="validateDataUsingZodSchema - utils should return true for given cases" name="validateDataUsingZodSchema - utils should return true for given cases" time="0.002"> </testcase> - <testcase classname="getPointOffset - util when all args are valid should not throw error" name="getPointOffset - util when all args are valid should not throw error" time="0"> + <testcase classname="validateDataUsingZodSchema - utils should return false for given cases" name="validateDataUsingZodSchema - utils should return false for given cases" time="0.009"> </testcase> - <testcase classname="getPointOffset - util when mapSize arg is invalid should throw error" name="getPointOffset - util when mapSize arg is invalid should throw error" time="0.005"> + </testsuite> + <testsuite name="getFinalImageSize - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.128" tests="4"> + <testcase classname="getFinalImageSize - util should return valid size and size factor" name="getFinalImageSize - util should return valid size and size factor" time="0.001"> + </testcase> + <testcase classname="getFinalImageSize - util should return valid size and size factor" name="getFinalImageSize - util should return valid size and size factor" time="0.001"> + </testcase> + <testcase classname="getFinalImageSize - util should return valid size and size factor" name="getFinalImageSize - util should return valid size and size factor" time="0"> + </testcase> + <testcase classname="getFinalImageSize - util should return valid size and size factor" name="getFinalImageSize - util should return valid size and size factor" time="0"> </testcase> </testsuite> - <testsuite name="addAlphaToHexString" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.125" tests="5"> - <testcase classname="addAlphaToHexString for [ '#ff0000', undefined ] should return #ff0000ff" name="addAlphaToHexString for [ '#ff0000', undefined ] should return #ff0000ff" time="0.002"> + <testsuite name="getHexTricolorGradientColorWithAlpha" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.145" tests="9"> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: -1 } should return #FF0000ff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: -1 } should return #FF0000ff" time="0.003"> </testcase> - <testcase classname="addAlphaToHexString for [ '#ff0000', 1 ] should return #ff0000ff" name="addAlphaToHexString for [ '#ff0000', 1 ] should return #ff0000ff" time="0"> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 0.8, position: -0.75 } should return #BF4000cc" name="getHexTricolorGradientColorWithAlpha and position { alpha: 0.8, position: -0.75 } should return #BF4000cc" time="0"> </testcase> - <testcase classname="addAlphaToHexString for [ '#ff0000', 0.8 ] should return #ff0000cc" name="addAlphaToHexString for [ '#ff0000', 0.8 ] should return #ff0000cc" time="0"> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 0.5, position: -0.5 } should return #80800080" name="getHexTricolorGradientColorWithAlpha and position { alpha: 0.5, position: -0.5 } should return #80800080" time="0"> + </testcase> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 0, position: -0.25 } should return #40BF0000" name="getHexTricolorGradientColorWithAlpha and position { alpha: 0, position: -0.25 } should return #40BF0000" time="0"> + </testcase> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0 } should return #00FF00ff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0 } should return #00FF00ff" time="0"> + </testcase> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.25 } should return #00BF40ff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.25 } should return #00BF40ff" time="0"> </testcase> - <testcase classname="addAlphaToHexString for [ '#ff0000', 0.5 ] should return #ff000080" name="addAlphaToHexString for [ '#ff0000', 0.5 ] should return #ff000080" time="0.001"> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.5 } should return #008080ff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.5 } should return #008080ff" time="0.001"> </testcase> - <testcase classname="addAlphaToHexString for [ '#ff0000', 0 ] should return #ff000000" name="addAlphaToHexString for [ '#ff0000', 0 ] should return #ff000000" time="0"> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.75 } should return #0040BFff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 0.75 } should return #0040BFff" time="0"> + </testcase> + <testcase classname="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 1 } should return #0000FFff" name="getHexTricolorGradientColorWithAlpha and position { alpha: 1, position: 1 } should return #0000FFff" time="0"> </testcase> </testsuite> - <testsuite name="interpolateThreeColors - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.161" tests="9"> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -1 should return { r: 255, g: 0, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -1 should return { r: 255, g: 0, b: 0 }" time="0.002"> + <testsuite name="login thunk" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.169" tests="2"> + <testcase classname="login thunk dispatches closeModal action on successful login with valid data" name="login thunk dispatches closeModal action on successful login with valid data" time="0.002"> </testcase> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.75 should return { r: 191, g: 64, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.75 should return { r: 191, g: 64, b: 0 }" time="0"> + <testcase classname="login thunk does not dispatch closeModal action on failed login with invalid data" name="login thunk does not dispatch closeModal action on failed login with invalid data" time="0.003"> </testcase> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.5 should return { r: 128, g: 128, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.5 should return { r: 128, g: 128, b: 0 }" time="0.001"> + </testsuite> + <testsuite name="getColorByAvailableProperties" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.156" tests="4"> + <testcase classname="getColorByAvailableProperties should return the result of getHexTricolorGradientColorWithAlpha if entity has a value equal to 0" name="getColorByAvailableProperties should return the result of getHexTricolorGradientColorWithAlpha if entity has a value equal to 0" time="0.002"> </testcase> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.25 should return { r: 64, g: 191, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position -0.25 should return { r: 64, g: 191, b: 0 }" time="0"> + <testcase classname="getColorByAvailableProperties should return the result of getHexTricolorGradientColorWithAlpha if entity has a value" name="getColorByAvailableProperties should return the result of getHexTricolorGradientColorWithAlpha if entity has a value" time="0"> </testcase> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0 should return { r: 0, g: 255, b: 0 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0 should return { r: 0, g: 255, b: 0 }" time="0"> + <testcase classname="getColorByAvailableProperties should return the result of convertDecimalToHex if entity has a color" name="getColorByAvailableProperties should return the result of convertDecimalToHex if entity has a color" time="0"> </testcase> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.25 should return { r: 0, g: 191, b: 64 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.25 should return { r: 0, g: 191, b: 64 }" time="0"> + <testcase classname="getColorByAvailableProperties should return the default color if entity has neither a value nor a color" name="getColorByAvailableProperties should return the default color if entity has neither a value nor a color" time="0.001"> </testcase> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.5 should return { r: 0, g: 128, b: 128 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.5 should return { r: 0, g: 128, b: 128 }" time="0.001"> + </testsuite> + <testsuite name="pointToLatLng - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.183" tests="3"> + <testcase classname="pointToLatLng - util when mapSize arg is undefined should return fallback value" name="pointToLatLng - util when mapSize arg is undefined should return fallback value" time="0.011"> </testcase> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.75 should return { r: 0, g: 64, b: 191 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 0.75 should return { r: 0, g: 64, b: 191 }" time="0"> + <testcase classname="pointToLatLng - util when mapSize arg is invalid should return fallback value" name="pointToLatLng - util when mapSize arg is invalid should return fallback value" time="0.001"> </testcase> - <testcase classname="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 1 should return { r: 0, g: 0, b: 255 }" name="interpolateThreeColors - util for linear gradient with range [-1,0,1]: left color (-1) {"r":255,"g":0,"b":0}, middle color (0) {"r":0,"g":255,"b":0} and right Color (1) {"r":0,"g":0,"b":255} and position 1 should return { r: 0, g: 0, b: 255 }" time="0"> + <testcase classname="pointToLatLng - util when all args are valid should return valid lat lng value" name="pointToLatLng - util when all args are valid should return valid lat lng value" time="0"> </testcase> </testsuite> - <testsuite name="getOverviewImageLinkSize - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:23" time="0.132" tests="5"> - <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0.001"> + <testsuite name="Overlay Bio Entity Reducers" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.216" tests="1"> + <testcase classname="Overlay Bio Entity Reducers getOverlayBioEntityReducer should update the state correctly when getOverlayBioEntity action is dispatched" name="Overlay Bio Entity Reducers getOverlayBioEntityReducer should update the state correctly when getOverlayBioEntity action is dispatched" time="0.007"> </testcase> - <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0"> + </testsuite> + <testsuite name="latLngToPoint - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.152" tests="4"> + <testcase classname="latLngToPoint - util on map with default tileSize = 256 should return valid point" name="latLngToPoint - util on map with default tileSize = 256 should return valid point" time="0.002"> </testcase> - <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0.001"> + <testcase classname="latLngToPoint - util on map with default tileSize = 256 should return valid point" name="latLngToPoint - util on map with default tileSize = 256 should return valid point" time="0"> </testcase> - <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0"> + <testcase classname="latLngToPoint - util on map with non-default tileSize = 128 should return valid point" name="latLngToPoint - util on map with non-default tileSize = 128 should return valid point" time="0.001"> </testcase> - <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0"> + <testcase classname="latLngToPoint - util on map with non-default tileSize = 128 should return valid point" name="latLngToPoint - util on map with non-default tileSize = 128 should return valid point" time="0"> </testcase> </testsuite> - <testsuite name="getPointMerged" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.131" tests="3"> - <testcase classname="getPointMerged should return valid merged point" name="getPointMerged should return valid merged point" time="0.002"> + <testsuite name="getFilteredReferences - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.148" tests="3"> + <testcase classname="getFilteredReferences - subUtil should return valid filtered references" name="getFilteredReferences - subUtil should return valid filtered references" time="0.001"> </testcase> - <testcase classname="getPointMerged should return valid merged point" name="getPointMerged should return valid merged point" time="0.001"> + <testcase classname="getFilteredReferences - subUtil should return valid filtered references" name="getFilteredReferences - subUtil should return valid filtered references" time="0.001"> </testcase> - <testcase classname="getPointMerged should return valid merged point" name="getPointMerged should return valid merged point" time="0"> + <testcase classname="getFilteredReferences - subUtil should return valid filtered references" name="getFilteredReferences - subUtil should return valid filtered references" time="0"> </testcase> </testsuite> - <testsuite name="convertDecimalToHexColor - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.159" tests="2"> - <testcase classname="convertDecimalToHexColor - util should convert small decimal" name="convertDecimalToHexColor - util should convert small decimal" time="0.001"> + <testsuite name="handleSearchResultForRightClickAction - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.154" tests="2"> + <testcase classname="handleSearchResultForRightClickAction - util on ALIAS search results should fire handleBioEntityResults" name="handleSearchResultForRightClickAction - util on ALIAS search results should fire handleBioEntityResults" time="0.001"> </testcase> - <testcase classname="convertDecimalToHexColor - util should convert negative decimal" name="convertDecimalToHexColor - util should convert negative decimal" time="0.001"> + <testcase classname="handleSearchResultForRightClickAction - util on REACTION search results should fire handleReactionResults" name="handleSearchResultForRightClickAction - util on REACTION search results should fire handleReactionResults" time="0"> </testcase> </testsuite> - <testsuite name="parseQueryToTypes" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.16" tests="1"> - <testcase classname="parseQueryToTypes should return valid data" name="parseQueryToTypes should return valid data" time="0.002"> + <testsuite name="getUpdatedMapData - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.149" tests="3"> + <testcase classname="getUpdatedMapData - util when model does not have default values should return correct value" name="getUpdatedMapData - util when model does not have default values should return correct value" time="0.002"> + </testcase> + <testcase classname="getUpdatedMapData - util when model has default falsy values should return correct value" name="getUpdatedMapData - util when model has default falsy values should return correct value" time="0.001"> + </testcase> + <testcase classname="getUpdatedMapData - util when model has default truthy values should return correct value" name="getUpdatedMapData - util when model has default truthy values should return correct value" time="0"> </testcase> </testsuite> - <testsuite name="api path" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.138" tests="3"> - <testcase classname="api path should return url string for drugs" name="api path should return url string for drugs" time="0.001"> + <testsuite name="getCheckboxElements" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.133" tests="4"> + <testcase classname="getCheckboxElements should return an empty array when elementTypes is undefined" name="getCheckboxElements should return an empty array when elementTypes is undefined" time="0.001"> </testcase> - <testcase classname="api path should return url string for bio entity content" name="api path should return url string for bio entity content" time="0"> + <testcase classname="getCheckboxElements should map elementTypes to MappedElementTypes and exclude duplicates based on name and parentClass" name="getCheckboxElements should map elementTypes to MappedElementTypes and exclude duplicates based on name and parentClass" time="0.001"> </testcase> - <testcase classname="api path should return url string for bio entity content" name="api path should return url string for bio entity content" time="0"> + <testcase classname="getCheckboxElements should handle an empty array of elementTypes" name="getCheckboxElements should handle an empty array of elementTypes" time="0"> + </testcase> + <testcase classname="getCheckboxElements should return an empty array when elementTypes is undefined" name="getCheckboxElements should return an empty array when elementTypes is undefined" time="0"> </testcase> </testsuite> - <testsuite name="latLngToPoint - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.152" tests="4"> - <testcase classname="latLngToPoint - util on map with default tileSize = 256 should return valid point" name="latLngToPoint - util on map with default tileSize = 256 should return valid point" time="0.001"> + <testsuite name="getOverviewImageLinkSize - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.115" tests="5"> + <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0.001"> </testcase> - <testcase classname="latLngToPoint - util on map with default tileSize = 256 should return valid point" name="latLngToPoint - util on map with default tileSize = 256 should return valid point" time="0"> + <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0"> </testcase> - <testcase classname="latLngToPoint - util on map with non-default tileSize = 128 should return valid point" name="latLngToPoint - util on map with non-default tileSize = 128 should return valid point" time="0"> + <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0"> </testcase> - <testcase classname="latLngToPoint - util on map with non-default tileSize = 128 should return valid point" name="latLngToPoint - util on map with non-default tileSize = 128 should return valid point" time="0.001"> + <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0"> + </testcase> + <testcase classname="getOverviewImageLinkSize - util should return valid link config size" name="getOverviewImageLinkSize - util should return valid link config size" time="0"> </testcase> </testsuite> - <testsuite name="handleSearchResultForRightClickAction - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.118" tests="2"> - <testcase classname="handleSearchResultForRightClickAction - util on ALIAS search results should fire handleBioEntityResults" name="handleSearchResultForRightClickAction - util on ALIAS search results should fire handleBioEntityResults" time="0.002"> + <testsuite name="handleSearchResultAction - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.13" tests="2"> + <testcase classname="handleSearchResultAction - util on ALIAS search results should fire handleAliasResults" name="handleSearchResultAction - util on ALIAS search results should fire handleAliasResults" time="0.002"> </testcase> - <testcase classname="handleSearchResultForRightClickAction - util on REACTION search results should fire handleReactionResults" name="handleSearchResultForRightClickAction - util on REACTION search results should fire handleReactionResults" time="0"> + <testcase classname="handleSearchResultAction - util on REACTION search results should fire handleReactionResults" name="handleSearchResultAction - util on REACTION search results should fire handleReactionResults" time="0"> </testcase> </testsuite> - <testsuite name="groupBy - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.132" tests="2"> - <testcase classname="groupBy - util should return valid data basing on predicate" name="groupBy - util should return valid data basing on predicate" time="0.002"> + <testsuite name="getUpdatedModel - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.175" tests="3"> + <testcase classname="getUpdatedModel - util when payload has valid modelId returns model object" name="getUpdatedModel - util when payload has valid modelId returns model object" time="0.003"> </testcase> - <testcase classname="groupBy - util should return valid data basing on predicate" name="groupBy - util should return valid data basing on predicate" time="0"> + <testcase classname="getUpdatedModel - util when payload has invalid modelId returns undefined" name="getUpdatedModel - util when payload has invalid modelId returns undefined" time="0"> + </testcase> + <testcase classname="getUpdatedModel - util when payload does not have modelId returns undefined" name="getUpdatedModel - util when payload does not have modelId returns undefined" time="0"> </testcase> </testsuite> - <testsuite name="getFontSizeToFit" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.153" tests="5"> - <testcase classname="getFontSizeToFit on text=Hello, fontFace=Helvetica, maxWidth=50 it should return value 10" name="getFontSizeToFit on text=Hello, fontFace=Helvetica, maxWidth=50 it should return value 10" time="0.003"> + <testsuite name="getFontSizeToFit" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.132" tests="5"> + <testcase classname="getFontSizeToFit on text=Hello, fontFace=Helvetica, maxWidth=50 it should return value 10" name="getFontSizeToFit on text=Hello, fontFace=Helvetica, maxWidth=50 it should return value 10" time="0.002"> </testcase> <testcase classname="getFontSizeToFit on text=123, fontFace=Arial, maxWidth=48 it should return value 16" name="getFontSizeToFit on text=123, fontFace=Arial, maxWidth=48 it should return value 16" time="0.001"> </testcase> @@ -1020,121 +1374,141 @@ </testcase> <testcase classname="getFontSizeToFit on text=Text, fontFace=, maxWidth=0 it should return value 0" name="getFontSizeToFit on text=Text, fontFace=, maxWidth=0 it should return value 0" time="0.001"> </testcase> - <testcase classname="getFontSizeToFit on text=, fontFace=, maxWidth=0 it should return value 0" name="getFontSizeToFit on text=, fontFace=, maxWidth=0 it should return value 0" time="0"> + <testcase classname="getFontSizeToFit on text=, fontFace=, maxWidth=0 it should return value 0" name="getFontSizeToFit on text=, fontFace=, maxWidth=0 it should return value 0" time="0.001"> </testcase> </testsuite> - <testsuite name="radiansToDegrees - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.144" tests="3"> - <testcase classname="radiansToDegrees - util coverts positive radian to close positive degrees" name="radiansToDegrees - util coverts positive radian to close positive degrees" time="0.001"> + <testsuite name="getGroupedReferences - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.133" tests="3"> + <testcase classname="getGroupedReferences - util should return correct grouped references" name="getGroupedReferences - util should return correct grouped references" time="0.002"> </testcase> - <testcase classname="radiansToDegrees - util coverts negative radian to close negative degrees" name="radiansToDegrees - util coverts negative radian to close negative degrees" time="0"> + <testcase classname="getGroupedReferences - util should return correct grouped references" name="getGroupedReferences - util should return correct grouped references" time="0.001"> </testcase> - <testcase classname="radiansToDegrees - util coverts zero radian to zero degrees" name="radiansToDegrees - util coverts zero radian to zero degrees" time="0"> + <testcase classname="getGroupedReferences - util should return correct grouped references" name="getGroupedReferences - util should return correct grouped references" time="0"> </testcase> </testsuite> - <testsuite name="degreesToRadians - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.133" tests="3"> - <testcase classname="degreesToRadians - util coverts positive degree to close positive radians" name="degreesToRadians - util coverts positive degree to close positive radians" time="0.001"> + <testsuite name="addAlphaToHexString" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.133" tests="5"> + <testcase classname="addAlphaToHexString for [ '#ff0000', undefined ] should return #ff0000ff" name="addAlphaToHexString for [ '#ff0000', undefined ] should return #ff0000ff" time="0.008"> </testcase> - <testcase classname="degreesToRadians - util coverts negative degree to close negative radians" name="degreesToRadians - util coverts negative degree to close negative radians" time="0"> + <testcase classname="addAlphaToHexString for [ '#ff0000', 1 ] should return #ff0000ff" name="addAlphaToHexString for [ '#ff0000', 1 ] should return #ff0000ff" time="0.001"> </testcase> - <testcase classname="degreesToRadians - util coverts zero degree to zero radians" name="degreesToRadians - util coverts zero degree to zero radians" time="0"> + <testcase classname="addAlphaToHexString for [ '#ff0000', 0.8 ] should return #ff0000cc" name="addAlphaToHexString for [ '#ff0000', 0.8 ] should return #ff0000cc" time="0"> + </testcase> + <testcase classname="addAlphaToHexString for [ '#ff0000', 0.5 ] should return #ff000080" name="addAlphaToHexString for [ '#ff0000', 0.5 ] should return #ff000080" time="0"> + </testcase> + <testcase classname="addAlphaToHexString for [ '#ff0000', 0 ] should return #ff000000" name="addAlphaToHexString for [ '#ff0000', 0 ] should return #ff000000" time="0.001"> </testcase> </testsuite> - <testsuite name="getPinStyle - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.416" tests="3"> + <testsuite name="user reducer" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:47" time="0.198" tests="4"> + <testcase classname="user reducer should match initial state" name="user reducer should match initial state" time="0.003"> + </testcase> + <testcase classname="user reducer should update store after successful login query" name="user reducer should update store after successful login query" time="0.007"> + </testcase> + <testcase classname="user reducer should update store on loading login query" name="user reducer should update store on loading login query" time="0.001"> + </testcase> + <testcase classname="user reducer should update store after successful getSessionValid query" name="user reducer should update store after successful getSessionValid query" time="0.001"> + </testcase> + </testsuite> + <testsuite name="getPinStyle - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.166" tests="3"> <testcase classname="getPinStyle - subUtil should return instance of Style" name="getPinStyle - subUtil should return instance of Style" time="0.001"> </testcase> - <testcase classname="getPinStyle - subUtil should return image object with displacament of pin size height" name="getPinStyle - subUtil should return image object with displacament of pin size height" time="0.007"> + <testcase classname="getPinStyle - subUtil should return image object with displacament of pin size height" name="getPinStyle - subUtil should return image object with displacament of pin size height" time="0"> </testcase> <testcase classname="getPinStyle - subUtil should return image of pin size" name="getPinStyle - subUtil should return image of pin size" time="0"> </testcase> </testsuite> - <testsuite name="createOverlayGeometryFeature" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.399" tests="2"> - <testcase classname="createOverlayGeometryFeature should create a feature with the correct geometry and style" name="createOverlayGeometryFeature should create a feature with the correct geometry and style" time="0.002"> + <testsuite name="getMapTileUrl - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.136" tests="2"> + <testcase classname="getMapTileUrl - util when projectDirectory is empty should return empty value" name="getMapTileUrl - util when projectDirectory is empty should return empty value" time="0.001"> </testcase> - <testcase classname="createOverlayGeometryFeature should create a feature with the correct geometry and style when using a different color" name="createOverlayGeometryFeature should create a feature with the correct geometry and style when using a different color" time="0"> + <testcase classname="getMapTileUrl - util when all args are valid should return correct value" name="getMapTileUrl - util when all args are valid should return correct value" time="0.001"> </testcase> </testsuite> - <testsuite name="getLineFeature" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="1.064" tests="2"> - <testcase classname="getLineFeature should return valid Feature object" name="getLineFeature should return valid Feature object" time="0.003"> + <testsuite name="interpolateColor" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.141" tests="5"> + <testcase classname="interpolateColor should return color1 for position 0" name="interpolateColor should return color1 for position 0" time="0.001"> </testcase> - <testcase classname="getLineFeature should return valid Feature object with LineString geometry" name="getLineFeature should return valid Feature object with LineString geometry" time="0.011"> + <testcase classname="interpolateColor should return color2 for position 1" name="interpolateColor should return color2 for position 1" time="0"> </testcase> - </testsuite> - <testsuite name="useOlMapReactionsLayer - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="1.078" tests="2"> - <testcase classname="useOlMapReactionsLayer - util should return VectorLayer" name="useOlMapReactionsLayer - util should return VectorLayer" time="0.01"> + <testcase classname="interpolateColor should interpolate colors for position 0.25" name="interpolateColor should interpolate colors for position 0.25" time="0.001"> + </testcase> + <testcase classname="interpolateColor should interpolate colors for position 0.5" name="interpolateColor should interpolate colors for position 0.5" time="0"> </testcase> - <testcase classname="useOlMapReactionsLayer - util should return VectorLayer with valid Style" name="useOlMapReactionsLayer - util should return VectorLayer with valid Style" time="0.01"> + <testcase classname="interpolateColor should interpolate colors for position 0.75" name="interpolateColor should interpolate colors for position 0.75" time="0"> </testcase> </testsuite> - <testsuite name="getPinFeature - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="1.04" tests="3"> - <testcase classname="getPinFeature - subUtil should return instance of Feature" name="getPinFeature - subUtil should return instance of Feature" time="0.001"> + <testsuite name="api path" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.125" tests="3"> + <testcase classname="api path should return url string for drugs" name="api path should return url string for drugs" time="0.001"> </testcase> - <testcase classname="getPinFeature - subUtil should return id as name" name="getPinFeature - subUtil should return id as name" time="0.001"> + <testcase classname="api path should return url string for bio entity content" name="api path should return url string for bio entity content" time="0.001"> </testcase> - <testcase classname="getPinFeature - subUtil should return point parsed with point to projection" name="getPinFeature - subUtil should return point parsed with point to projection" time="0.001"> + <testcase classname="api path should return url string for bio entity content" name="api path should return url string for bio entity content" time="0"> </testcase> </testsuite> - <testsuite name="getBioEntitySingleFeature - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="1.057" tests="6"> - <testcase classname="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=bioEntity" name="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=bioEntity" time="0.012"> + <testsuite name="expandHexToFullFormatIfItsShorthanded" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.124" tests="11"> + <testcase classname="expandHexToFullFormatIfItsShorthanded should expand short-handed hex string to full format" name="expandHexToFullFormatIfItsShorthanded should expand short-handed hex string to full format" time="0.001"> </testcase> - <testcase classname="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=drugs" name="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=drugs" time="0.001"> + <testcase classname="expandHexToFullFormatIfItsShorthanded should not modify full-format hex string" name="expandHexToFullFormatIfItsShorthanded should not modify full-format hex string" time="0"> </testcase> - <testcase classname="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=chemicals" name="getBioEntitySingleFeature - subUtil should return instance of Feature with Style type=chemicals" time="0.001"> + <testcase classname="expandHexToFullFormatIfItsShorthanded should handle hex string without leading #" name="expandHexToFullFormatIfItsShorthanded should handle hex string without leading #" time="0"> </testcase> - <testcase classname="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=bioEntity" name="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=bioEntity" time="0.003"> + <testcase classname="expandHexToFullFormatIfItsShorthanded should return original string if it does not match short-hand regex" name="expandHexToFullFormatIfItsShorthanded should return original string if it does not match short-hand regex" time="0"> </testcase> - <testcase classname="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=drugs" name="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=drugs" time="0.002"> + <testcase classname="hexToRgb should convert valid hex string to RGB object" name="hexToRgb should convert valid hex string to RGB object" time="0"> </testcase> - <testcase classname="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=chemicals" name="getBioEntitySingleFeature - subUtil should run getPinStyle with valid args for type=chemicals" time="0.002"> + <testcase classname="hexToRgb should return null for invalid hex string" name="hexToRgb should return null for invalid hex string" time="0"> </testcase> - </testsuite> - <testsuite name="useOlMapPinsLayer - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="1.068" tests="1"> - <testcase classname="useOlMapPinsLayer - util should return VectorLayer" name="useOlMapPinsLayer - util should return VectorLayer" time="0.025"> + <testcase classname="hexToRgb should handle hex string without leading #" name="hexToRgb should handle hex string without leading #" time="0.001"> </testcase> - </testsuite> - <testsuite name="getBioEntitiesFeatures - subUtil" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.992" tests="3"> - <testcase classname="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=bioEntity" name="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=bioEntity" time="0.024"> + <testcase classname="hexToRgb should return null for hex string with invalid characters" name="hexToRgb should return null for hex string with invalid characters" time="0"> </testcase> - <testcase classname="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=drugs" name="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=drugs" time="0.005"> + <testcase classname="hexToRgb should convert short-handed RGB hex string without leading # to RGB object" name="hexToRgb should convert short-handed RGB hex string without leading # to RGB object" time="0"> </testcase> - <testcase classname="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=chemicals" name="getBioEntitiesFeatures - subUtil should return array of instances of Feature with Style type=chemicals" time="0.005"> + <testcase classname="hexToRgb should handle short-handed RGB hex string with invalid characters" name="hexToRgb should handle short-handed RGB hex string with invalid characters" time="0"> + </testcase> + <testcase classname="hexToRgb should handle short-handed RGB hex string with invalid characters and without leading #" name="hexToRgb should handle short-handed RGB hex string with invalid characters and without leading #" time="0"> </testcase> </testsuite> - <testsuite name="useOlMapListeners - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="1.012" tests="2"> - <testcase classname="useOlMapListeners - util on change:center view event should run onMapPositionChange event" name="useOlMapListeners - util on change:center view event should run onMapPositionChange event" time="0.01"> + <testsuite name="getPointMerged" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.117" tests="3"> + <testcase classname="getPointMerged should return valid merged point" name="getPointMerged should return valid merged point" time="0.001"> </testcase> - <testcase classname="useOlMapListeners - util on singleclick view event should run onMapPositionChange event" name="useOlMapListeners - util on singleclick view event should run onMapPositionChange event" time="0.001"> + <testcase classname="getPointMerged should return valid merged point" name="getPointMerged should return valid merged point" time="0"> </testcase> - </testsuite> - <testsuite name="useOlMapTileLayer - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="0.859" tests="1"> - <testcase classname="useOlMapTileLayer - util should return valid TileLayer instance" name="useOlMapTileLayer - util should return valid TileLayer instance" time="0.013"> + <testcase classname="getPointMerged should return valid merged point" name="getPointMerged should return valid merged point" time="0"> </testcase> </testsuite> - <testsuite name="useOlMapView - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:24" time="1.067" tests="2"> - <testcase classname="useOlMapView - util should modify view of the map instance on INITIAL position config change" name="useOlMapView - util should modify view of the map instance on INITIAL position config change" time="0.047"> + <testsuite name="getSearchValuesArray - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.119" tests="6"> + <testcase classname="getSearchValuesArray - util should return array of values when string has ; separator" name="getSearchValuesArray - util should return array of values when string has ; separator" time="0.002"> </testcase> - <testcase classname="useOlMapView - util should return valid View instance" name="useOlMapView - util should return valid View instance" time="0.007"> + <testcase classname="getSearchValuesArray - util should trim values to seven if more values are provided" name="getSearchValuesArray - util should trim values to seven if more values are provided" time="0"> </testcase> - </testsuite> - <testsuite name="useOlMapLayers - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:25" time="0.469" tests="4"> - <testcase classname="useOlMapLayers - util should modify layers of the map instance on init" name="useOlMapLayers - util should modify layers of the map instance on init" time="0.029"> + <testcase classname="getSearchValuesArray - util should return single value in array if no ; was passed in string" name="getSearchValuesArray - util should return single value in array if no ; was passed in string" time="0"> </testcase> - <testcase classname="useOlMapLayers - util should return valid TileLayer instance [1]" name="useOlMapLayers - util should return valid TileLayer instance [1]" time="0.01"> + <testcase classname="getDefaultSearchTab for [ 'nadh', 'o2', 'mp3' ] should return nadh" name="getDefaultSearchTab for [ 'nadh', 'o2', 'mp3' ] should return nadh" time="0"> </testcase> - <testcase classname="useOlMapLayers - util should return valid VectorLayer instance [2]" name="useOlMapLayers - util should return valid VectorLayer instance [2]" time="0.009"> + <testcase classname="getDefaultSearchTab for [ 'o2' ] should return o2" name="getDefaultSearchTab for [ 'o2' ] should return o2" time="0.001"> </testcase> - <testcase classname="useOlMapLayers - util should return valid VectorLayer instance [3]" name="useOlMapLayers - util should return valid VectorLayer instance [3]" time="0.006"> + <testcase classname="getDefaultSearchTab for [ '' ] should return " name="getDefaultSearchTab for [ '' ] should return " time="0"> </testcase> </testsuite> - <testsuite name="useOlMap - util" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:25" time="0.455" tests="2"> - <testcase classname="useOlMap - util when initializing should set map instance" name="useOlMap - util when initializing should set map instance" time="0.033"> + <testsuite name="rgbToHex - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.123" tests="2"> + <testcase classname="rgbToHex - util should convert RGB values to hex format" name="rgbToHex - util should convert RGB values to hex format" time="0.001"> </testcase> - <testcase classname="useOlMap - util when initializing should render content inside the target element" name="useOlMap - util when initializing should render content inside the target element" time="0.006"> + <testcase classname="rgbToHex - util should handle invalid input values" name="rgbToHex - util should handle invalid input values" time="0.004"> </testcase> </testsuite> - <testsuite name="MapViewer - component" errors="0" failures="0" skipped="0" timestamp="2024-01-03T15:35:25" time="0.482" tests="2"> - <testcase classname="MapViewer - component should render component container" name="MapViewer - component should render component container" time="0.045"> + <testsuite name="boundNumber - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.103" tests="3"> + <testcase classname="boundNumber - util should return valid bounded number | v = 1, minMax = (0, 2), final = 1" name="boundNumber - util should return valid bounded number | v = 1, minMax = (0, 2), final = 1" time="0.001"> + </testcase> + <testcase classname="boundNumber - util should return valid bounded number | v = 1, minMax = (2, 2), final = 2" name="boundNumber - util should return valid bounded number | v = 1, minMax = (2, 2), final = 2" time="0"> + </testcase> + <testcase classname="boundNumber - util should return valid bounded number | v = 2, minMax = (0, 1), final = 1" name="boundNumber - util should return valid bounded number | v = 2, minMax = (0, 1), final = 1" time="0"> </testcase> - <testcase classname="MapViewer - component should render openlayers map inside the component" name="MapViewer - component should render openlayers map inside the component" time="0.008"> + </testsuite> + <testsuite name="getTruthyObjectOrUndefined - util" errors="0" failures="0" skipped="0" timestamp="2024-01-12T14:39:48" time="0.095" tests="4"> + <testcase classname="getTruthyObjectOrUndefined - util shoud return a truthy object if the object is truthy" name="getTruthyObjectOrUndefined - util shoud return a truthy object if the object is truthy" time="0.001"> + </testcase> + <testcase classname="getTruthyObjectOrUndefined - util shoud return a truthy object if the object is empty" name="getTruthyObjectOrUndefined - util shoud return a truthy object if the object is empty" time="0"> + </testcase> + <testcase classname="getTruthyObjectOrUndefined - util shoud return undefined if the object is partially truthy" name="getTruthyObjectOrUndefined - util shoud return undefined if the object is partially truthy" time="0.001"> + </testcase> + <testcase classname="getTruthyObjectOrUndefined - util shoud return undefined if the objects's nested objects is partially truthy" name="getTruthyObjectOrUndefined - util shoud return undefined if the objects's nested objects is partially truthy" time="0"> </testcase> </testsuite> </testsuites> \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 815105c02df0818adc2c668a6afc742796eff297..4aad8440554ebbab3ac260423e29db2eb4097bbe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21036,8 +21036,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.camelcase": { "version": "4.3.0", diff --git a/package.json b/package.json index 8a754dc0eed77ccbde955e6e3a335e05258a463e..4cf34d33a72916303aa6cf834ab8b7e4f1e2a1ba 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "check-types": "tsc --pretty --noEmit", "prepare": "husky install", "postinstall": "husky install", - "test": "jest --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!@toolz/allow-react)/'", - "test:watch": "jest --watch --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|.*\\.mjs$))'", + "test": "jest --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$))'", + "test:watch": "jest --watch --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$))'", "test:ci": "jest --config ./jest.config.ts --collectCoverage --coverageDirectory=\"./coverage\" --ci --reporters=default --reporters=jest-junit --watchAll=false --passWithNoTests --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$))'", "test:coverage": "jest --watchAll --coverage --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|.*\\.mjs$))'", "test:coveragee": "jest --coverage --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|.*\\.mjs$))'", diff --git a/src/components/AppWrapper/AppWrapper.component.tsx b/src/components/AppWrapper/AppWrapper.component.tsx index 2bb7e192c61b37fef97dafaf58cd0bfc1d94395d..3b59e82bec77dc93528d14168014000abd095242 100644 --- a/src/components/AppWrapper/AppWrapper.component.tsx +++ b/src/components/AppWrapper/AppWrapper.component.tsx @@ -1,11 +1,14 @@ +import { store } from '@/redux/store'; +import { MapInstanceProvider } from '@/utils/context/mapInstanceContext'; import { ReactNode } from 'react'; import { Provider } from 'react-redux'; -import { store } from '@/redux/store'; interface AppWrapperProps { children: ReactNode; } export const AppWrapper = ({ children }: AppWrapperProps): JSX.Element => ( - <Provider store={store}>{children}</Provider> + <MapInstanceProvider> + <Provider store={store}>{children}</Provider> + </MapInstanceProvider> ); diff --git a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.test.tsx b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.test.tsx index 4b7ee0e1d1ea8db5dbd3ff8d4eceb72f6f29b775..4925b9c9b892ab79626a1f0832aeb5f31c6c6fca 100644 --- a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.test.tsx +++ b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.test.tsx @@ -65,7 +65,12 @@ describe('SearchBar - component', () => { query: { searchValue: 'aspirin;nadh' }, }); renderComponent(); + + const input = screen.getByTestId<HTMLInputElement>('search-input'); + + expect(input.value).toBe('aspirin;nadh'); }); + it('should change selected search element when user search another', () => { const { store } = renderComponent(); const input = screen.getByTestId<HTMLInputElement>('search-input'); diff --git a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx index 02c20a18c027610cc60e3980107665ab9a0f75ec..ee5d31369ed9062989ef97c07c4d762c1933cb1c 100644 --- a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx +++ b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx @@ -8,7 +8,8 @@ import { } from '@/redux/search/search.selectors'; import { getSearchData } from '@/redux/search/search.thunks'; import Image from 'next/image'; -import { ChangeEvent, KeyboardEvent, useState } from 'react'; +import { ChangeEvent, KeyboardEvent, useCallback, useEffect, useState } from 'react'; +import { useRouter } from 'next/router'; import { useSelector } from 'react-redux'; import { getDefaultSearchTab, getSearchValuesArrayAndTrimToSeven } from './SearchBar.utils'; @@ -20,6 +21,14 @@ export const SearchBar = (): JSX.Element => { const isDrawerOpen = useSelector(isDrawerOpenSelector); const isPerfectMatch = useSelector(perfectMatchSelector); const dispatch = useAppDispatch(); + const router = useRouter(); + + const updateSearchValueFromQueryParam = useCallback((): void => { + const { searchValue: searchValueQueryParam } = router.query; + if (typeof searchValueQueryParam === 'string') { + setSearchValue(searchValueQueryParam); + } + }, [router.query]); const openSearchDrawerIfClosed = (defaultSearchTab: string): void => { if (!isDrawerOpen) { @@ -49,6 +58,10 @@ export const SearchBar = (): JSX.Element => { } }; + useEffect(() => { + updateSearchValueFromQueryParam(); + }, [updateSearchValueFromQueryParam]); + return ( <div className="relative" data-testid="search-bar"> <input diff --git a/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.test.tsx deleted file mode 100644 index df05c8e0c5e7fcef43da5d5085d34a3c6ea14f43..0000000000000000000000000000000000000000 --- a/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.test.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { render, screen, waitFor } from '@testing-library/react'; -import { - InitialStoreState, - getReduxWrapperWithStore, -} from '@/utils/testing/getReduxWrapperWithStore'; -import { StoreType } from '@/redux/store'; -import { statisticsFixture } from '@/models/fixtures/statisticsFixture'; -import { act } from 'react-dom/test-utils'; -import { Annotations } from './Annotations.component'; - -const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { - const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState); - - return ( - render( - <Wrapper> - <Annotations /> - </Wrapper>, - ), - { - store, - } - ); -}; - -describe('Annotations - component', () => { - it('should display annotations checkboxes when fetching data is successful', async () => { - renderComponent({ - statistics: { - data: { - ...statisticsFixture, - elementAnnotations: { - compartment: 1, - pathway: 0, - }, - }, - loading: 'succeeded', - error: { - message: '', - name: '', - }, - }, - }); - const navigationButton = screen.getByTestId('accordion-item-button'); - - act(() => { - navigationButton.click(); - }); - - expect(screen.getByText('Select annotations')).toBeInTheDocument(); - - await waitFor(() => { - expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument(); - expect(screen.getByLabelText('compartment')).toBeInTheDocument(); - expect(screen.getByLabelText('search-input')).toBeInTheDocument(); - }); - }); - it('should not display annotations checkboxes when fetching data fails', async () => { - renderComponent({ - statistics: { - data: undefined, - loading: 'failed', - error: { - message: '', - name: '', - }, - }, - }); - expect(screen.getByText('Select annotations')).toBeInTheDocument(); - const navigationButton = screen.getByTestId('accordion-item-button'); - act(() => { - navigationButton.click(); - }); - - expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument(); - }); - it('should not display annotations checkboxes when fetched data is empty object', async () => { - renderComponent({ - statistics: { - data: { - ...statisticsFixture, - elementAnnotations: {}, - }, - loading: 'failed', - error: { - message: '', - name: '', - }, - }, - }); - expect(screen.getByText('Select annotations')).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({ - statistics: { - data: undefined, - loading: 'pending', - error: { - message: '', - name: '', - }, - }, - }); - expect(screen.getByText('Select annotations')).toBeInTheDocument(); - const navigationButton = screen.getByTestId('accordion-item-button'); - act(() => { - navigationButton.click(); - }); - - expect(screen.getByText('Loading...')).toBeInTheDocument(); - }); -}); diff --git a/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.tsx b/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.tsx deleted file mode 100644 index a68fd3894887e2c5fa30733e4388d8f8f76927eb..0000000000000000000000000000000000000000 --- a/src/components/Map/Drawer/ExportDrawer/Annotations/Annotations.component.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* eslint-disable no-magic-numbers */ -import { - Accordion, - AccordionItem, - AccordionItemButton, - AccordionItemHeading, - AccordionItemPanel, -} from '@/shared/Accordion'; -import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { - elementAnnotationsSelector, - loadingStatisticsSelector, -} from '@/redux/statistics/statistics.selectors'; -import { CheckboxFilter } from '../CheckboxFilter'; - -export const Annotations = (): React.ReactNode => { - const loadingStatistics = useAppSelector(loadingStatisticsSelector); - const elementAnnotations = useAppSelector(elementAnnotationsSelector); - const isPending = loadingStatistics === 'pending'; - - const mappedElementAnnotations = elementAnnotations - ? Object.keys(elementAnnotations)?.map(el => ({ id: el, label: el })) - : []; - - return ( - <Accordion allowZeroExpanded> - <AccordionItem> - <AccordionItemHeading> - <AccordionItemButton>Select annotations</AccordionItemButton> - </AccordionItemHeading> - <AccordionItemPanel> - {isPending && <p>Loading...</p>} - {!isPending && mappedElementAnnotations && mappedElementAnnotations.length > 0 && ( - <CheckboxFilter options={mappedElementAnnotations} /> - )} - </AccordionItemPanel> - </AccordionItem> - </Accordion> - ); -}; diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx index 68dbe9c6ecf1ea715852925c85e2f2d18b3d4ad2..54ac8df4fc0f8634d21a474a3d4cfca07b239434 100644 --- a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx @@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react'; import lensIcon from '@/assets/vectors/icons/lens.svg'; import { twMerge } from 'tailwind-merge'; -type CheckboxItem = { id: string; label: string }; +export type CheckboxItem = { id: string; label: string }; type CheckboxFilterProps = { options: CheckboxItem[]; diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/index.ts b/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/index.ts deleted file mode 100644 index 3b82aaf76f1b363c9cc2429bbe05d17938bdac29..0000000000000000000000000000000000000000 --- a/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { Annotations } from './Annotations.component'; diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.tsx deleted file mode 100644 index c6d8084fe24299b8f13a6fc07dc1aa6019188646..0000000000000000000000000000000000000000 --- a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { CheckboxFilter } from '../../CheckboxFilter'; -import { CollapsibleSection } from '../../CollapsibleSection'; -import { COLUMNS } from './Columns.constants'; - -export const Columns = (): React.ReactNode => ( - <CollapsibleSection title="Select column"> - <CheckboxFilter options={COLUMNS} isSearchEnabled={false} /> - </CollapsibleSection> -); diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx index ffc3bf45e09d8512073f41cfa3b858c6627b5c66..fcf01b6a0c8fd6cae6b847e245f70e3d072508e7 100644 --- a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx @@ -1,31 +1,16 @@ -import { useEffect } from 'react'; -import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { modelsDataSelector } from '@/redux/models/models.selectors'; -import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; -import { getCompartmentPathways } from '@/redux/compartmentPathways/compartmentPathways.thunks'; -import { Annotations } from '../Annotations'; -import { Types } from './Types'; -import { IncludedCompartmentPathways } from './IncludedCompartmentPathways '; -import { ExcludedCompartmentPathways } from './ExcludedCompartmentPathways'; -import { Columns } from './Columns'; -import { getModelsIds } from './Elements.utils'; +import { Export } from '../ExportCompound'; export const Elements = (): React.ReactNode => { - const models = useAppSelector(modelsDataSelector); - const dispatch = useAppDispatch(); - - useEffect(() => { - const modelsIds = getModelsIds(models); - dispatch(getCompartmentPathways(modelsIds)); - }, [dispatch, models]); - return ( <div data-testid="elements-tab"> - <Types /> - <Columns /> - <Annotations /> - <IncludedCompartmentPathways /> - <ExcludedCompartmentPathways /> + <Export> + <Export.Types /> + <Export.Columns /> + <Export.Annotations /> + <Export.IncludedCompartmentPathways /> + <Export.ExcludedCompartmentPathways /> + <Export.DownloadElements /> + </Export> </div> ); }; diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.ts b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.ts index 25c681809836f5f8fa2fb66b2d7e5dae79707fe1..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.ts +++ b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.ts @@ -1,42 +0,0 @@ -/* eslint-disable no-magic-numbers */ -import { CompartmentPathwayDetails, MapModel } from '@/types/models'; - -type AddedNames = { [key: string]: number }; - -type CheckboxElement = { id: string; label: string }; - -type CheckboxElements = CheckboxElement[]; - -export const getCompartmentPathwaysCheckboxElements = ( - items: CompartmentPathwayDetails[], -): CheckboxElements => { - const addedNames: AddedNames = {}; - - const setNameToIdIfUndefined = (item: CompartmentPathwayDetails): void => { - if (addedNames[item.name] === undefined) { - addedNames[item.name] = item.id; - } - }; - - items.forEach(setNameToIdIfUndefined); - - const parseIdAndLabel = ([name, id]: [name: string, id: number]): CheckboxElement => ({ - id: id.toString(), - label: name, - }); - - const sortByLabel = (a: CheckboxElement, b: CheckboxElement): number => { - if (a.label > b.label) return 1; - return -1; - }; - - const elements = Object.entries(addedNames).map(parseIdAndLabel).sort(sortByLabel); - - return elements; -}; - -export const getModelsIds = (models: MapModel[] | undefined): number[] => { - if (!models) return []; - - return models.map(model => model.idObject); -}; diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.test.tsx similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.test.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.test.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.tsx similarity index 73% rename from src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.tsx index f3795e9b9f5c9828957e6691c5427fd42deacd2d..6f7034f871d9034f2a038493d426d6784d552b02 100644 --- a/src/components/Map/Drawer/ExportDrawer/Elements/Annotations/Annotations.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.tsx @@ -1,13 +1,16 @@ -/* eslint-disable no-magic-numbers */ +import { useContext } from 'react'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; import { elementAnnotationsSelector, loadingStatisticsSelector, } from '@/redux/statistics/statistics.selectors'; +import { ZERO } from '@/constants/common'; import { CheckboxFilter } from '../../CheckboxFilter'; import { CollapsibleSection } from '../../CollapsibleSection'; +import { ExportContext } from '../ExportCompound.context'; export const Annotations = (): React.ReactNode => { + const { setAnnotations } = useContext(ExportContext); const loadingStatistics = useAppSelector(loadingStatisticsSelector); const elementAnnotations = useAppSelector(elementAnnotationsSelector); const isPending = loadingStatistics === 'pending'; @@ -19,8 +22,8 @@ export const Annotations = (): React.ReactNode => { return ( <CollapsibleSection title="Select annotations"> {isPending && <p>Loading...</p>} - {!isPending && mappedElementAnnotations && mappedElementAnnotations.length > 0 && ( - <CheckboxFilter options={mappedElementAnnotations} /> + {!isPending && mappedElementAnnotations && mappedElementAnnotations.length > ZERO && ( + <CheckboxFilter options={mappedElementAnnotations} onCheckedChange={setAnnotations} /> )} </CollapsibleSection> ); diff --git a/src/components/Map/Drawer/ExportDrawer/Annotations/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/index.ts similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Annotations/index.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/index.ts diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.test.tsx similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.component.test.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.test.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..954a4c60a4354f675d4c7bab265f45d69c384039 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.tsx @@ -0,0 +1,15 @@ +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> + ); +}; diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.constants.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.constants.tsx similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/Columns/Columns.constants.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.constants.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Columns/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/index.ts similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/Columns/index.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/index.ts diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadElements/DownloadElements.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadElements/DownloadElements.tsx new file mode 100644 index 0000000000000000000000000000000000000000..53276caa74a5bd4b0851f3b189df50e79a2a53f3 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadElements/DownloadElements.tsx @@ -0,0 +1,13 @@ +import { useContext } from 'react'; +import { Button } from '@/shared/Button'; +import { ExportContext } from '../ExportCompound.context'; + +export const DownloadElements = (): React.ReactNode => { + const { handleDownloadElements } = useContext(ExportContext); + + return ( + <div className="mt-6"> + <Button onClick={handleDownloadElements}>Download</Button> + </div> + ); +}; diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadElements/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadElements/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/DownloadNetwork.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/DownloadNetwork.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fbe769f0877561ab755049749e12577e13c1b005 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/DownloadNetwork.tsx @@ -0,0 +1,13 @@ +import { useContext } from 'react'; +import { Button } from '@/shared/Button'; +import { ExportContext } from '../ExportCompound.context'; + +export const DownloadElements = (): React.ReactNode => { + const { handleDownloadNetwork } = useContext(ExportContext); + + return ( + <div className="mt-6"> + <Button onClick={handleDownloadNetwork}>Download</Button> + </div> + ); +}; diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.test.tsx similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.test.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.test.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx similarity index 64% rename from src/components/Map/Drawer/ExportDrawer/Elements/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx index 73e95759251ec96571f7f7d88eb84dcccf3b6389..a1de0816bef5e657fee1ee41ca4ed3f0937d0160 100644 --- a/src/components/Map/Drawer/ExportDrawer/Elements/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx @@ -1,24 +1,32 @@ -/* eslint-disable no-magic-numbers */ +import { useContext } from 'react'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; import { compartmentPathwaysDataSelector, loadingCompartmentPathwaysSelector, } from '@/redux/compartmentPathways/compartmentPathways.selectors'; +import { ZERO } from '@/constants/common'; import { CheckboxFilter } from '../../CheckboxFilter'; import { CollapsibleSection } from '../../CollapsibleSection'; -import { getCompartmentPathwaysCheckboxElements } from '../Elements.utils'; +import { ExportContext } from '../ExportCompound.context'; +import { getCompartmentPathwaysCheckboxElements } from '../utils/getCompartmentPathwaysCheckboxElements'; export const ExcludedCompartmentPathways = (): React.ReactNode => { + const { setExcludedCompartmentPathways } = useContext(ExportContext); const loadingCompartmentPathways = useAppSelector(loadingCompartmentPathwaysSelector); const isPending = loadingCompartmentPathways === 'pending'; const compartmentPathways = useAppSelector(compartmentPathwaysDataSelector); const checkboxElements = getCompartmentPathwaysCheckboxElements(compartmentPathways); - const isCheckboxFilterVisible = !isPending && checkboxElements && checkboxElements.length > 0; + const isCheckboxFilterVisible = !isPending && checkboxElements && checkboxElements.length > ZERO; return ( <CollapsibleSection title="Select excluded compartment / pathways"> {isPending && <p>Loading...</p>} - {isCheckboxFilterVisible && <CheckboxFilter options={checkboxElements} />} + {isCheckboxFilterVisible && ( + <CheckboxFilter + options={checkboxElements} + onCheckedChange={setExcludedCompartmentPathways} + /> + )} </CollapsibleSection> ); }; diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/ExcludedCompartmentPathways/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/index.ts similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/ExcludedCompartmentPathways/index.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/index.ts diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..15f4767e22864d74979a577f62314f5af2d828de --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx @@ -0,0 +1,74 @@ +import { ReactNode, useCallback, useMemo, useState } from 'react'; +import { useAppSelector } from '@/redux/hooks/useAppSelector'; +import { modelsIdsSelector } from '@/redux/models/models.selectors'; +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 '; +import { DownloadElements } from './DownloadElements/DownloadElements'; +import { ExportContext } from './ExportCompound.context'; +import { getNetworkDownloadBodyRequest } from './utils/getNetworkBodyRequest'; +import { getDownloadElementsBodyRequest } from './utils/getDownloadElementsBodyRequest'; + +type ExportProps = { + children: ReactNode; +}; + +export const Export = ({ children }: ExportProps): JSX.Element => { + const [types, setTypes] = useState<CheckboxItem[]>([]); + const [columns, setColumns] = useState<CheckboxItem[]>([]); + const [annotations, setAnnotations] = useState<CheckboxItem[]>([]); + const modelIds = useAppSelector(modelsIdsSelector); + const [includedCompartmentPathways, setIncludedCompartmentPathways] = useState<CheckboxItem[]>( + [], + ); + const [excludedCompartmentPathways, setExcludedCompartmentPathways] = useState<CheckboxItem[]>( + [], + ); + + const handleDownloadElements = useCallback(() => { + getDownloadElementsBodyRequest({ + types, + columns, + modelIds, + annotations, + includedCompartmentPathways, + excludedCompartmentPathways, + }); + }, [ + types, + columns, + modelIds, + annotations, + includedCompartmentPathways, + excludedCompartmentPathways, + ]); + + const handleDownloadNetwork = useCallback(() => { + getNetworkDownloadBodyRequest(); + }, []); + + const globalContextValue = useMemo( + () => ({ + setTypes, + setColumns, + setAnnotations, + setIncludedCompartmentPathways, + setExcludedCompartmentPathways, + handleDownloadElements, + handleDownloadNetwork, + }), + [handleDownloadElements, handleDownloadNetwork], + ); + + return <ExportContext.Provider value={globalContextValue}>{children}</ExportContext.Provider>; +}; + +Export.Types = Types; +Export.Columns = Columns; +Export.Annotations = Annotations; +Export.IncludedCompartmentPathways = IncludedCompartmentPathways; +Export.ExcludedCompartmentPathways = ExcludedCompartmentPathways; +Export.DownloadElements = DownloadElements; diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.context.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.context.ts new file mode 100644 index 0000000000000000000000000000000000000000..3490162eb61f13c9ddbf4f2a13d732693e98d003 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.context.ts @@ -0,0 +1,22 @@ +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[]>>; + handleDownloadElements: () => void; + handleDownloadNetwork: () => void; +}; + +export const ExportContext = createContext<ExportContextType>({ + setTypes: () => {}, + setColumns: () => {}, + setAnnotations: () => {}, + setIncludedCompartmentPathways: () => {}, + setExcludedCompartmentPathways: () => {}, + handleDownloadElements: () => {}, + handleDownloadNetwork: () => {}, +}); diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/IncludedCompartmentPathways /IncludedCompartmentPathways.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.test.tsx similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/IncludedCompartmentPathways /IncludedCompartmentPathways.component.test.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.test.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx similarity index 67% rename from src/components/Map/Drawer/ExportDrawer/Elements/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx index 77a64aed273ac294c018bc23197b1a1cd4036b0a..39164e58904ff7d2667b9573c82ad1d5a38e58f1 100644 --- a/src/components/Map/Drawer/ExportDrawer/Elements/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx @@ -1,14 +1,17 @@ -/* eslint-disable no-magic-numbers */ +import { useContext } from 'react'; import { compartmentPathwaysDataSelector, loadingCompartmentPathwaysSelector, } from '@/redux/compartmentPathways/compartmentPathways.selectors'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; +import { ZERO } from '@/constants/common'; import { CheckboxFilter } from '../../CheckboxFilter'; import { CollapsibleSection } from '../../CollapsibleSection'; -import { getCompartmentPathwaysCheckboxElements } from '../Elements.utils'; +import { ExportContext } from '../ExportCompound.context'; +import { getCompartmentPathwaysCheckboxElements } from '../utils/getCompartmentPathwaysCheckboxElements'; export const IncludedCompartmentPathways = (): React.ReactNode => { + const { setIncludedCompartmentPathways } = useContext(ExportContext); const loadingCompartmentPathways = useAppSelector(loadingCompartmentPathwaysSelector); const isPending = loadingCompartmentPathways === 'pending'; const compartmentPathways = useAppSelector(compartmentPathwaysDataSelector); @@ -17,8 +20,11 @@ export const IncludedCompartmentPathways = (): React.ReactNode => { return ( <CollapsibleSection title="Select included compartment / pathways"> {isPending && <p>Loading...</p>} - {!isPending && checkboxElements && checkboxElements.length > 0 && ( - <CheckboxFilter options={checkboxElements} /> + {!isPending && checkboxElements && checkboxElements.length > ZERO && ( + <CheckboxFilter + options={checkboxElements} + onCheckedChange={setIncludedCompartmentPathways} + /> )} </CollapsibleSection> ); diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/IncludedCompartmentPathways /index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /index.ts similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/IncludedCompartmentPathways /index.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /index.ts diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.test.tsx similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.test.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.test.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.tsx similarity index 64% rename from src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.tsx index 0c37bdf6907d676eeaed5182c5002710327ff13c..9398790028d9a1e60cbaeee9bf85014523839570 100644 --- a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.tsx @@ -1,16 +1,25 @@ +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} />} + {checkboxElements && ( + <CheckboxFilter + options={checkboxElements} + isSearchEnabled={false} + onCheckedChange={setTypes} + /> + )} </CollapsibleSection> ); }; diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.test.ts similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.test.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.test.ts diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.ts similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/Types/Types.utils.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.ts diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Types/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/index.ts similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/Elements/Types/index.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/index.ts diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc9ebec49c0de9036d71209be308feaecd41229c --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/index.ts @@ -0,0 +1 @@ +export { Export } from './ExportCompound.component'; diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.test.ts similarity index 74% rename from src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.test.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.test.ts index 76d374425476c156e0d2c9d8b5c4a8e2725ce4ad..d0a7806ce4d62ea5210b1249087b97345affa819 100644 --- a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.test.ts +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.test.ts @@ -1,7 +1,6 @@ /* eslint-disable no-magic-numbers */ import { CompartmentPathwayDetails } from '@/types/models'; -import { modelsFixture } from '@/models/fixtures/modelsFixture'; -import { getCompartmentPathwaysCheckboxElements, getModelsIds } from './Elements.utils'; +import { getCompartmentPathwaysCheckboxElements } from './getCompartmentPathwaysCheckboxElements'; describe('getCompartmentPathwaysCheckboxElements', () => { it('should return an empty array when given an empty items array', () => { @@ -45,17 +44,3 @@ describe('getCompartmentPathwaysCheckboxElements', () => { ]); }); }); - -const MODELS_IDS = modelsFixture.map(item => item.idObject); - -describe('getModelsIds', () => { - it('should return an empty array if models are not provided', () => { - const result = getModelsIds(undefined); - expect(result).toEqual([]); - }); - - it('should return an array of model IDs', () => { - const result = getModelsIds(modelsFixture); - expect(result).toEqual(MODELS_IDS); - }); -}); diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.ts new file mode 100644 index 0000000000000000000000000000000000000000..e0f4bf81a14c4fece41eff986e4b3685b2506f16 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.ts @@ -0,0 +1,36 @@ +/* eslint-disable no-magic-numbers */ +import { CompartmentPathwayDetails } from '@/types/models'; + +type AddedNames = { [key: string]: number }; + +type CheckboxElement = { id: string; label: string }; + +type CheckboxElements = CheckboxElement[]; + +export const getCompartmentPathwaysCheckboxElements = ( + items: CompartmentPathwayDetails[], +): CheckboxElements => { + const addedNames: AddedNames = {}; + + const setNameToIdIfUndefined = (item: CompartmentPathwayDetails): void => { + if (addedNames[item.name] === undefined) { + addedNames[item.name] = item.id; + } + }; + + items.forEach(setNameToIdIfUndefined); + + const parseIdAndLabel = ([name, id]: [name: string, id: number]): CheckboxElement => ({ + id: id.toString(), + label: name, + }); + + const sortByLabel = (a: CheckboxElement, b: CheckboxElement): number => { + if (a.label > b.label) return 1; + return -1; + }; + + const elements = Object.entries(addedNames).map(parseIdAndLabel).sort(sortByLabel); + + return elements; +}; diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..68d1e8f0ae0858439f4ed21fc681eef713d921b1 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.test.ts @@ -0,0 +1,47 @@ +import { getDownloadElementsBodyRequest } from './getDownloadElementsBodyRequest'; + +describe('getDownloadElementsBodyRequest', () => { + it('should return the correct DownloadBodyRequest object', () => { + const types = [ + { id: '1', label: 'Type 1' }, + { id: '2', label: 'Type 2' }, + ]; + const columns = [ + { id: '1', label: 'Column 1' }, + { id: '2', label: 'Column 2' }, + ]; + // eslint-disable-next-line no-magic-numbers + const modelIds = [1, 2, 3]; + const annotations = [ + { id: '1', label: 'Annotation 1' }, + { id: '2', label: 'Annotation 2' }, + ]; + const includedCompartmentPathways = [ + { id: '1', label: 'Compartment 1' }, + { id: '2', label: 'Compartment 2' }, + ]; + const excludedCompartmentPathways = [ + { id: '1', label: 'Compartment 3' }, + { id: '2', label: 'Compartment 4' }, + ]; + + const result = getDownloadElementsBodyRequest({ + types, + columns, + modelIds, + annotations, + includedCompartmentPathways, + excludedCompartmentPathways, + }); + + expect(result).toEqual({ + types: ['Type 1', 'Type 2'], + columns: ['Column 1', 'Column 2'], + // eslint-disable-next-line no-magic-numbers + submaps: [1, 2, 3], + annotations: ['Annotation 1', 'Annotation 2'], + includedCompartmentIds: ['Compartment 1', 'Compartment 2'], + excludedCompartmentIds: ['Compartment 3', 'Compartment 4'], + }); + }); +}); diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a262a95703df1efc1e0baba873acf11cc50e13a --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.ts @@ -0,0 +1,35 @@ +import { CheckboxItem } from '../../CheckboxFilter/CheckboxFilter.component'; + +type DownloadBodyRequest = { + types: string[]; + columns: string[]; + submaps: number[]; + annotations: string[]; + includedCompartmentIds: string[]; + excludedCompartmentIds: string[]; +}; + +type GetDownloadBodyRequestProps = { + types: CheckboxItem[]; + columns: CheckboxItem[]; + modelIds: number[]; + annotations: CheckboxItem[]; + includedCompartmentPathways: CheckboxItem[]; + excludedCompartmentPathways: CheckboxItem[]; +}; + +export const getDownloadElementsBodyRequest = ({ + types, + columns, + modelIds, + annotations, + includedCompartmentPathways, + excludedCompartmentPathways, +}: GetDownloadBodyRequestProps): DownloadBodyRequest => ({ + types: types.map(type => type.label), + columns: columns.map(column => column.label), + submaps: modelIds, + annotations: annotations.map(annotation => annotation.label), + includedCompartmentIds: includedCompartmentPathways.map(compartment => compartment.label), + excludedCompartmentIds: excludedCompartmentPathways.map(compartment => compartment.label), +}); diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1aa3d73b227fb3f5ba7ce6a3fd69e70b161ac58e --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.test.ts @@ -0,0 +1,8 @@ +import { getNetworkDownloadBodyRequest } from './getNetworkBodyRequest'; + +describe('getNetworkDownloadBodyRequest', () => { + it('should return an empty object', () => { + const result = getNetworkDownloadBodyRequest(); + expect(result).toEqual({}); + }); +}); diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.ts new file mode 100644 index 0000000000000000000000000000000000000000..6613aea72d35cc71d858350896d3d8ea79121e73 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.ts @@ -0,0 +1 @@ +export const getNetworkDownloadBodyRequest = (): object => ({}); diff --git a/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx index 068348d1f068bbe22bd14e16b430a1948fee3453..1d98f663a79aae7c2dbe4b2e954c58c32536794f 100644 --- a/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx @@ -1,23 +1,36 @@ +import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; +import { useAppSelector } from '@/redux/hooks/useAppSelector'; +import { modelsIdsSelector } from '@/redux/models/models.selectors'; import { DrawerHeading } from '@/shared/DrawerHeading'; -import { useState } from 'react'; +import { getCompartmentPathways } from '@/redux/compartmentPathways/compartmentPathways.thunks'; +import { useEffect, useState } from 'react'; import { TabNavigator } from './TabNavigator'; import { Elements } from './Elements'; import { TAB_NAMES } from './TabNavigator/TabNavigator.constants'; import { TabNames } from './TabNavigator/TabNavigator.types'; +import { Network } from './Network'; export const ExportDrawer = (): React.ReactNode => { + const modelsIds = useAppSelector(modelsIdsSelector); + const dispatch = useAppDispatch(); const [activeTab, setActiveTab] = useState<TabNames>(TAB_NAMES.ELEMENTS); const handleTabChange = (tabName: TabNames): void => { setActiveTab(tabName); }; + useEffect(() => { + dispatch(getCompartmentPathways(modelsIds)); + }, [dispatch, modelsIds]); + return ( <div data-testid="export-drawer" className="h-full max-h-full"> <DrawerHeading title="Export" /> <div className="h-[calc(100%-93px)] max-h-[calc(100%-93px)] overflow-y-auto px-6"> <TabNavigator activeTab={activeTab} onTabChange={handleTabChange} /> {activeTab === TAB_NAMES.ELEMENTS && <Elements />} + {activeTab === TAB_NAMES.NETWORK && <Network />} + {activeTab === TAB_NAMES.GRAPHICS && <div>Graphics</div>} </div> </div> ); diff --git a/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.utils.tsx b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.utils.tsx new file mode 100644 index 0000000000000000000000000000000000000000..20e5e8711bc36f2a2c962bf1a599296c59e6f408 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.utils.tsx @@ -0,0 +1,7 @@ +import { MapModel } from '@/types/models'; + +export const getModelsIds = (models: MapModel[] | undefined): number[] => { + if (!models) return []; + + return models.map(model => model.idObject); +}; diff --git a/src/components/Map/Drawer/ExportDrawer/ExportDrawer.utils.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.utils.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee1aa52f9e3194b17cbdfddc9b963357211afc37 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.utils.test.ts @@ -0,0 +1,16 @@ +import { modelsFixture } from '@/models/fixtures/modelsFixture'; +import { getModelsIds } from './ExportDrawer.component.utils'; + +const MODELS_IDS = modelsFixture.map(item => item.idObject); + +describe('getModelsIds', () => { + it('should return an empty array if models are not provided', () => { + const result = getModelsIds(undefined); + expect(result).toEqual([]); + }); + + it('should return an array of model IDs', () => { + const result = getModelsIds(modelsFixture); + expect(result).toEqual(MODELS_IDS); + }); +}); diff --git a/src/components/Map/Drawer/ExportDrawer/Network/Network.component.tsx b/src/components/Map/Drawer/ExportDrawer/Network/Network.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1438a0851f3581298f226532ff874bf44821a1b6 --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/Network/Network.component.tsx @@ -0,0 +1,16 @@ +import { Export } from '../ExportCompound'; + +export const Network = (): React.ReactNode => { + return ( + <div data-testid="export-tab"> + <Export> + <Export.Types /> + <Export.Columns /> + <Export.Annotations /> + <Export.IncludedCompartmentPathways /> + <Export.ExcludedCompartmentPathways /> + <Export.DownloadElements /> + </Export> + </div> + ); +}; diff --git a/src/components/Map/Drawer/ExportDrawer/Network/index.ts b/src/components/Map/Drawer/ExportDrawer/Network/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d64c4bfc39b924fccc516b5138431f7034a53ba --- /dev/null +++ b/src/components/Map/Drawer/ExportDrawer/Network/index.ts @@ -0,0 +1 @@ +export { Network } from './Network.component'; diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.test.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.test.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a30986f5e018ce2af17e0dfd92dcf99a029c0bad --- /dev/null +++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.test.tsx @@ -0,0 +1,149 @@ +import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; +import { backgroundsFixture } from '@/models/fixtures/backgroundsFixture'; +import { configurationFixture } from '@/models/fixtures/configurationFixture'; +import { modelsFixture } from '@/models/fixtures/modelsFixture'; +import { + CONFIGURATION_FORMATS_MOCK, + CONFIGURATION_FORMATS_TYPES_MOCK, +} from '@/models/mocks/configurationFormatsMock'; +import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; +import { RootState, StoreType } from '@/redux/store'; +import { + InitialStoreState, + getReduxWrapperWithStore, +} from '@/utils/testing/getReduxWrapperWithStore'; +import { act, render, renderHook, screen } from '@testing-library/react'; +import { DownloadSubmap } from './DownloadSubmap.component'; +import { GetSubmapDownloadUrl, useGetSubmapDownloadUrl } from './utils/useGetSubmapDownloadUrl'; + +const VALID_MODEL_ID = 5052; +const VALID_BACKGROUND_ID = 53; +const VALID_MAX_ZOOM = 9; + +const getState = (): RootState => ({ + ...INITIAL_STORE_STATE_MOCK, + map: { + ...INITIAL_STORE_STATE_MOCK.map, + data: { + ...INITIAL_STORE_STATE_MOCK.map.data, + modelId: VALID_MODEL_ID, + backgroundId: VALID_BACKGROUND_ID, + size: { + ...INITIAL_STORE_STATE_MOCK.map.data.size, + maxZoom: VALID_MAX_ZOOM, + }, + }, + }, + models: { + ...INITIAL_STORE_STATE_MOCK.models, + data: [ + { + ...modelsFixture[FIRST_ARRAY_ELEMENT], + idObject: VALID_MODEL_ID, + }, + ], + }, + backgrounds: { + ...INITIAL_STORE_STATE_MOCK.backgrounds, + data: [ + { + ...backgroundsFixture[FIRST_ARRAY_ELEMENT], + id: VALID_BACKGROUND_ID, + }, + ], + }, + configuration: { + ...INITIAL_STORE_STATE_MOCK.configuration, + main: { + ...INITIAL_STORE_STATE_MOCK.configuration.main, + data: { + ...configurationFixture, + modelFormats: CONFIGURATION_FORMATS_MOCK, + }, + }, + }, +}); + +const toggleListByButtonClick = (): void => { + const button = screen.getByTestId('download-submap-button'); + act(() => { + button.click(); + }); +}; + +const getUtilGetSubmapDownloadUrl = (): GetSubmapDownloadUrl => { + const { Wrapper } = getReduxWrapperWithStore(getState()); + + const { + result: { current: getSubmapDownloadUrl }, + } = renderHook(() => useGetSubmapDownloadUrl(), { wrapper: Wrapper }); + + return getSubmapDownloadUrl; +}; + +const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { + const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState); + + return ( + render( + <Wrapper> + <DownloadSubmap /> + </Wrapper>, + ), + { + store, + } + ); +}; + +describe('DownloadSubmap - component', () => { + it('should render download button', () => { + renderComponent(getState()); + const button = screen.getByTestId('download-submap-button'); + expect(button).toBeInTheDocument(); + }); + + it('should open list on button click', () => { + renderComponent(getState()); + toggleListByButtonClick(); + + const list = screen.getByTestId('download-submap-list'); + expect(list).not.toHaveClass('hidden'); + }); + + it('should close list on button click twice', () => { + renderComponent(getState()); + const list = screen.getByTestId('download-submap-list'); + + // list should be opened + toggleListByButtonClick(); + expect(list).not.toHaveClass('hidden'); + + // list should be closed + toggleListByButtonClick(); + expect(list).toHaveClass('hidden'); + }); + + it('should not show list when closed (default state)', () => { + renderComponent(getState()); + const list = screen.getByTestId('download-submap-list'); + expect(list).toHaveClass('hidden'); + }); + + it('should render list elements with href and names when opened', () => { + const getSubmapDownloadUrl = getUtilGetSubmapDownloadUrl(); + renderComponent(getState()); + const list = screen.getByTestId('download-submap-list'); + + const validHrefs = CONFIGURATION_FORMATS_MOCK.map(({ handler }) => + getSubmapDownloadUrl({ handler }), + ); + const validNames = CONFIGURATION_FORMATS_TYPES_MOCK; + const allAnchors = [...list.getElementsByTagName('a')]; + + allAnchors.forEach(anchor => { + expect(validHrefs.includes(anchor.href)).toBeTruthy(); + expect(validNames.includes(anchor.innerText)).toBeTruthy(); + }); + }); +}); diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..01587d62f8bbd459f9aff42cd0f7502c1051ec8a --- /dev/null +++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx @@ -0,0 +1,50 @@ +import { formatsHandlersSelector } from '@/redux/configuration/configuration.selectors'; +import { Button } from '@/shared/Button'; +import { useSelect } from 'downshift'; +import { useSelector } from 'react-redux'; +import { SUBMAP_DOWNLOAD_HANDLERS_NAMES } from './DownloadSubmap.constants'; +import { useGetSubmapDownloadUrl } from './utils/useGetSubmapDownloadUrl'; + +export const DownloadSubmap = (): JSX.Element => { + const formatsHandlers = useSelector(formatsHandlersSelector); + const formatsHandlersItems = Object.entries(formatsHandlers); + const getSubmapDownloadUrl = useGetSubmapDownloadUrl(); + + const { isOpen, getToggleButtonProps, getMenuProps } = useSelect({ + items: formatsHandlersItems, + }); + + return ( + <div className="relative"> + <Button + data-testid="download-submap-button" + variantStyles="ghost" + className="mr-4" + {...getToggleButtonProps()} + > + Download + </Button> + <ul + data-testid="download-submap-list" + className={`absolute left-[-50%] z-10 max-h-80 w-48 overflow-scroll rounded-sm border bg-white p-0 ps-0 ${ + !isOpen && 'hidden' + }`} + {...getMenuProps()} + > + {isOpen && + formatsHandlersItems.map(([formatId, handler]) => ( + <li key={formatId}> + <a + className="flex flex-col border-t px-4 py-2 shadow-sm" + href={getSubmapDownloadUrl({ handler })} + target="_blank" + download + > + <span>{SUBMAP_DOWNLOAD_HANDLERS_NAMES[formatId]}</span> + </a> + </li> + ))} + </ul> + </div> + ); +}; diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.constants.ts b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.constants.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bd478cc6117c4170772519a99f7e0ffe29e74ce --- /dev/null +++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.constants.ts @@ -0,0 +1,13 @@ +import { + CELL_DESIGNER_SBML_HANDLER_NAME_ID, + GPML_HANDLER_NAME_ID, + SBGN_ML_HANDLER_NAME_ID, + SBML_HANDLER_NAME_ID, +} from '@/redux/configuration/configuration.constants'; + +export const SUBMAP_DOWNLOAD_HANDLERS_NAMES: Record<string, string> = { + [GPML_HANDLER_NAME_ID]: 'GPML', + [SBML_HANDLER_NAME_ID]: 'SBML', + [CELL_DESIGNER_SBML_HANDLER_NAME_ID]: 'CellDesigner SBML', + [SBGN_ML_HANDLER_NAME_ID]: 'SBGN-ML', +}; diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/index.ts b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..96d65c330502b30451ab503c4fa00e0a409887fa --- /dev/null +++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/index.ts @@ -0,0 +1 @@ +export { DownloadSubmap } from './DownloadSubmap.component'; diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.test.ts b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8f335bff701d4fdeef65f9f815dcfe6dbc1fab2 --- /dev/null +++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.test.ts @@ -0,0 +1,117 @@ +import { BASE_API_URL, PROJECT_ID } from '@/constants'; +import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; +import { backgroundsFixture } from '@/models/fixtures/backgroundsFixture'; +import { modelsFixture } from '@/models/fixtures/modelsFixture'; +import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; +import { RootState } from '@/redux/store'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { renderHook } from '@testing-library/react'; +import { useGetSubmapDownloadUrl } from './useGetSubmapDownloadUrl'; + +const VALID_HANDLER = 'lcsb.mapviewer.wikipathway.GpmlParser'; +const VALID_MODEL_ID = 5052; +const VALID_BACKGROUND_ID = 53; +const VALID_MAX_ZOOM = 9; + +const getState = ({ + modelId, + backgroundId, + mapSizeMaxZoom, +}: { + modelId: number; + backgroundId: number; + mapSizeMaxZoom: number; +}): RootState => ({ + ...INITIAL_STORE_STATE_MOCK, + map: { + ...INITIAL_STORE_STATE_MOCK.map, + data: { + ...INITIAL_STORE_STATE_MOCK.map.data, + modelId, + backgroundId, + size: { + ...INITIAL_STORE_STATE_MOCK.map.data.size, + maxZoom: mapSizeMaxZoom, + }, + }, + }, + models: { + ...INITIAL_STORE_STATE_MOCK.models, + data: [ + { + ...modelsFixture[FIRST_ARRAY_ELEMENT], + idObject: VALID_MODEL_ID, + }, + ], + }, + backgrounds: { + ...INITIAL_STORE_STATE_MOCK.backgrounds, + data: [ + { + ...backgroundsFixture[FIRST_ARRAY_ELEMENT], + id: VALID_BACKGROUND_ID, + }, + ], + }, +}); + +describe('useGetSubmapDownloadUrl - hook', () => { + describe('when not all params valid', () => { + const cases = [ + { + modelId: 0, + backgroundId: VALID_BACKGROUND_ID, + mapSizeMaxZoom: VALID_MAX_ZOOM, + handler: VALID_HANDLER, + }, + { + modelId: VALID_MODEL_ID, + backgroundId: 0, + mapSizeMaxZoom: VALID_MAX_ZOOM, + handler: VALID_HANDLER, + }, + { + modelId: VALID_MODEL_ID, + backgroundId: VALID_BACKGROUND_ID, + mapSizeMaxZoom: 0, + handler: VALID_HANDLER, + }, + { + modelId: VALID_MODEL_ID, + backgroundId: VALID_BACKGROUND_ID, + mapSizeMaxZoom: VALID_MAX_ZOOM, + handler: '', + }, + ]; + + it.each(cases)('should return empty string', ({ handler, ...stateParams }) => { + const { Wrapper } = getReduxWrapperWithStore(getState(stateParams)); + + const { + result: { current: getSubmapDownloadUrl }, + } = renderHook(() => useGetSubmapDownloadUrl(), { wrapper: Wrapper }); + + expect(getSubmapDownloadUrl({ handler })).toBe(''); + }); + }); + + describe('when all params valid', () => { + it('should return valid string', () => { + const { Wrapper } = getReduxWrapperWithStore( + getState({ + modelId: VALID_MODEL_ID, + backgroundId: VALID_BACKGROUND_ID, + mapSizeMaxZoom: VALID_MAX_ZOOM, + }), + ); + + const { + result: { current: getSubmapDownloadUrl }, + } = renderHook(() => useGetSubmapDownloadUrl(), { wrapper: Wrapper }); + + expect(getSubmapDownloadUrl({ handler: VALID_HANDLER })).toBe( + `${BASE_API_URL}/projects/${PROJECT_ID}/models/5052:downloadModel?backgroundOverlayId=53&handlerClass=lcsb.mapviewer.wikipathway.GpmlParser&zoomLevel=9`, + ); + }); + }); +}); diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.ts b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.ts new file mode 100644 index 0000000000000000000000000000000000000000..e003af360c856d2e254ea8f0a1252391c7e6610d --- /dev/null +++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.ts @@ -0,0 +1,27 @@ +import { BASE_API_URL, PROJECT_ID } from '@/constants'; +import { currentBackgroundSelector } from '@/redux/backgrounds/background.selectors'; +import { mapDataSizeSelector } from '@/redux/map/map.selectors'; +import { currentModelSelector } from '@/redux/models/models.selectors'; +import { useSelector } from 'react-redux'; + +export type GetSubmapDownloadUrl = ({ handler }: { handler: string }) => string; + +export const useGetSubmapDownloadUrl = (): GetSubmapDownloadUrl => { + const model = useSelector(currentModelSelector); + const background = useSelector(currentBackgroundSelector); + const mapSize = useSelector(mapDataSizeSelector); + + const getSubmapDownloadUrl: GetSubmapDownloadUrl = ({ handler }) => { + const allParamsValid = [model?.idObject, background?.id, mapSize.maxZoom, handler].reduce( + (a, b) => Boolean(a) && Boolean(b), + true, + ); + if (!allParamsValid) { + return ''; + } + + return `${BASE_API_URL}/projects/${PROJECT_ID}/models/${model?.idObject}:downloadModel?backgroundOverlayId=${background?.id}&handlerClass=${handler}&zoomLevel=${mapSize.maxZoom}`; + }; + + return getSubmapDownloadUrl; +}; diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx index e056671a444f93c2d528489ab00c9b5074e8a214..a7a38dfae9cb989d98e2bbb2e8be273f4b8cf0aa 100644 --- a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx +++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx @@ -1,5 +1,5 @@ -import { Button } from '@/shared/Button'; import { IconButton } from '@/shared/IconButton'; +import { DownloadSubmap } from './DownloadSubmap'; interface SubmapItemProps { modelName: string; @@ -10,9 +10,7 @@ export const SubmpamItem = ({ modelName, onOpenClick }: SubmapItemProps): JSX.El <div className="flex flex-row flex-nowrap items-center justify-between border-b py-6"> {modelName} <div className="flex flex-row flex-nowrap items-center"> - <Button variantStyles="ghost" className="mr-4"> - Download - </Button> + <DownloadSubmap /> <IconButton icon="chevron-right" className="h-6 w-6 bg-white-pearl" diff --git a/src/components/Map/Map.component.tsx b/src/components/Map/Map.component.tsx index ea5a18e2ef3a95b5001d4873022ee8c220ae829f..36ac1a1f14fe6f6f65ec250f55ee29c396c69128 100644 --- a/src/components/Map/Map.component.tsx +++ b/src/components/Map/Map.component.tsx @@ -1,5 +1,6 @@ import { Drawer } from '@/components/Map/Drawer'; import { Legend } from '@/components/Map/Legend'; +import { MapAdditionalActions } from './MapAdditionalActions'; import { MapAdditionalOptions } from './MapAdditionalOptions'; import { MapViewer } from './MapViewer/MapViewer.component'; @@ -12,5 +13,6 @@ export const Map = (): JSX.Element => ( <Drawer /> <MapViewer /> <Legend /> + <MapAdditionalActions /> </div> ); 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..f65f5b605510ad4afb566e763c886fddbc9b1225 --- /dev/null +++ b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.test.tsx @@ -0,0 +1,159 @@ +/* eslint-disable no-magic-numbers */ +import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; +import { MAP_DATA_INITIAL_STATE } from '@/redux/map/map.constants'; +import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; +import { AppDispatch, RootState, StoreType } from '@/redux/store'; +import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; +import { + InitialStoreState, + getReduxWrapperWithStore, +} from '@/utils/testing/getReduxWrapperWithStore'; +import { act, render, screen } from '@testing-library/react'; +import Map from 'ol/Map'; +import { MockStoreEnhanced } from 'redux-mock-store'; +import { MapAdditionalActions } from './MapAdditionalActions.component'; +import { useVisibleBioEntitiesPolygonCoordinates } from './utils/useVisibleBioEntitiesPolygonCoordinates'; + +const setBounds = jest.fn(); + +jest.mock('../../../utils/map/useSetBounds', () => ({ + _esModule: true, + useSetBounds: (): jest.Mock => setBounds, +})); + +jest.mock('./utils/useVisibleBioEntitiesPolygonCoordinates', () => ({ + _esModule: true, + useVisibleBioEntitiesPolygonCoordinates: jest.fn(), +})); + +const useVisibleBioEntitiesPolygonCoordinatesMock = + useVisibleBioEntitiesPolygonCoordinates as jest.Mock; + +setBounds.mockImplementation(() => {}); + +const renderComponent = ( + initialStore?: InitialStoreState, +): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => { + const { Wrapper, store } = getReduxStoreWithActionsListener(initialStore); + return ( + render( + <Wrapper> + <MapAdditionalActions /> + </Wrapper>, + ), + { + store, + } + ); +}; + +const renderComponentWithMapInstance = (initialStore?: InitialStoreState): { store: StoreType } => { + const dummyElement = document.createElement('div'); + const mapInstance = new Map({ target: dummyElement }); + + const { Wrapper, store } = getReduxWrapperWithStore(initialStore, { + mapInstanceContextValue: { + mapInstance, + setMapInstance: () => {}, + }, + }); + + return ( + render( + <Wrapper> + <MapAdditionalActions /> + </Wrapper>, + ), + { + store, + } + ); +}; + +describe('MapAdditionalActions - component', () => { + describe('when always', () => { + beforeEach(() => { + renderComponent(INITIAL_STORE_STATE_MOCK); + }); + + it('should render zoom in button', () => { + const button = screen.getByTestId('zoom-in-button'); + expect(button).toBeInTheDocument(); + }); + + it('should render zoom out button', () => { + const button = screen.getByTestId('zoom-out-button'); + expect(button).toBeInTheDocument(); + }); + + it('should render location button', () => { + const button = screen.getByTestId('location-button'); + expect(button).toBeInTheDocument(); + }); + }); + + describe('when clicked on zoom in button', () => { + it('should dispatch varyPositionZoom action with valid delta', () => { + const { store } = renderComponent(INITIAL_STORE_STATE_MOCK); + const button = screen.getByTestId('zoom-in-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(INITIAL_STORE_STATE_MOCK); + const button = screen.getByTestId('zoom-out-button'); + button!.click(); + + const actions = store.getActions(); + expect(actions[FIRST_ARRAY_ELEMENT]).toStrictEqual({ + payload: { delta: -1 }, + type: 'map/varyPositionZoom', + }); + }); + }); + + describe('when clicked on location button', () => { + it('setBounds should be called', () => { + useVisibleBioEntitiesPolygonCoordinatesMock.mockImplementation(() => [ + [128, 128], + [192, 192], + ]); + + renderComponentWithMapInstance({ + map: { + data: { + ...MAP_DATA_INITIAL_STATE, + size: { + width: 256, + height: 256, + tileSize: 256, + minZoom: 1, + maxZoom: 1, + }, + }, + loading: 'idle', + error: { + name: '', + message: '', + }, + openedMaps: [], + }, + }); + + const button = screen.getByTestId('location-button'); + act(() => { + button!.click(); + }); + + expect(setBounds).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c0b7368f0b9ab106806ac58284a9e0a87f6f669d --- /dev/null +++ b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx @@ -0,0 +1,44 @@ +import { Icon } from '@/shared/Icon'; +import { twMerge } from 'tailwind-merge'; +import { useAddtionalActions } from './utils/useAdditionalActions'; + +export const MapAdditionalActions = (): JSX.Element => { + const { zoomIn, zoomOut, zoomInToBioEntities } = useAddtionalActions(); + + return ( + <div + className={twMerge( + 'absolute bottom-6 right-6 z-10 flex flex-col gap-4', + 'drop-shadow-primary', + )} + > + <button + type="button" + className="flex h-12 w-12 items-center justify-center rounded-full bg-white" + onClick={zoomInToBioEntities} + data-testid="location-button" + > + <Icon className="h-[28px] w-[28px]" name="location" /> + </button> + <div className="flex h-auto w-12 flex-col items-center justify-center rounded-full bg-white py-2"> + <button + type="button" + className="flex h-12 w-12 items-center justify-center" + onClick={zoomIn} + data-testid="zoom-in-button" + > + <Icon className="h-[24px] w-[24px]" name="magnifier-zoom-in" /> + </button> + <div className="h-px w-12 bg-[#F1F1F1]" /> + <button + type="button" + className="flex h-12 w-12 items-center justify-center" + onClick={zoomOut} + data-testid="zoom-out-button" + > + <Icon className="h-[24px] w-[24px]" name="magnifier-zoom-out" /> + </button> + </div> + </div> + ); +}; diff --git a/src/components/Map/MapAdditionalActions/MappAdditionalActions.constants.ts b/src/components/Map/MapAdditionalActions/MappAdditionalActions.constants.ts new file mode 100644 index 0000000000000000000000000000000000000000..0803794471425c623acb0dd038ef4f4389e83898 --- /dev/null +++ b/src/components/Map/MapAdditionalActions/MappAdditionalActions.constants.ts @@ -0,0 +1,3 @@ +export const MAP_ZOOM_IN_DELTA = 1; + +export const MAP_ZOOM_OUT_DELTA = -1; diff --git a/src/components/Map/MapAdditionalActions/index.ts b/src/components/Map/MapAdditionalActions/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..1b2260185302e8c2d4376e0390693594ffd951b0 --- /dev/null +++ b/src/components/Map/MapAdditionalActions/index.ts @@ -0,0 +1 @@ +export { MapAdditionalActions } from './MapAdditionalActions.component'; 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..7d296729a6fde1d04dec7fa42f3b4f8a313b54a7 --- /dev/null +++ b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts @@ -0,0 +1,139 @@ +/* eslint-disable no-magic-numbers */ +import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; +import { MAP_DATA_INITIAL_STATE } from '@/redux/map/map.constants'; +import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; +import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { renderHook } from '@testing-library/react'; +import Map from 'ol/Map'; +import { useAddtionalActions } from './useAdditionalActions'; +import { useVisibleBioEntitiesPolygonCoordinates } from './useVisibleBioEntitiesPolygonCoordinates'; + +jest.mock('./useVisibleBioEntitiesPolygonCoordinates', () => ({ + _esModule: true, + useVisibleBioEntitiesPolygonCoordinates: jest.fn(), +})); + +const useVisibleBioEntitiesPolygonCoordinatesMock = + useVisibleBioEntitiesPolygonCoordinates as jest.Mock; + +describe('useAddtionalActions - hook', () => { + describe('on zoomIn', () => { + it('should dispatch varyPositionZoom action with valid delta', () => { + const { Wrapper, store } = getReduxStoreWithActionsListener(INITIAL_STORE_STATE_MOCK); + 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(INITIAL_STORE_STATE_MOCK); + 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', () => { + describe('when there are valid polygon coordinates', () => { + beforeEach(() => { + useVisibleBioEntitiesPolygonCoordinatesMock.mockImplementation(() => [ + [128, 128], + [192, 192], + ]); + }); + + it('should return valid results', () => { + const dummyElement = document.createElement('div'); + const mapInstance = new Map({ target: dummyElement }); + + const { Wrapper } = getReduxWrapperWithStore( + { + map: { + data: { + ...MAP_DATA_INITIAL_STATE, + size: { + width: 256, + height: 256, + tileSize: 256, + minZoom: 1, + maxZoom: 1, + }, + }, + loading: 'idle', + error: { + name: '', + message: '', + }, + openedMaps: [], + }, + }, + { + mapInstanceContextValue: { + mapInstance, + setMapInstance: () => {}, + }, + }, + ); + const { + result: { + current: { zoomInToBioEntities }, + }, + } = renderHook(() => useAddtionalActions(), { + wrapper: Wrapper, + }); + + expect(zoomInToBioEntities()).toStrictEqual({ + extent: [128, 128, 192, 192], + options: { maxZoom: 1, padding: [128, 128, 128, 128], size: undefined }, + // size is real size on the screen, so it'll be undefined in the jest + }); + }); + }); + + describe('when there are no polygon coordinates', () => { + beforeEach(() => { + useVisibleBioEntitiesPolygonCoordinatesMock.mockImplementation(() => undefined); + }); + + it('should return undefined', () => { + const { Wrapper } = getReduxStoreWithActionsListener(INITIAL_STORE_STATE_MOCK); + const { + result: { + current: { zoomInToBioEntities }, + }, + } = renderHook(() => useAddtionalActions(), { + wrapper: Wrapper, + }); + + expect(zoomInToBioEntities()).toBeUndefined(); + }); + }); + }); +}); diff --git a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts new file mode 100644 index 0000000000000000000000000000000000000000..b93fc761920b36c99d3a51426a9bbed0f25f6512 --- /dev/null +++ b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts @@ -0,0 +1,39 @@ +import { varyPositionZoom } from '@/redux/map/map.slice'; +import { SetBoundsResult, useSetBounds } from '@/utils/map/useSetBounds'; +import { useCallback } from 'react'; +import { useDispatch } from 'react-redux'; +import { MAP_ZOOM_IN_DELTA, MAP_ZOOM_OUT_DELTA } from '../MappAdditionalActions.constants'; +import { useVisibleBioEntitiesPolygonCoordinates } from './useVisibleBioEntitiesPolygonCoordinates'; + +interface UseAddtionalActionsResult { + zoomIn(): void; + zoomOut(): void; + zoomInToBioEntities(): void; +} + +export const useAddtionalActions = (): UseAddtionalActionsResult => { + const dispatch = useDispatch(); + const setBounds = useSetBounds(); + const polygonCoordinates = useVisibleBioEntitiesPolygonCoordinates(); + + const zoomInToBioEntities = (): SetBoundsResult | undefined => { + if (!polygonCoordinates) { + return undefined; + } + + return setBounds(polygonCoordinates); + }; + + const varyZoomByDelta = useCallback( + (delta: number) => { + dispatch(varyPositionZoom({ delta })); + }, + [dispatch], + ); + + return { + zoomIn: () => varyZoomByDelta(MAP_ZOOM_IN_DELTA), + zoomOut: () => varyZoomByDelta(MAP_ZOOM_OUT_DELTA), + zoomInToBioEntities, + }; +}; diff --git a/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.test.ts b/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8f84e5d6f681e7d13ea4f2e0ecd3f5326fd4b665 --- /dev/null +++ b/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.test.ts @@ -0,0 +1,221 @@ +import { drugsFixture } from '@/models/fixtures/drugFixtures'; +/* eslint-disable no-magic-numbers */ +import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; +import { chemicalsFixture } from '@/models/fixtures/chemicalsFixture'; +import { modelsFixture } from '@/models/fixtures/modelsFixture'; +import { BIOENTITY_INITIAL_STATE_MOCK } from '@/redux/bioEntity/bioEntity.mock'; +import { DRAWER_INITIAL_STATE } from '@/redux/drawer/drawer.constants'; +import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; +import { RootState } from '@/redux/store'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { renderHook } from '@testing-library/react'; +import { CHEMICALS_INITIAL_STATE_MOCK } from '../../../../redux/chemicals/chemicals.mock'; +import { DRUGS_INITIAL_STATE_MOCK } from '../../../../redux/drugs/drugs.mock'; +import { DEFAULT_POSITION, MAIN_MAP, MAP_INITIAL_STATE } from '../../../../redux/map/map.constants'; +import { MODELS_INITIAL_STATE_MOCK } from '../../../../redux/models/models.mock'; +import { useVisibleBioEntitiesPolygonCoordinates } from './useVisibleBioEntitiesPolygonCoordinates'; + +/* key elements of the state: + - this state simulates situation where there is: + -- one searched element + -- of currently selected map + -- for each content/chemicals/drugs data set + + - the key differences in this states are x/y/z coordinates of element's bioEntities +*/ + +const getInitalState = ( + { hideElements }: { hideElements: boolean } = { hideElements: false }, +): RootState => { + const elementsLimit = hideElements ? 0 : 1; + + return { + ...INITIAL_STORE_STATE_MOCK, + drawer: { + ...DRAWER_INITIAL_STATE, + searchDrawerState: { + ...DRAWER_INITIAL_STATE.searchDrawerState, + selectedSearchElement: 'search', + }, + }, + models: { + ...MODELS_INITIAL_STATE_MOCK, + data: [ + { + ...modelsFixture[0], + idObject: 5052, + }, + ], + }, + map: { + ...MAP_INITIAL_STATE, + data: { + ...MAP_INITIAL_STATE.data, + modelId: 5052, + size: { + width: 256, + height: 256, + tileSize: 256, + minZoom: 1, + maxZoom: 1, + }, + }, + openedMaps: [{ modelId: 5052, modelName: MAIN_MAP, lastPosition: DEFAULT_POSITION }], + }, + bioEntity: { + ...BIOENTITY_INITIAL_STATE_MOCK, + data: [ + { + searchQueryElement: 'search', + data: [ + { + ...bioEntityContentFixture, + bioEntity: { + ...bioEntityContentFixture.bioEntity, + model: 5052, + x: 16, + y: 16, + z: 1, + }, + }, + ].slice(0, elementsLimit), + loading: 'succeeded', + error: { message: '', name: '' }, + }, + ], + }, + chemicals: { + ...CHEMICALS_INITIAL_STATE_MOCK, + data: [ + { + searchQueryElement: 'search', + data: [ + { + ...chemicalsFixture[0], + targets: [ + { + ...chemicalsFixture[0].targets[0], + targetElements: [ + { + ...chemicalsFixture[0].targets[0].targetElements[0], + model: 5052, + x: 32, + y: 32, + z: 1, + }, + ], + }, + ], + }, + ].slice(0, elementsLimit), + loading: 'succeeded', + error: { message: '', name: '' }, + }, + { + searchQueryElement: 'not-search', + data: [ + { + ...chemicalsFixture[0], + targets: [ + { + ...chemicalsFixture[0].targets[0], + targetElements: [ + { + ...chemicalsFixture[0].targets[0].targetElements[0], + model: 5052, + x: 8, + y: 2, + z: 9, + }, + ], + }, + ], + }, + ].slice(0, elementsLimit), + loading: 'succeeded', + error: { message: '', name: '' }, + }, + ], + }, + drugs: { + ...DRUGS_INITIAL_STATE_MOCK, + data: [ + { + searchQueryElement: 'search', + data: [ + { + ...drugsFixture[0], + targets: [ + { + ...drugsFixture[0].targets[0], + targetElements: [ + { + ...drugsFixture[0].targets[0].targetElements[0], + model: 5052, + x: 128, + y: 128, + z: 1, + }, + ], + }, + ], + }, + ].slice(0, elementsLimit), + loading: 'succeeded', + error: { message: '', name: '' }, + }, + { + searchQueryElement: 'not-search', + data: [ + { + ...drugsFixture[0], + targets: [ + { + ...drugsFixture[0].targets[0], + targetElements: [ + { + ...drugsFixture[0].targets[0].targetElements[0], + model: 5052, + x: 100, + y: 50, + z: 4, + }, + ], + }, + ], + }, + ].slice(0, elementsLimit), + loading: 'succeeded', + error: { message: '', name: '' }, + }, + ], + }, + }; +}; + +describe('useVisibleBioEntitiesPolygonCoordinates - hook', () => { + describe('when allVisibleBioEntities is empty', () => { + const { Wrapper } = getReduxWrapperWithStore(getInitalState({ hideElements: true })); + const { result } = renderHook(() => useVisibleBioEntitiesPolygonCoordinates(), { + wrapper: Wrapper, + }); + + it('should return undefined', () => { + expect(result.current).toBe(undefined); + }); + }); + + describe('when allVisibleBioEntities has data', () => { + const { Wrapper } = getReduxWrapperWithStore(getInitalState()); + const { result } = renderHook(() => useVisibleBioEntitiesPolygonCoordinates(), { + wrapper: Wrapper, + }); + + it('should return undefined', () => { + expect(result.current).toStrictEqual([ + [-17532820, -0], + [0, 17532820], + ]); + }); + }); +}); diff --git a/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.ts b/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.ts new file mode 100644 index 0000000000000000000000000000000000000000..4fbcd551ac4a6e2856951352d999529494446903 --- /dev/null +++ b/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.ts @@ -0,0 +1,49 @@ +import { allVisibleBioEntitiesSelector } from '@/redux/bioEntity/bioEntity.selectors'; +import { Point } from '@/types/map'; +import { usePointToProjection } from '@/utils/map/usePointToProjection'; +import { isPointValid } from '@/utils/point/isPointValid'; +import { Coordinate } from 'ol/coordinate'; +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; + +const VALID_POLYGON_COORDINATES_LENGTH = 2; + +export const useVisibleBioEntitiesPolygonCoordinates = (): Coordinate[] | undefined => { + const allVisibleBioEntities = useSelector(allVisibleBioEntitiesSelector); + const pointToProjection = usePointToProjection(); + + const polygonPoints = useMemo((): Point[] => { + const allX = allVisibleBioEntities.map(({ x }) => x); + const allY = allVisibleBioEntities.map(({ y }) => y); + + const minX = Math.min(...allX); + const maxX = Math.max(...allX); + + const minY = Math.min(...allY); + const maxY = Math.max(...allY); + + const points = [ + { + x: minX, + y: maxY, + }, + { + x: maxX, + y: minY, + }, + ]; + + return points.filter(isPointValid); + }, [allVisibleBioEntities]); + + const polygonCoordinates = useMemo( + () => polygonPoints.map(point => pointToProjection(point)), + [polygonPoints, pointToProjection], + ); + + if (polygonCoordinates.length !== VALID_POLYGON_COORDINATES_LENGTH) { + return undefined; + } + + return polygonCoordinates; +}; diff --git a/src/components/Map/MapViewer/MapViewer.types.ts b/src/components/Map/MapViewer/MapViewer.types.ts index 2cc15d5da01ea0a5ab0cec43e9f0abacc762f790..f6750e5cb1b7db0b38c29ba97fc7ca3c5cbd7b26 100644 --- a/src/components/Map/MapViewer/MapViewer.types.ts +++ b/src/components/Map/MapViewer/MapViewer.types.ts @@ -1,9 +1,6 @@ -import Map from 'ol/Map'; import View from 'ol/View'; import BaseLayer from 'ol/layer/Base'; -export type MapInstance = Map | undefined; - export type MapConfig = { view: View; layers: BaseLayer[]; diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getColorByAvailableProperties.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getColorByAvailableProperties.test.ts deleted file mode 100644 index 6b71e37ee7f09fe9fb74e4aab6a6e9bc7bf420a0..0000000000000000000000000000000000000000 --- a/src/components/Map/MapViewer/utils/config/overlaysLayer/getColorByAvailableProperties.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { OverlayBioEntityRender } from '@/types/OLrendering'; -import { getColorByAvailableProperties } from './getColorByAvailableProperties'; - -describe('getColorByAvailableProperties', () => { - const ENTITY: OverlayBioEntityRender = { - id: 0, - modelId: 0, - x1: 0, - y1: 0, - x2: 0, - y2: 0, - width: 0, - height: 0, - value: null, - overlayId: 0, - color: null, - }; - - const getHexTricolorGradientColorWithAlpha = jest.fn().mockReturnValue('#FFFFFF'); - const defaultColor = '#000000'; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should return the result of getHexTricolorGradientColorWithAlpha if entity has a value equal to 0', () => { - const entity = { ...ENTITY, value: 0 }; - const result = getColorByAvailableProperties( - entity, - getHexTricolorGradientColorWithAlpha, - defaultColor, - ); - - expect(result).toEqual('#FFFFFF'); - expect(getHexTricolorGradientColorWithAlpha).toHaveBeenCalledWith(entity.value); - }); - - it('should return the result of getHexTricolorGradientColorWithAlpha if entity has a value', () => { - const entity = { ...ENTITY, value: -0.2137 }; - const result = getColorByAvailableProperties( - entity, - getHexTricolorGradientColorWithAlpha, - defaultColor, - ); - - expect(result).toEqual('#FFFFFF'); - expect(getHexTricolorGradientColorWithAlpha).toHaveBeenCalledWith(entity.value); - }); - - it('should return the result of convertDecimalToHex if entity has a color', () => { - const entity = { ...ENTITY, color: { rgb: -65536, alpha: 0 } }; // red color - - const result = getColorByAvailableProperties( - entity, - getHexTricolorGradientColorWithAlpha, - defaultColor, - ); - - expect(result).toEqual('#ff0000'); - expect(getHexTricolorGradientColorWithAlpha).not.toHaveBeenCalled(); - }); - - it('should return the default color if entity has neither a value nor a color', () => { - const result = getColorByAvailableProperties( - ENTITY, - getHexTricolorGradientColorWithAlpha, - defaultColor, - ); - - expect(result).toEqual('#000000'); - expect(getHexTricolorGradientColorWithAlpha).not.toHaveBeenCalled(); - }); -}); diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getColorByAvailableProperties.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getColorByAvailableProperties.ts deleted file mode 100644 index 6cbc988306822a2bcd1bd2a4cc1aabbc7d24b4f4..0000000000000000000000000000000000000000 --- a/src/components/Map/MapViewer/utils/config/overlaysLayer/getColorByAvailableProperties.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ZERO } from '@/constants/common'; -import type { GetHex3ColorGradientColorWithAlpha } from '@/hooks/useTriColorLerp'; -import { OverlayBioEntityRender } from '@/types/OLrendering'; -import { convertDecimalToHexColor } from '@/utils/convert/convertDecimalToHex'; - -export const getColorByAvailableProperties = ( - entity: OverlayBioEntityRender, - getHexTricolorGradientColorWithAlpha: GetHex3ColorGradientColorWithAlpha, - defaultColor: string, -): string => { - if (typeof entity.value === 'number') { - return getHexTricolorGradientColorWithAlpha(entity.value || ZERO); - } - if (entity.color) { - return convertDecimalToHexColor(entity.color.rgb); - } - return defaultColor; -}; diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayFeatures.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayFeatures.ts deleted file mode 100644 index 45723ea8732116db8d006f6ad510d4c5f36f5646..0000000000000000000000000000000000000000 --- a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayFeatures.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { GetHex3ColorGradientColorWithAlpha } from '@/hooks/useTriColorLerp'; -import { OverlayBioEntityRender } from '@/types/OLrendering'; -import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; -import type Feature from 'ol/Feature'; -import type Polygon from 'ol/geom/Polygon'; -import { OverlayOrder } from '@/redux/overlayBioEntity/overlayBioEntity.utils'; -import { ZERO } from '@/constants/common'; -import { createOverlayGeometryFeature } from './createOverlayGeometryFeature'; -import { getColorByAvailableProperties } from './getColorByAvailableProperties'; -import { getPolygonLatitudeCoordinates } from './getPolygonLatitudeCoordinates'; - -type GetOverlayFeaturesProps = { - bioEntities: OverlayBioEntityRender[]; - pointToProjection: UsePointToProjectionResult; - getHex3ColorGradientColorWithAlpha: GetHex3ColorGradientColorWithAlpha; - defaultColor: string; - overlaysOrder: OverlayOrder[]; -}; - -export const getOverlayFeatures = ({ - bioEntities, - pointToProjection, - getHex3ColorGradientColorWithAlpha, - defaultColor, - overlaysOrder, -}: GetOverlayFeaturesProps): Feature<Polygon>[] => - bioEntities.map(entity => { - /** - * Depending on number of active overlays - * it's required to calculate xMin and xMax coordinates of the polygon - * so "entity" might be devided equali between active overlays - */ - const { xMin, xMax } = getPolygonLatitudeCoordinates({ - width: entity.width, - nOverlays: overlaysOrder.length, - xMin: entity.x1, - overlayIndexBasedOnOrder: - overlaysOrder.find(({ id }) => id === entity.overlayId)?.index || ZERO, - }); - - return createOverlayGeometryFeature( - [ - ...pointToProjection({ x: xMin, y: entity.y1 }), - ...pointToProjection({ x: xMax, y: entity.y2 }), - ], - getColorByAvailableProperties(entity, getHex3ColorGradientColorWithAlpha, defaultColor), - ); - }); diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b580a998904b2975b82c0a527aa805c748c38288 --- /dev/null +++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts @@ -0,0 +1,62 @@ +import { renderHook } from '@testing-library/react'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { CONFIGURATION_INITIAL_STORE_MOCKS } from '@/redux/configuration/configuration.mock'; +import { OverlayBioEntityRender } from '@/types/OLrendering'; +import { useGetOverlayColor } from './useGetOverlayColor'; + +describe('useOverlayFeatures - hook', () => { + const { Wrapper } = getReduxWrapperWithStore({ + configuration: { + ...CONFIGURATION_INITIAL_STORE_MOCKS, + }, + }); + const { + result: { + current: { getOverlayBioEntityColorByAvailableProperties }, + }, + } = renderHook(() => useGetOverlayColor(), { + wrapper: Wrapper, + }); + + describe('getOverlayBioEntityColorByAvailableProperties - function', () => { + const ENTITY: OverlayBioEntityRender = { + id: 0, + modelId: 0, + x1: 0, + y1: 0, + x2: 0, + y2: 0, + width: 0, + height: 0, + value: null, + overlayId: 0, + color: null, + }; + + it('should return color based on value', () => {}); + + it('should return the correct result if entity has a value equal to 0', () => { + const entity = { ...ENTITY, value: 0 }; + + expect(getOverlayBioEntityColorByAvailableProperties(entity)).toEqual('#FFFFFFcc'); + }); + + it('should return the result if entity has a value', () => { + const entity = { ...ENTITY, value: -0.2137 }; + + expect(getOverlayBioEntityColorByAvailableProperties(entity)).toEqual('#FFC9C9cc'); + }); + + it('should return the correct result if entity has a color but no value', () => { + const entity = { ...ENTITY, color: { rgb: -65536, alpha: 0 } }; // red color + + expect(getOverlayBioEntityColorByAvailableProperties(entity)).toEqual('#ff0000cc'); + }); + + it('should return the default color if entity has neither a value nor a color', () => { + const entity = { ...ENTITY }; + + expect(getOverlayBioEntityColorByAvailableProperties(entity)).toEqual('#00FF00cc'); + }); + }); +}); diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.ts new file mode 100644 index 0000000000000000000000000000000000000000..64518c5e005318aca9f21c9635478e735043330b --- /dev/null +++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.ts @@ -0,0 +1,73 @@ +import { useCallback, useMemo } from 'react'; +import { WHITE_HEX_OPACITY_0 } from '@/constants/hexColors'; +import { + maxColorValSelector, + minColorValSelector, + neutralColorValSelector, + overlayOpacitySelector, + simpleColorValSelector, +} from '@/redux/configuration/configuration.selectors'; +import { useAppSelector } from '@/redux/hooks/useAppSelector'; +import { getHexTricolorGradientColorWithAlpha } from '@/utils/convert/getHexTricolorGradientColorWithAlpha'; +import { ONE, ZERO } from '@/constants/common'; +import { OverlayBioEntityRender } from '@/types/OLrendering'; +import { addAlphaToHexString } from '@/utils/convert/addAlphaToHexString'; +import { getHexStringColorFromRGBIntWithAlpha } from '@/utils/convert/getHexStringColorFromRGBIntWithAlpha'; + +type GetOverlayBioEntityColorByAvailableProperties = (entity: OverlayBioEntityRender) => string; + +type UseTriColorLerpReturn = { + getOverlayBioEntityColorByAvailableProperties: GetOverlayBioEntityColorByAvailableProperties; +}; + +export const useGetOverlayColor = (): UseTriColorLerpReturn => { + const minColorValHexString = useAppSelector(minColorValSelector) || ''; + const maxColorValHexString = useAppSelector(maxColorValSelector) || ''; + const neutralColorValHexString = useAppSelector(neutralColorValSelector) || ''; + const overlayOpacityValue = useAppSelector(overlayOpacitySelector) || ONE; + const simpleColorValue = useAppSelector(simpleColorValSelector) || WHITE_HEX_OPACITY_0; + + const getHex3ColorGradientColorWithAlpha = useCallback( + (position: number) => + getHexTricolorGradientColorWithAlpha({ + leftColor: minColorValHexString, + middleColor: neutralColorValHexString, + rightColor: maxColorValHexString, + position, + alpha: Number(overlayOpacityValue), + }), + [minColorValHexString, neutralColorValHexString, maxColorValHexString, overlayOpacityValue], + ); + + const getHexColorFromRGBIntWithAlpha = useCallback( + (rgbInt: number) => + getHexStringColorFromRGBIntWithAlpha({ rgbInt, alpha: Number(overlayOpacityValue) }), + [overlayOpacityValue], + ); + + const defaultColorHex = useMemo( + () => addAlphaToHexString(simpleColorValue, Number(overlayOpacityValue)), + [simpleColorValue, overlayOpacityValue], + ); + + /** + * Entity might have 3 properties that indicates color: + * value - which value from [-1,1] range and needs to interpolate between minColorVal, neutralColorVal and maxColorVal + * color - which is integer representation of color and needs to be converted to hex string + * defaultColor - which is hex string representation of color. It occurs when color and value are not available + */ + const getOverlayBioEntityColorByAvailableProperties = useCallback( + (entity: OverlayBioEntityRender) => { + if (typeof entity.value === 'number') { + return getHex3ColorGradientColorWithAlpha(entity.value || ZERO); + } + if (entity.color) { + return getHexColorFromRGBIntWithAlpha(entity.color.rgb); + } + return defaultColorHex; + }, + [getHex3ColorGradientColorWithAlpha, getHexColorFromRGBIntWithAlpha, defaultColorHex], + ); + + return { getOverlayBioEntityColorByAvailableProperties }; +}; diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer.ts index 71247c54a4bc0ae7ac0091de51336ac64c5d73cc..1fb0084b4de573f5a94c58e9145cfc18424a111a 100644 --- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer.ts +++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer.ts @@ -1,16 +1,9 @@ -import { useTriColorLerp } from '@/hooks/useTriColorLerp'; -import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { - getOverlayOrderSelector, - overlayBioEntitiesForCurrentModelSelector, -} from '@/redux/overlayBioEntity/overlayBioEntity.selector'; -import { usePointToProjection } from '@/utils/map/usePointToProjection'; -import { Feature } from 'ol'; -import { Geometry } from 'ol/geom'; +import Geometry from 'ol/geom/Geometry'; import VectorLayer from 'ol/layer/Vector'; import VectorSource from 'ol/source/Vector'; +import { Feature } from 'ol'; import { useMemo } from 'react'; -import { getOverlayFeatures } from './getOverlayFeatures'; +import { useOverlayFeatures } from './useOverlayFeatures'; /** * Prerequisites: "view" button triggers opening overlays -> it triggers downloading overlayBioEntityData for given overlay for ALL available submaps(models) @@ -27,34 +20,13 @@ import { getOverlayFeatures } from './getOverlayFeatures'; */ export const useOlMapOverlaysLayer = (): VectorLayer<VectorSource<Feature<Geometry>>> => { - const pointToProjection = usePointToProjection(); - const { getHex3ColorGradientColorWithAlpha, defaultColorHex } = useTriColorLerp(); - const bioEntities = useAppSelector(overlayBioEntitiesForCurrentModelSelector); - const overlaysOrder = useAppSelector(getOverlayOrderSelector); - - const features = useMemo( - () => - getOverlayFeatures({ - bioEntities, - pointToProjection, - getHex3ColorGradientColorWithAlpha, - defaultColor: defaultColorHex, - overlaysOrder, - }), - [ - bioEntities, - getHex3ColorGradientColorWithAlpha, - pointToProjection, - defaultColorHex, - overlaysOrder, - ], - ); + const overlaysFeatures = useOverlayFeatures(); const vectorSource = useMemo(() => { return new VectorSource({ - features, + features: overlaysFeatures, }); - }, [features]); + }, [overlaysFeatures]); const overlaysLayer = useMemo( () => diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..19c9b309415c6943c7c86e8b1fe477c606affe81 --- /dev/null +++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts @@ -0,0 +1,69 @@ +/* eslint-disable no-magic-numbers */ +import { renderHook } from '@testing-library/react'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { CONFIGURATION_INITIAL_STORE_MOCKS } from '@/redux/configuration/configuration.mock'; +import { OVERLAYS_PUBLIC_FETCHED_STATE_MOCK } from '@/redux/overlays/overlays.mock'; +import { mapStateWithCurrentlySelectedMainMapFixture } from '@/redux/map/map.fixtures'; +import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock'; +import { MOCKED_OVERLAY_BIO_ENTITY_RENDER } from '@/redux/overlayBioEntity/overlayBioEntity.mock'; +import { useOverlayFeatures } from './useOverlayFeatures'; + +/** + * mocks for useOverlayFeatures + * are taken from helpers functions that are used inside useOverlayFeatures + * point of the test is to test if all helper functions work correctly when combined together + */ + +describe('useOverlayFeatures', () => { + const { Wrapper } = getReduxWrapperWithStore({ + configuration: { + ...CONFIGURATION_INITIAL_STORE_MOCKS, + }, + overlayBioEntity: { + overlaysId: [11, 12], + data: { + // overlayId + 11: { + // modelId + 52: MOCKED_OVERLAY_BIO_ENTITY_RENDER, + 53: MOCKED_OVERLAY_BIO_ENTITY_RENDER, + }, + 12: { + 52: MOCKED_OVERLAY_BIO_ENTITY_RENDER, + 53: MOCKED_OVERLAY_BIO_ENTITY_RENDER, + }, + }, + }, + overlays: { + ...OVERLAYS_PUBLIC_FETCHED_STATE_MOCK, + }, + map: { + ...mapStateWithCurrentlySelectedMainMapFixture, + }, + models: { + ...MODELS_DATA_MOCK_WITH_MAIN_MAP, + }, + }); + + it('should return an array of features', () => { + const { + result: { current: features }, + } = renderHook(() => useOverlayFeatures(), { + wrapper: Wrapper, + }); + + expect(features).toHaveLength(6); + expect(features[0].getGeometry()?.getCoordinates()).toEqual([ + [ + [-13149141, 18867005], + [-13149141, 18881970], + [-13143529, 18881970], + [-13143529, 18867005], + [-13149141, 18867005], + ], + ]); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(features[0].getStyle().getFill().getColor()).toBe('#FFFFFFcc'); + }); +}); diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts new file mode 100644 index 0000000000000000000000000000000000000000..06985195eb9dafe82dbf23f616b3214945c9aff2 --- /dev/null +++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts @@ -0,0 +1,49 @@ +import { useMemo } from 'react'; +import { usePointToProjection } from '@/utils/map/usePointToProjection'; +import type Feature from 'ol/Feature'; +import type Polygon from 'ol/geom/Polygon'; +import { ZERO } from '@/constants/common'; +import { useAppSelector } from '@/redux/hooks/useAppSelector'; +import { + getOverlayOrderSelector, + overlayBioEntitiesForCurrentModelSelector, +} from '@/redux/overlayBioEntity/overlayBioEntity.selector'; +import { createOverlayGeometryFeature } from './createOverlayGeometryFeature'; +import { getPolygonLatitudeCoordinates } from './getPolygonLatitudeCoordinates'; +import { useGetOverlayColor } from './useGetOverlayColor'; + +export const useOverlayFeatures = (): Feature<Polygon>[] => { + const pointToProjection = usePointToProjection(); + const { getOverlayBioEntityColorByAvailableProperties } = useGetOverlayColor(); + const overlaysOrder = useAppSelector(getOverlayOrderSelector); + const bioEntities = useAppSelector(overlayBioEntitiesForCurrentModelSelector); + + const features = useMemo( + () => + bioEntities.map(entity => { + /** + * Depending on number of active overlays + * it's required to calculate xMin and xMax coordinates of the polygon + * so "entity" might be devided equality between active overlays + */ + const { xMin, xMax } = getPolygonLatitudeCoordinates({ + width: entity.width, + nOverlays: overlaysOrder.length, + xMin: entity.x1, + overlayIndexBasedOnOrder: + overlaysOrder.find(({ id }) => id === entity.overlayId)?.index || ZERO, + }); + + return createOverlayGeometryFeature( + [ + ...pointToProjection({ x: xMin, y: entity.y1 }), + ...pointToProjection({ x: xMax, y: entity.y2 }), + ], + getOverlayBioEntityColorByAvailableProperties(entity), + ); + }), + [overlaysOrder, bioEntities, pointToProjection, getOverlayBioEntityColorByAvailableProperties], + ); + + return features; +}; diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts index 0c2079d04320fc6daf02b194402aa5b2bbddb32b..ceecf01f0ad220d2637283d80ae564b650f13f53 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts @@ -3,14 +3,15 @@ import { searchedBioEntitesSelectorOfCurrentMap } from '@/redux/bioEntity/bioEnt import { searchedChemicalsBioEntitesOfCurrentMapSelector } from '@/redux/chemicals/chemicals.selectors'; import { searchedDrugsBioEntitesOfCurrentMapSelector } from '@/redux/drugs/drugs.selectors'; import { usePointToProjection } from '@/utils/map/usePointToProjection'; -import BaseLayer from 'ol/layer/Base'; +import Feature from 'ol/Feature'; +import { Geometry } from 'ol/geom'; import VectorLayer from 'ol/layer/Vector'; import VectorSource from 'ol/source/Vector'; import { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { getBioEntitiesFeatures } from './getBioEntitiesFeatures'; -export const useOlMapPinsLayer = (): BaseLayer => { +export const useOlMapPinsLayer = (): VectorLayer<VectorSource<Feature<Geometry>>> => { const pointToProjection = usePointToProjection(); const contentBioEntites = useSelector(searchedBioEntitesSelectorOfCurrentMap); const chemicalsBioEntities = useSelector(searchedChemicalsBioEntitesOfCurrentMapSelector); diff --git a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts index b4db459df1c08630eae039f9f5539855cf4964ac..ff40ba9134e054c7dd1cb444337071f2a7aef2ed 100644 --- a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts +++ b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts @@ -1,10 +1,11 @@ /* eslint-disable no-magic-numbers */ +import { MapInstance } from '@/types/map'; import { useEffect } from 'react'; -import { MapConfig, MapInstance } from '../../MapViewer.types'; +import { MapConfig } from '../../MapViewer.types'; +import { useOlMapOverlaysLayer } from './overlaysLayer/useOlMapOverlaysLayer'; import { useOlMapPinsLayer } from './pinsLayer/useOlMapPinsLayer'; import { useOlMapReactionsLayer } from './reactionsLayer/useOlMapReactionsLayer'; import { useOlMapTileLayer } from './useOlMapTileLayer'; -import { useOlMapOverlaysLayer } from './overlaysLayer/useOlMapOverlaysLayer'; interface UseOlMapLayersInput { mapInstance: MapInstance; diff --git a/src/components/Map/MapViewer/utils/config/useOlMapView.ts b/src/components/Map/MapViewer/utils/config/useOlMapView.ts index 9dc00a261aaed3dfc9c4f3dda0187755d0ae9c7e..4a4d9dc18032cb862f0bd6a88f96ab199f5bff47 100644 --- a/src/components/Map/MapViewer/utils/config/useOlMapView.ts +++ b/src/components/Map/MapViewer/utils/config/useOlMapView.ts @@ -1,12 +1,12 @@ /* eslint-disable no-magic-numbers */ import { OPTIONS } from '@/constants/map'; import { mapDataInitialPositionSelector } from '@/redux/map/map.selectors'; -import { Point } from '@/types/map'; +import { MapInstance, Point } from '@/types/map'; import { usePointToProjection } from '@/utils/map/usePointToProjection'; import { View } from 'ol'; import { useEffect, useMemo } from 'react'; import { useSelector } from 'react-redux'; -import { MapConfig, MapInstance } from '../../MapViewer.types'; +import { MapConfig } from '../../MapViewer.types'; interface UseOlMapViewInput { mapInstance: MapInstance; diff --git a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts index 5be3fd4cbf657d07bc3e958bda4e2c8b1205d812..5d7631ff007bc82ddcc675b81e67bd5eb384fdf4 100644 --- a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts +++ b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts @@ -2,16 +2,16 @@ import { OPTIONS } from '@/constants/map'; import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { mapDataSizeSelector } from '@/redux/map/map.selectors'; import { currentModelIdSelector } from '@/redux/models/models.selectors'; +import { MapInstance } from '@/types/map'; import { View } from 'ol'; import { unByKey } from 'ol/Observable'; +import { Coordinate } from 'ol/coordinate'; +import { Pixel } from 'ol/pixel'; import { useEffect, useRef } from 'react'; import { useSelector } from 'react-redux'; import { useDebouncedCallback } from 'use-debounce'; -import { Pixel } from 'ol/pixel'; -import { Coordinate } from 'ol/coordinate'; -import { MapInstance } from '../../MapViewer.types'; -import { onMapSingleClick } from './mapSingleClick/onMapSingleClick'; import { onMapRightClick } from './mapRightClick/onMapRightClick'; +import { onMapSingleClick } from './mapSingleClick/onMapSingleClick'; import { onMapPositionChange } from './onMapPositionChange'; interface UseOlMapListenersInput { diff --git a/src/components/Map/MapViewer/utils/useOlMap.ts b/src/components/Map/MapViewer/utils/useOlMap.ts index a7ffb39839e07fea132e5b3fbb7093aadbc03ff4..326e8ec8822585de8fe9397ec380143a7f040016 100644 --- a/src/components/Map/MapViewer/utils/useOlMap.ts +++ b/src/components/Map/MapViewer/utils/useOlMap.ts @@ -1,6 +1,8 @@ +import { MapInstance } from '@/types/map'; +import { useMapInstance } from '@/utils/context/mapInstanceContext'; import Map from 'ol/Map'; -import React, { MutableRefObject, useEffect, useState } from 'react'; -import { MapInstance } from '../MapViewer.types'; +import { Zoom } from 'ol/control'; +import React, { MutableRefObject, useEffect } from 'react'; import { useOlMapLayers } from './config/useOlMapLayers'; import { useOlMapView } from './config/useOlMapView'; import { useOlMapListeners } from './listeners/useOlMapListeners'; @@ -17,7 +19,7 @@ type UseOlMap = (input?: UseOlMapInput) => UseOlMapOutput; export const useOlMap: UseOlMap = ({ target } = {}) => { const mapRef = React.useRef<null | HTMLDivElement>(null); - const [mapInstance, setMapInstance] = useState<MapInstance>(undefined); + const { mapInstance, setMapInstance } = useMapInstance(); const view = useOlMapView({ mapInstance }); useOlMapLayers({ mapInstance }); useOlMapListeners({ view, mapInstance }); @@ -32,8 +34,15 @@ export const useOlMap: UseOlMap = ({ target } = {}) => { target: target || mapRef.current, }); + // remove zoom controls as we are using our own + map.getControls().forEach(mapControl => { + if (mapControl instanceof Zoom) { + map.removeControl(mapControl); + } + }); + setMapInstance(currentMap => currentMap || map); - }, [target]); + }, [target, setMapInstance]); return { mapRef, diff --git a/src/hooks/useTriColorLerp.ts b/src/hooks/useTriColorLerp.ts deleted file mode 100644 index f872b09c506edbf4b8c50c3e70d02e1a860d12f2..0000000000000000000000000000000000000000 --- a/src/hooks/useTriColorLerp.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { useCallback } from 'react'; -import { WHITE_HEX_OPACITY_0 } from '@/constants/hexColors'; -import { - maxColorValSelector, - minColorValSelector, - neutralColorValSelector, - overlayOpacitySelector, - simpleColorValSelector, -} from '@/redux/configuration/configuration.selectors'; -import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { getHexTricolorGradientColorWithAlpha } from '@/utils/convert/getHexTricolorGradientColorWithAlpha'; -import { ONE } from '@/constants/common'; -import { addAlphaToHexString } from '../utils/convert/addAlphaToHexString'; - -export type GetHex3ColorGradientColorWithAlpha = (position: number) => string; - -type UseTriColorLerpReturn = { - getHex3ColorGradientColorWithAlpha: GetHex3ColorGradientColorWithAlpha; - defaultColorHex: string; -}; - -export const useTriColorLerp = (): UseTriColorLerpReturn => { - const minColorValHexString = useAppSelector(minColorValSelector) || ''; - const maxColorValHexString = useAppSelector(maxColorValSelector) || ''; - const neutralColorValHexString = useAppSelector(neutralColorValSelector) || ''; - const overlayOpacityValue = useAppSelector(overlayOpacitySelector) || ONE; - const simpleColorValue = useAppSelector(simpleColorValSelector) || WHITE_HEX_OPACITY_0; - - const getHex3ColorGradientColorWithAlpha = useCallback( - (position: number) => - getHexTricolorGradientColorWithAlpha({ - leftColor: minColorValHexString, - middleColor: neutralColorValHexString, - rightColor: maxColorValHexString, - position, - alpha: Number(overlayOpacityValue), - }), - [minColorValHexString, neutralColorValHexString, maxColorValHexString, overlayOpacityValue], - ); - - const defaultColorHex = addAlphaToHexString(simpleColorValue, Number(overlayOpacityValue)); - - return { getHex3ColorGradientColorWithAlpha, defaultColorHex }; -}; diff --git a/src/models/configurationSchema.ts b/src/models/configurationSchema.ts index db44bb5651921d33a73a75029205a2b30f5291eb..b3ec41d84ddccc28ed1e1fbc0628508a316e51b9 100644 --- a/src/models/configurationSchema.ts +++ b/src/models/configurationSchema.ts @@ -16,13 +16,7 @@ export const optionSchema = z.object({ value: z.string().optional(), }); -export const imageFormatSchema = z.object({ - name: z.string(), - handler: z.string(), - extension: z.string(), -}); - -export const modelFormatSchema = z.object({ +export const formatSchema = z.object({ name: z.string(), handler: z.string(), extension: z.string(), @@ -87,8 +81,8 @@ export const modificationStateTypeSchema = z.record( export const configurationSchema = z.object({ elementTypes: z.array(elementTypeSchema), options: z.array(optionSchema), - imageFormats: z.array(imageFormatSchema), - modelFormats: z.array(modelFormatSchema), + imageFormats: z.array(formatSchema), + modelFormats: z.array(formatSchema), overlayTypes: z.array(overlayTypeSchema), reactionTypes: z.array(reactionTypeSchema), miriamTypes: miriamTypesSchema, diff --git a/src/models/fixtures/configurationFixture.ts b/src/models/fixtures/configurationFixture.ts new file mode 100644 index 0000000000000000000000000000000000000000..56e19f7adcb59678ca144fd6a63bb741c8e51876 --- /dev/null +++ b/src/models/fixtures/configurationFixture.ts @@ -0,0 +1,9 @@ +import { ZOD_SEED } from '@/constants'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { createFixture } from 'zod-fixture'; +import { configurationSchema } from '../configurationSchema'; + +export const configurationFixture = createFixture(configurationSchema, { + seed: ZOD_SEED, + array: { min: 1, max: 1 }, +}); diff --git a/src/models/mapPoint.ts b/src/models/mapPoint.ts new file mode 100644 index 0000000000000000000000000000000000000000..813926d1fa8cd6b008d0ebe51649938c0f6e533d --- /dev/null +++ b/src/models/mapPoint.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; + +/* This schema is used only for local Point objects, it's NOT returned from backend */ + +export const mapPointSchema = z.object({ + x: z.number().finite().nonnegative(), + y: z.number().finite().nonnegative(), + z: z.number().finite().nonnegative().optional(), +}); diff --git a/src/models/mocks/configurationFormatsMock.ts b/src/models/mocks/configurationFormatsMock.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d6d4e8afa75491a2fcafee702da4320a633f1b9 --- /dev/null +++ b/src/models/mocks/configurationFormatsMock.ts @@ -0,0 +1,31 @@ +import { ConfigurationFormatSchema } from '@/types/models'; + +export const CONFIGURATION_FORMATS_TYPES_MOCK: string[] = [ + 'CellDesigner SBML', + 'SBGN-ML', + 'SBML', + 'GPML', +]; + +export const CONFIGURATION_FORMATS_MOCK: ConfigurationFormatSchema[] = [ + { + name: 'CellDesigner SBML', + handler: 'lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser', + extension: 'xml', + }, + { + name: 'SBGN-ML', + handler: 'lcsb.mapviewer.converter.model.sbgnml.SbgnmlXmlConverter', + extension: 'sbgn', + }, + { + name: 'SBML', + handler: 'lcsb.mapviewer.converter.model.sbml.SbmlParser', + extension: 'xml', + }, + { + name: 'GPML', + handler: 'lcsb.mapviewer.wikipathway.GpmlParser', + extension: 'gpml', + }, +]; diff --git a/src/models/mocks/configurationOptionMock.ts b/src/models/mocks/configurationOptionMock.ts index f658402ecdddcb0df80cf9a1e92e940b5c422679..c1e6a1e53d452fd0b9b66bf25538afdbe832623b 100644 --- a/src/models/mocks/configurationOptionMock.ts +++ b/src/models/mocks/configurationOptionMock.ts @@ -5,6 +5,7 @@ export const CONFIGURATION_OPTIONS_TYPES_MOCK: string[] = [ 'MAX_COLOR_VAL', 'SIMPLE_COLOR_VAL', 'NEUTRAL_COLOR_VAL', + 'OVERLAY_OPACITY', ]; export const CONFIGURATION_OPTIONS_COLOURS_MOCK: ConfigurationOption[] = [ @@ -44,4 +45,13 @@ export const CONFIGURATION_OPTIONS_COLOURS_MOCK: ConfigurationOption[] = [ value: 'FFFFFF', group: 'Overlays', }, + { + idObject: 33, + type: 'OVERLAY_OPACITY', + valueType: 'DOUBLE', + commonName: 'Opacity used when drawing data overlays (value between 0.0-1.0)', + isServerSide: false, + value: '0.8', + group: 'Overlays', + }, ]; diff --git a/src/redux/bioEntity/bioEntity.selectors.ts b/src/redux/bioEntity/bioEntity.selectors.ts index f3b2149d886a31f9605d9cf1b044837447059f40..8b39954fdb451fe218724c0315382a527b4f39b1 100644 --- a/src/redux/bioEntity/bioEntity.selectors.ts +++ b/src/redux/bioEntity/bioEntity.selectors.ts @@ -3,11 +3,13 @@ import { rootSelector } from '@/redux/root/root.selectors'; import { MultiSearchData } from '@/types/fetchDataState'; import { BioEntity, BioEntityContent, MapModel } from '@/types/models'; import { createSelector } from '@reduxjs/toolkit'; +import { searchedChemicalsBioEntitesOfCurrentMapSelector } from '../chemicals/chemicals.selectors'; +import { currentSelectedBioEntityIdSelector } from '../contextMenu/contextMenu.selector'; import { currentSearchedBioEntityId, currentSelectedSearchElement, } from '../drawer/drawer.selectors'; -import { currentSelectedBioEntityIdSelector } from '../contextMenu/contextMenu.selector'; +import { searchedDrugsBioEntitesOfCurrentMapSelector } from '../drugs/drugs.selectors'; import { currentModelIdSelector, modelsDataSelector } from '../models/models.selectors'; export const bioEntitySelector = createSelector(rootSelector, state => state.bioEntity); @@ -105,3 +107,12 @@ export const bioEntitiesPerModelSelector = createSelector( ); }, ); + +export const allVisibleBioEntitiesSelector = createSelector( + searchedBioEntitesSelectorOfCurrentMap, + searchedChemicalsBioEntitesOfCurrentMapSelector, + searchedDrugsBioEntitesOfCurrentMapSelector, + (content, chemicals, drugs): BioEntity[] => { + return [content, chemicals, drugs].flat(); + }, +); diff --git a/src/redux/compartmentPathways/compartmentPathways.reducers.test.ts b/src/redux/compartmentPathways/compartmentPathways.reducers.test.ts index 2c2639032a77c6798b6ec8c8b648f4927a135e21..037eefa24fe80a7a82141bdedf7ce5c757e0b9b6 100644 --- a/src/redux/compartmentPathways/compartmentPathways.reducers.test.ts +++ b/src/redux/compartmentPathways/compartmentPathways.reducers.test.ts @@ -10,7 +10,7 @@ import { compartmentPathwaysFixture, compartmentPathwaysOverLimitFixture, } from '@/models/fixtures/compartmentPathways'; -import { getModelsIds } from '@/components/Map/Drawer/ExportDrawer/Elements/Elements.utils'; +import { getModelsIds } from '@/components/Map/Drawer/ExportDrawer/ExportDrawer.component.utils'; import { apiPath } from '../apiPath'; import compartmentPathwaysReducer from './compartmentPathways.slice'; import { CompartmentPathwaysState } from './compartmentPathways.types'; diff --git a/src/redux/compartmentPathways/compartmentPathways.thunks.test.ts b/src/redux/compartmentPathways/compartmentPathways.thunks.test.ts index b2d801e304562f0a8da4aecd402b9b3aa0bfe906..407eb70d6a20ff4abb36a2408b2a0eb388c084b3 100644 --- a/src/redux/compartmentPathways/compartmentPathways.thunks.test.ts +++ b/src/redux/compartmentPathways/compartmentPathways.thunks.test.ts @@ -10,7 +10,7 @@ import { compartmentPathwaysFixture, compartmentPathwaysOverLimitFixture, } from '@/models/fixtures/compartmentPathways'; -import { getModelsIds } from '@/components/Map/Drawer/ExportDrawer/Elements/Elements.utils'; +import { getModelsIds } from '@/components/Map/Drawer/ExportDrawer/ExportDrawer.component.utils'; import { apiPath } from '../apiPath'; import compartmentPathwaysReducer from './compartmentPathways.slice'; import { CompartmentPathwaysState } from './compartmentPathways.types'; diff --git a/src/redux/configuration/configuration.constants.ts b/src/redux/configuration/configuration.constants.ts index ebf80efa62cfa09dab7aa8a2b4d94167ab0b16c3..56448d47fce6e44bf31adfe19acd78b25b340453 100644 --- a/src/redux/configuration/configuration.constants.ts +++ b/src/redux/configuration/configuration.constants.ts @@ -10,3 +10,8 @@ export const LEGEND_FILE_NAMES_IDS = [ 'LEGEND_FILE_3', 'LEGEND_FILE_4', ]; + +export const GPML_HANDLER_NAME_ID = 'GPML'; +export const SBML_HANDLER_NAME_ID = 'SBML'; +export const CELL_DESIGNER_SBML_HANDLER_NAME_ID = 'CellDesigner SBML'; +export const SBGN_ML_HANDLER_NAME_ID = 'SBGN-ML'; diff --git a/src/redux/configuration/configuration.mock.ts b/src/redux/configuration/configuration.mock.ts index d371990411b2f4fc2e88b66f44c411da248d346e..07ee6ea998096fcad4a62772d50845021e074e18 100644 --- a/src/redux/configuration/configuration.mock.ts +++ b/src/redux/configuration/configuration.mock.ts @@ -1,8 +1,8 @@ /* eslint-disable no-magic-numbers */ import { DEFAULT_ERROR } from '@/constants/errors'; import { - CONFIGURATION_OPTIONS_TYPES_MOCK, CONFIGURATION_OPTIONS_COLOURS_MOCK, + CONFIGURATION_OPTIONS_TYPES_MOCK, } from '@/models/mocks/configurationOptionMock'; import { ConfigurationState } from './configuration.adapter'; @@ -29,6 +29,7 @@ export const CONFIGURATION_INITIAL_STORE_MOCKS: ConfigurationState = { [CONFIGURATION_OPTIONS_TYPES_MOCK[1]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[1], [CONFIGURATION_OPTIONS_TYPES_MOCK[2]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[2], [CONFIGURATION_OPTIONS_TYPES_MOCK[3]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[3], + [CONFIGURATION_OPTIONS_TYPES_MOCK[4]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[4], }, loading: 'idle', error: DEFAULT_ERROR, diff --git a/src/redux/configuration/configuration.reducers.ts b/src/redux/configuration/configuration.reducers.ts index 57e60a05a28eda8721332f80adbf4abeda5c56bd..f1f428a1a6b3d8704c67221227a56d410b7e8b02 100644 --- a/src/redux/configuration/configuration.reducers.ts +++ b/src/redux/configuration/configuration.reducers.ts @@ -1,6 +1,6 @@ import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; -import { getConfiguration, getConfigurationOptions } from './configuration.thunks'; import { ConfigurationState, configurationAdapter } from './configuration.adapter'; +import { getConfiguration, getConfigurationOptions } from './configuration.thunks'; export const getConfigurationOptionsReducer = ( builder: ActionReducerMapBuilder<ConfigurationState>, diff --git a/src/redux/configuration/configuration.selectors.ts b/src/redux/configuration/configuration.selectors.ts index 3fc6d2e7118f93ef7c17d575fbdfb1ec6dd17b1b..451590bbca72cf44ab73bec01501175c15f96612 100644 --- a/src/redux/configuration/configuration.selectors.ts +++ b/src/redux/configuration/configuration.selectors.ts @@ -1,17 +1,24 @@ +import { ConfigurationFormatSchema } from '@/types/models'; import { createSelector } from '@reduxjs/toolkit'; import { rootSelector } from '../root/root.selectors'; import { configurationAdapter } from './configuration.adapter'; import { + CELL_DESIGNER_SBML_HANDLER_NAME_ID, + GPML_HANDLER_NAME_ID, LEGEND_FILE_NAMES_IDS, MAX_COLOR_VAL_NAME_ID, MIN_COLOR_VAL_NAME_ID, NEUTRAL_COLOR_VAL_NAME_ID, OVERLAY_OPACITY_NAME_ID, + SBGN_ML_HANDLER_NAME_ID, + SBML_HANDLER_NAME_ID, SIMPLE_COLOR_VAL_NAME_ID, } from './configuration.constants'; +import { ConfigurationHandlersIds } from './configuration.types'; const configurationSelector = createSelector(rootSelector, state => state.configuration); const configurationOptionsSelector = createSelector(configurationSelector, state => state.options); +const configurationMainSelector = createSelector(configurationSelector, state => state.main.data); const configurationAdapterSelectors = configurationAdapter.getSelectors(); @@ -46,12 +53,38 @@ export const defaultLegendImagesSelector = createSelector(configurationOptionsSe ).filter(legendImage => Boolean(legendImage)), ); -export const configurationMainSelector = createSelector( - configurationSelector, - state => state.main.data, -); - export const elementTypesSelector = createSelector( configurationMainSelector, state => state?.elementTypes, ); + +export const modelFormatsSelector = createSelector( + configurationMainSelector, + state => state?.modelFormats, +); + +export const formatsEntriesSelector = createSelector( + modelFormatsSelector, + (modelFormats): Record<string, ConfigurationFormatSchema> => { + return Object.fromEntries( + (modelFormats || []) + .flat() + .filter((format: ConfigurationFormatSchema): format is ConfigurationFormatSchema => + Boolean(format), + ) + .map((format: ConfigurationFormatSchema) => [format.name, format]), + ); + }, +); + +export const formatsHandlersSelector = createSelector( + formatsEntriesSelector, + (formats): ConfigurationHandlersIds => { + return { + [GPML_HANDLER_NAME_ID]: formats[GPML_HANDLER_NAME_ID]?.handler, + [SBML_HANDLER_NAME_ID]: formats[SBML_HANDLER_NAME_ID]?.handler, + [CELL_DESIGNER_SBML_HANDLER_NAME_ID]: formats[CELL_DESIGNER_SBML_HANDLER_NAME_ID]?.handler, + [SBGN_ML_HANDLER_NAME_ID]: formats[SBGN_ML_HANDLER_NAME_ID]?.handler, + }; + }, +); diff --git a/src/redux/configuration/configuration.slice.ts b/src/redux/configuration/configuration.slice.ts index 7758564a93148b091a89035997757284c363e5ca..5b71ec09cdf82f7578287f0888a4a2ed19346731 100644 --- a/src/redux/configuration/configuration.slice.ts +++ b/src/redux/configuration/configuration.slice.ts @@ -1,6 +1,6 @@ import { createSlice } from '@reduxjs/toolkit'; -import { getConfigurationOptionsReducer, getConfigurationReducer } from './configuration.reducers'; import { CONFIGURATION_INITIAL_STATE } from './configuration.adapter'; +import { getConfigurationOptionsReducer, getConfigurationReducer } from './configuration.reducers'; export const configurationSlice = createSlice({ name: 'configuration', diff --git a/src/redux/configuration/configuration.types.ts b/src/redux/configuration/configuration.types.ts index 086619ae0b02e56f9a8d4a9a21f26beaebfa4545..e797b88764723d2f18b1c2c7b2898c46d3ade799 100644 --- a/src/redux/configuration/configuration.types.ts +++ b/src/redux/configuration/configuration.types.ts @@ -1,4 +1,17 @@ import { FetchDataState } from '@/types/fetchDataState'; import { Configuration } from '@/types/models'; +import { + CELL_DESIGNER_SBML_HANDLER_NAME_ID, + GPML_HANDLER_NAME_ID, + SBGN_ML_HANDLER_NAME_ID, + SBML_HANDLER_NAME_ID, +} from './configuration.constants'; export type ConfigurationMainState = FetchDataState<Configuration>; + +export interface ConfigurationHandlersIds { + [GPML_HANDLER_NAME_ID]?: string; + [SBML_HANDLER_NAME_ID]?: string; + [CELL_DESIGNER_SBML_HANDLER_NAME_ID]?: string; + [SBGN_ML_HANDLER_NAME_ID]?: string; +} 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.fixtures.ts b/src/redux/map/map.fixtures.ts index 5cb2f16fe2683d2988f2a7bd16aff6e95a558eaf..be022b6972ad0c42f4ff1c7c9e2c95351f47af4e 100644 --- a/src/redux/map/map.fixtures.ts +++ b/src/redux/map/map.fixtures.ts @@ -40,3 +40,20 @@ export const initialMapStateFixture: MapState = { error: DEFAULT_ERROR, openedMaps: openedMapsInitialValueFixture, }; + +export const mapStateWithCurrentlySelectedMainMapFixture: MapState = { + data: { + ...initialMapDataFixture, + modelId: 52, + size: { + width: 26779.25, + height: 13503, + tileSize: 256, + minZoom: 2, + maxZoom: 9, + }, + }, + loading: 'idle', + error: DEFAULT_ERROR, + openedMaps: openedMapsInitialValueFixture, +}; 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.reducers.ts b/src/redux/map/map.reducers.ts index b17f1432b0cad6c95e8877e6970d2c6de5d501fa..eef6f9324c56ef85ab70d4c61ccf5f9320f82fd6 100644 --- a/src/redux/map/map.reducers.ts +++ b/src/redux/map/map.reducers.ts @@ -1,4 +1,5 @@ import { ZERO } from '@/constants/common'; +import { DEFAULT_ZOOM } from '@/constants/map'; import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; import { getPointMerged } from '../../utils/object/getPointMerged'; import { MAIN_MAP } from './map.constants'; @@ -14,6 +15,7 @@ import { OpenMapAndSetActiveAction, SetActiveMapAction, SetBackgroundAction, + SetLastPositionZoomAction, SetMapDataAction, SetMapPositionDataAction, } from './map.types'; @@ -40,6 +42,20 @@ export const setMapPositionReducer = (state: MapState, action: SetMapPositionDat }; }; +export const varyPositionZoomReducer = ( + state: MapState, + action: SetLastPositionZoomAction, +): void => { + const { minZoom, maxZoom } = state.data.size; + const { delta } = action.payload; + const currentZ = state.data.position.last.z || DEFAULT_ZOOM; + const newZ = currentZ + delta; + const newZLimited = Math.min(Math.max(newZ, minZoom), maxZoom); + + state.data.position.last.z = newZLimited; + state.data.position.initial.z = newZLimited; +}; + const updateLastPositionOfCurrentlyActiveMap = (state: MapState): void => { const currentMapId = state.data.modelId; const currentOpenedMap = state.openedMaps.find(openedMap => openedMap.modelId === currentMapId); diff --git a/src/redux/map/map.slice.ts b/src/redux/map/map.slice.ts index 73cbb92f2e7887f7674dd7260e8e895b45de24bb..8fc687b9fb29301fc18cc15579ca40b6caef893f 100644 --- a/src/redux/map/map.slice.ts +++ b/src/redux/map/map.slice.ts @@ -1,30 +1,23 @@ 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, + initMapBackgroundsReducer, + initMapPositionReducers, + initMapSizeAndModelIdReducer, + initOpenedMapsReducer, openMapAndSetActiveReducer, setActiveMapReducer, + setMapBackgroundReducer, setMapDataReducer, - initMapPositionReducers, setMapPositionReducer, - initOpenedMapsReducer, - initMapSizeAndModelIdReducer, - initMapBackgroundsReducer, - setMapBackgroundReducer, + 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, @@ -32,6 +25,7 @@ const mapSlice = createSlice({ closeMap: closeMapReducer, closeMapAndSetMainMapActive: closeMapAndSetMainMapActiveReducer, setMapPosition: setMapPositionReducer, + varyPositionZoom: varyPositionZoomReducer, setMapBackground: setMapBackgroundReducer, }, extraReducers: builder => { @@ -50,6 +44,7 @@ export const { closeMapAndSetMainMapActive, setMapPosition, setMapBackground, + varyPositionZoom, } = mapSlice.actions; export default mapSlice.reducer; diff --git a/src/redux/map/map.types.ts b/src/redux/map/map.types.ts index 16f5e54210814eca8c851769a049622b2b4057c1..3d15719aa783b34b5796321c166e30c02a2d9eb6 100644 --- a/src/redux/map/map.types.ts +++ b/src/redux/map/map.types.ts @@ -82,6 +82,12 @@ export type GetUpdatedMapDataResult = Pick< export type SetMapPositionDataAction = PayloadAction<Point>; +export type SetLastPositionZoomActionPayload = { + delta: number; +}; + +export type SetLastPositionZoomAction = PayloadAction<SetLastPositionZoomActionPayload>; + export type InitMapDataActionPayload = { data: GetUpdatedMapDataResult | object; openedMaps: OppenedMap[]; diff --git a/src/redux/models/models.mock.ts b/src/redux/models/models.mock.ts index e45763d82516d7ff30c12ee7512a8da5f2378cdf..b7658d3867c9d80e221fa59ffd8507c51b0cf46d 100644 --- a/src/redux/models/models.mock.ts +++ b/src/redux/models/models.mock.ts @@ -6,3 +6,27 @@ export const MODELS_INITIAL_STATE_MOCK: ModelsState = { loading: 'idle', error: DEFAULT_ERROR, }; + +export const MODELS_DATA_MOCK_WITH_MAIN_MAP: ModelsState = { + data: [ + { + idObject: 52, + width: 26779.25, + height: 13503, + defaultCenterX: null, + defaultCenterY: null, + description: '', + name: 'Core PD map', + defaultZoomLevel: null, + tileSize: 256, + references: [], + authors: [], + creationDate: null, + modificationDates: [], + minZoom: 2, + maxZoom: 9, + }, + ], + loading: 'idle', + error: DEFAULT_ERROR, +}; diff --git a/src/redux/overlayBioEntity/overlayBioEntity.mock.ts b/src/redux/overlayBioEntity/overlayBioEntity.mock.ts index 4fa115d0c747d65e9d25369984108bc98c4ca6ce..84fab91d714d1acdbb49aa3275b6b5fe13cc668c 100644 --- a/src/redux/overlayBioEntity/overlayBioEntity.mock.ts +++ b/src/redux/overlayBioEntity/overlayBioEntity.mock.ts @@ -1,6 +1,49 @@ +import { OverlayBioEntityRender } from '@/types/OLrendering'; import { OverlaysBioEntityState } from './overlayBioEntity.types'; export const OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK: OverlaysBioEntityState = { overlaysId: [], data: [], }; + +export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [ + { + id: 1, + modelId: 52, + width: 30, + x1: 18412, + x2: 18492, + y1: 3128.653195488725, + y2: 3088.653195488725, + overlayId: 11, + height: 10, + value: 0, + color: null, + }, + { + id: 2, + modelId: 52, + width: 30, + x1: 18412, + x2: 18492, + y1: 3128.653195488725, + y2: 3088.653195488725, + overlayId: 11, + height: 10, + value: -0.2137, + color: null, + }, + { + id: 3, + modelId: 52, + width: 40, + x1: 18412, + x2: 18492, + y1: 3128.653195488725, + y2: 3088.653195488725, + overlayId: 11, + height: 10, + value: null, + color: { rgb: -65536, alpha: 0 }, + }, +]; diff --git a/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts b/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts index 2ba83189feb03c61dd36bb018a9519b485a81772..8a09ebb08aca68fb46d2bb1a908fceb45c41bd56 100644 --- a/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts +++ b/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts @@ -1,11 +1,11 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import { z } from 'zod'; import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance'; import { OverlayBioEntity } from '@/types/models'; -import { overlayBioEntitySchema } from '@/models/overlayBioEntitySchema'; -import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema'; import { OverlayBioEntityRender } from '@/types/OLrendering'; -import { parseOverlayBioEntityToOlRenderingFormat } from './overlayBioEntity.utils'; +import { + getValidOverlayBioEntities, + parseOverlayBioEntityToOlRenderingFormat, +} from './overlayBioEntity.utils'; import { apiPath } from '../apiPath'; import { modelsIdsSelector } from '../models/models.selectors'; import type { RootState } from '../store'; @@ -27,10 +27,10 @@ export const getOverlayBioEntity = createAsyncThunk( apiPath.getOverlayBioEntity({ overlayId, modelId }), ); - const isDataValid = validateDataUsingZodSchema(response.data, z.array(overlayBioEntitySchema)); + const validOverlayBioEntities = getValidOverlayBioEntities(response.data); - if (isDataValid) { - return parseOverlayBioEntityToOlRenderingFormat(response.data, overlayId); + if (validOverlayBioEntities) { + return parseOverlayBioEntityToOlRenderingFormat(validOverlayBioEntities, overlayId); } return undefined; diff --git a/src/redux/overlayBioEntity/overlayBioEntity.utils.test.ts b/src/redux/overlayBioEntity/overlayBioEntity.utils.test.ts index 5714a9a799a8b56f2d6ae54ccac8055261fa613c..abb5b8fb8b1a2e841f19a268a3c49a4e2350de02 100644 --- a/src/redux/overlayBioEntity/overlayBioEntity.utils.test.ts +++ b/src/redux/overlayBioEntity/overlayBioEntity.utils.test.ts @@ -1,4 +1,6 @@ -import { calculateOvarlaysOrder } from './overlayBioEntity.utils'; +import { overlayBioEntityFixture } from '@/models/fixtures/overlayBioEntityFixture'; +import { OverlayBioEntity } from '@/types/models'; +import { calculateOvarlaysOrder, getValidOverlayBioEntities } from './overlayBioEntity.utils'; describe('calculateOverlaysOrder', () => { const cases = [ @@ -62,3 +64,37 @@ describe('calculateOverlaysOrder', () => { expect(calculateOvarlaysOrder(data)).toStrictEqual(expected); }); }); + +describe('getValidOverlayBioEntities', () => { + it('should return empty array if overlayBioEntities are empty array', () => { + const result = getValidOverlayBioEntities([]); + + expect(result).toEqual([]); + }); + it('should return the same overlayBioEntities if all overlayBioEntities are valid', () => { + const result = getValidOverlayBioEntities(overlayBioEntityFixture); + expect(result).toEqual(overlayBioEntityFixture); + }); + it('should filter properly and return valid overlayBioEntities if overlayBioEntities are mixed array with valid and invalid entities', () => { + const invalidOverlayBioEntities = overlayBioEntityFixture.map(overlayBioEntity => ({ + ...overlayBioEntity, + left: {}, + })) as OverlayBioEntity[]; + + const result = getValidOverlayBioEntities([ + ...overlayBioEntityFixture, + ...invalidOverlayBioEntities, + ]); + expect(result).toEqual(overlayBioEntityFixture); + }); + it('should return empty array if all overlayBioEntities are invalid', () => { + const invalidOverlayBioEntities = overlayBioEntityFixture.map(overlayBioEntity => ({ + ...overlayBioEntity, + right: {}, + })) as OverlayBioEntity[]; + + const result = getValidOverlayBioEntities(invalidOverlayBioEntities); + + expect(result).toEqual([]); + }); +}); diff --git a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts index e632f31a4fd5cb75b966d33868cddf9f0acf1777..7c92f7a20080e78660bcf391194990c13940451b 100644 --- a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts +++ b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts @@ -1,6 +1,8 @@ import { ONE } from '@/constants/common'; +import { overlayBioEntitySchema } from '@/models/overlayBioEntitySchema'; import { OverlayBioEntityRender } from '@/types/OLrendering'; import { OverlayBioEntity } from '@/types/models'; +import { z } from 'zod'; export const parseOverlayBioEntityToOlRenderingFormat = ( data: OverlayBioEntity[], @@ -66,3 +68,23 @@ export const calculateOvarlaysOrder = ( return overlaysOrder; }; + +const isValidOverlayBioEntity = (overlayBioEntity: OverlayBioEntity): boolean => { + return overlayBioEntitySchema.safeParse(overlayBioEntity).success; +}; + +type OverlayBioEntities = OverlayBioEntity[]; + +export const getValidOverlayBioEntities = ( + unvalidatedOverlayBioEntities: OverlayBioEntities, +): OverlayBioEntities | undefined => { + const filteredValidOverlayBioEntitiesSchema = z + .array(z.any()) + .transform(overlayBioEntities => overlayBioEntities.filter(isValidOverlayBioEntity)); + + const parsedOverlayBioEntities = filteredValidOverlayBioEntitiesSchema.safeParse( + unvalidatedOverlayBioEntities, + ); + + return parsedOverlayBioEntities.success ? parsedOverlayBioEntities.data : undefined; +}; diff --git a/src/redux/root/query.selectors.ts b/src/redux/root/query.selectors.ts index 98660410716f25c5e3f663f7f22cd7073667ceee..3088b0dacb0ae0051fb11a60a658af927aff4667 100644 --- a/src/redux/root/query.selectors.ts +++ b/src/redux/root/query.selectors.ts @@ -16,18 +16,20 @@ export const queryDataParamsSelector = createSelector( { modelId, backgroundId, position }, activeOverlaysId, ): QueryDataParams => { + const joinedSearchValue = searchValue.join(';'); + const shouldIncludeSearchValue = searchValue.length > ZERO && joinedSearchValue; + + const shouldIncludeOverlaysId = activeOverlaysId.length > ZERO; + const queryDataParams: QueryDataParams = { - searchValue: searchValue.join(';'), perfectMatch, modelId, backgroundId, ...position.last, + ...(shouldIncludeSearchValue ? { searchValue: joinedSearchValue } : {}), + ...(shouldIncludeOverlaysId ? { overlaysId: activeOverlaysId.join(',') } : {}), }; - if (activeOverlaysId.length > ZERO) { - queryDataParams.overlaysId = activeOverlaysId.join(','); - } - return queryDataParams; }, ); diff --git a/src/shared/Icon/Icon.component.tsx b/src/shared/Icon/Icon.component.tsx index a4b4ee63bf1c35658d6e35493e908c7c8689e0bf..0dae32d43b3d4e3848f0dcbce4bbaebc30e6dab6 100644 --- a/src/shared/Icon/Icon.component.tsx +++ b/src/shared/Icon/Icon.component.tsx @@ -15,6 +15,9 @@ import { CloseIcon } from '@/shared/Icon/Icons/CloseIcon'; import { Pin } from '@/shared/Icon/Icons/Pin'; import type { IconTypes } from '@/types/iconTypes'; +import { LocationIcon } from './Icons/LocationIcon'; +import { MaginfierZoomInIcon } from './Icons/MagnifierZoomIn'; +import { MaginfierZoomOutIcon } from './Icons/MagnifierZoomOut'; export interface IconProps { className?: string; @@ -37,6 +40,9 @@ const icons = { page: PageIcon, plugin: PluginIcon, close: CloseIcon, + location: LocationIcon, + 'magnifier-zoom-in': MaginfierZoomInIcon, + 'magnifier-zoom-out': MaginfierZoomOutIcon, } as const; export const Icon = ({ name, className = '', ...rest }: IconProps): JSX.Element => { diff --git a/src/shared/Icon/Icons/LocationIcon.tsx b/src/shared/Icon/Icons/LocationIcon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d931d3310ad3ceb023c6b182a88c85211e7abfe5 --- /dev/null +++ b/src/shared/Icon/Icons/LocationIcon.tsx @@ -0,0 +1,19 @@ +interface LocationIconProps { + className?: string; +} + +export const LocationIcon = ({ className }: LocationIconProps): JSX.Element => ( + <svg + width="28" + height="28" + viewBox="0 0 28 28" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className={className} + > + <path + d="M13.9998 9.33073C11.4215 9.33073 9.33317 11.4191 9.33317 13.9974C9.33317 16.5757 11.4215 18.6641 13.9998 18.6641C16.5782 18.6641 18.6665 16.5757 18.6665 13.9974C18.6665 11.4191 16.5782 9.33073 13.9998 9.33073ZM24.4298 12.8307C24.1656 10.4649 23.1047 8.25919 21.4214 6.57587C19.738 4.89255 17.5324 3.83166 15.1665 3.5674V1.16406H12.8332V3.5674C10.4673 3.83166 8.26163 4.89255 6.57831 6.57587C4.895 8.25919 3.8341 10.4649 3.56984 12.8307H1.1665V15.1641H3.56984C3.8341 17.5299 4.895 19.7356 6.57831 21.4189C8.26163 23.1022 10.4673 24.1631 12.8332 24.4274V26.8307H15.1665V24.4274C17.5324 24.1631 19.738 23.1022 21.4214 21.4189C23.1047 19.7356 24.1656 17.5299 24.4298 15.1641H26.8332V12.8307H24.4298V12.8307ZM13.9998 22.1641C9.48484 22.1641 5.83317 18.5124 5.83317 13.9974C5.83317 9.4824 9.48484 5.83073 13.9998 5.83073C18.5148 5.83073 22.1665 9.4824 22.1665 13.9974C22.1665 18.5124 18.5148 22.1641 13.9998 22.1641Z" + fill="#8E92A1" + /> + </svg> +); diff --git a/src/shared/Icon/Icons/MagnifierZoomIn.tsx b/src/shared/Icon/Icons/MagnifierZoomIn.tsx new file mode 100644 index 0000000000000000000000000000000000000000..574eba979012da98ae659df45f9b66594b092449 --- /dev/null +++ b/src/shared/Icon/Icons/MagnifierZoomIn.tsx @@ -0,0 +1,27 @@ +interface MaginfierZoomInProps { + className?: string; +} + +export const MaginfierZoomInIcon = ({ className }: MaginfierZoomInProps): JSX.Element => ( + <svg + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className={className} + > + <g clipPath="url(#clip0_4_190)"> + <path d="M15 12H12V15H9V12H6V9H9V6H12V9H15V12Z" fill="#8E92A1" /> + <path + d="M23.5605 19.9395L19.5 15.879C20.4798 14.2558 20.9985 12.396 21 10.5C21 4.71 16.2885 0 10.5 0C4.7115 0 0 4.71 0 10.5C0 16.29 4.7115 21 10.5 21C12.3962 20.9994 14.2562 20.4808 15.879 19.5L19.9395 23.5605C20.0785 23.7003 20.2437 23.8112 20.4257 23.8869C20.6077 23.9626 20.8029 24.0016 21 24.0016C21.1971 24.0016 21.3923 23.9626 21.5743 23.8869C21.7563 23.8112 21.9215 23.7003 22.0605 23.5605L23.5605 22.0605C23.6999 21.9213 23.8105 21.756 23.886 21.574C23.9615 21.3921 24.0003 21.197 24.0003 21C24.0003 20.803 23.9615 20.6079 23.886 20.426C23.8105 20.244 23.6999 20.0787 23.5605 19.9395V19.9395ZM10.5 18C8.51068 17.9998 6.60291 17.2094 5.19639 15.8026C3.78987 14.3957 2.9998 12.4878 3 10.4985C3.0002 8.50918 3.79064 6.60141 5.19745 5.19489C6.60425 3.78837 8.51218 2.9983 10.5015 2.9985C12.4908 2.9987 14.3986 3.78915 15.8051 5.19595C17.2116 6.60275 18.0017 8.51068 18.0015 10.5C18.0013 12.4893 17.2109 14.3971 15.8041 15.8036C14.3972 17.2101 12.4893 18.0002 10.5 18V18Z" + fill="#8E92A1" + /> + </g> + <defs> + <clipPath id="clip0_4_190"> + <rect width="24" height="24" fill="white" /> + </clipPath> + </defs> + </svg> +); diff --git a/src/shared/Icon/Icons/MagnifierZoomOut.tsx b/src/shared/Icon/Icons/MagnifierZoomOut.tsx new file mode 100644 index 0000000000000000000000000000000000000000..56978cc55c4b43417e38d5c30833bef91ac6e374 --- /dev/null +++ b/src/shared/Icon/Icons/MagnifierZoomOut.tsx @@ -0,0 +1,27 @@ +interface MaginfierZoomOutProps { + className?: string; +} + +export const MaginfierZoomOutIcon = ({ className }: MaginfierZoomOutProps): JSX.Element => ( + <svg + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className={className} + > + <g clipPath="url(#clip0_4_194)"> + <path d="M6 9H15V12H6V9Z" fill="#8E92A1" /> + <path + d="M23.5605 19.9395L19.5 15.879C20.4798 14.2558 20.9985 12.396 21 10.5C21 4.71 16.2885 0 10.5 0C4.7115 0 0 4.71 0 10.5C0 16.29 4.7115 21 10.5 21C12.3962 20.9994 14.2562 20.4808 15.879 19.5L19.9395 23.5605C20.0785 23.7003 20.2437 23.8112 20.4257 23.8869C20.6077 23.9626 20.8029 24.0016 21 24.0016C21.1971 24.0016 21.3923 23.9626 21.5743 23.8869C21.7563 23.8112 21.9215 23.7003 22.0605 23.5605L23.5605 22.0605C23.6999 21.9213 23.8105 21.756 23.886 21.574C23.9615 21.3921 24.0003 21.197 24.0003 21C24.0003 20.803 23.9615 20.6079 23.886 20.426C23.8105 20.244 23.6999 20.0787 23.5605 19.9395V19.9395ZM10.5 18C8.51068 17.9998 6.60291 17.2094 5.19639 15.8026C3.78987 14.3957 2.9998 12.4878 3 10.4985C3.0002 8.50918 3.79064 6.60141 5.19745 5.19489C6.60425 3.78837 8.51218 2.9983 10.5015 2.9985C12.4908 2.9987 14.3986 3.78915 15.8051 5.19595C17.2116 6.60275 18.0017 8.51068 18.0015 10.5C18.0013 12.4893 17.2109 14.3971 15.8041 15.8036C14.3972 17.2101 12.4893 18.0002 10.5 18V18Z" + fill="#8E92A1" + /> + </g> + <defs> + <clipPath id="clip0_4_194"> + <rect width="24" height="24" fill="white" /> + </clipPath> + </defs> + </svg> +); diff --git a/src/types/iconTypes.ts b/src/types/iconTypes.ts index c37714cb64db3ae771784cd0978c5858bfdf5536..c125f09c0ea0f1cb06bb15da4037fd4d1f8e56bf 100644 --- a/src/types/iconTypes.ts +++ b/src/types/iconTypes.ts @@ -13,4 +13,7 @@ export type IconTypes = | 'page' | 'plugin' | 'close' + | 'location' + | 'magnifier-zoom-in' + | 'magnifier-zoom-out' | 'pin'; diff --git a/src/types/map.ts b/src/types/map.ts index 8dedc23f1526474dcc10d639b9e3e76312a86996..81013f9631bf84d468e0a89539747eae480f34c3 100644 --- a/src/types/map.ts +++ b/src/types/map.ts @@ -1,3 +1,5 @@ +import Map from 'ol/Map'; + export interface Point { x: number; y: number; @@ -5,3 +7,5 @@ export interface Point { } export type LatLng = [number, number]; + +export type MapInstance = Map | undefined; diff --git a/src/types/mapLayers.ts b/src/types/mapLayers.ts new file mode 100644 index 0000000000000000000000000000000000000000..d5b7bb6aaff107991b1aec21a9fd956ec00d3ed1 --- /dev/null +++ b/src/types/mapLayers.ts @@ -0,0 +1,15 @@ +/* excluded from map.ts due to depenceny cycle */ + +import { useOlMapOverlaysLayer } from '@/components/Map/MapViewer/utils/config/overlaysLayer/useOlMapOverlaysLayer'; +import { useOlMapPinsLayer } from '@/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer'; +import { useOlMapReactionsLayer } from '@/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer'; +import { useOlMapTileLayer } from '@/components/Map/MapViewer/utils/config/useOlMapTileLayer'; + +export type MapLayers = + | { + tileLayer: ReturnType<typeof useOlMapTileLayer>; + reactionsLayer: ReturnType<typeof useOlMapReactionsLayer>; + pinsLayer: ReturnType<typeof useOlMapPinsLayer>; + overlaysLayer: ReturnType<typeof useOlMapOverlaysLayer>; + } + | undefined; diff --git a/src/types/models.ts b/src/types/models.ts index 23d350f7ec57208a8053061a8e61b966a441893e..dce27badd9f02dc755462a39205f5e52abfc7545 100644 --- a/src/types/models.ts +++ b/src/types/models.ts @@ -8,7 +8,7 @@ import { compartmentPathwaySchema, } from '@/models/compartmentPathwaySchema'; import { configurationOptionSchema } from '@/models/configurationOptionSchema'; -import { configurationSchema } from '@/models/configurationSchema'; +import { configurationSchema, formatSchema } from '@/models/configurationSchema'; import { disease } from '@/models/disease'; import { drugSchema } from '@/models/drugSchema'; import { elementSearchResult, elementSearchResultType } from '@/models/elementSearchResult'; @@ -63,6 +63,7 @@ export type SessionValid = z.infer<typeof sessionSchemaValid>; export type Login = z.infer<typeof loginSchema>; export type ConfigurationOption = z.infer<typeof configurationOptionSchema>; export type Configuration = z.infer<typeof configurationSchema>; +export type ConfigurationFormatSchema = z.infer<typeof formatSchema>; export type OverlayBioEntity = z.infer<typeof overlayBioEntitySchema>; export type CreatedOverlayFile = z.infer<typeof createdOverlayFileSchema>; export type UploadedOverlayFileContent = z.infer<typeof uploadedOverlayFileContentSchema>; diff --git a/src/utils/context/mapInstanceContext.tsx b/src/utils/context/mapInstanceContext.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1c0982d8e55a4bcbafdf1416b473b43afcf9f9b9 --- /dev/null +++ b/src/utils/context/mapInstanceContext.tsx @@ -0,0 +1,40 @@ +import { MapInstance } from '@/types/map'; +import { Dispatch, SetStateAction, createContext, useContext, useMemo, useState } from 'react'; + +export interface MapInstanceContext { + mapInstance: MapInstance; + setMapInstance: Dispatch<SetStateAction<MapInstance>>; +} + +export const MapInstanceContext = createContext<MapInstanceContext>({ + mapInstance: undefined, + setMapInstance: () => {}, +}); + +export const useMapInstance = (): MapInstanceContext => useContext(MapInstanceContext); + +export interface MapInstanceProviderProps { + children: React.ReactNode; + initialValue?: MapInstanceContext; +} + +export const MapInstanceProvider = ({ + children, + initialValue, +}: MapInstanceProviderProps): JSX.Element => { + const [mapInstance, setMapInstance] = useState<MapInstance>(initialValue?.mapInstance); + + const mapInstanceContextValue = useMemo( + () => ({ + mapInstance, + setMapInstance, + }), + [mapInstance], + ); + + return ( + <MapInstanceContext.Provider value={mapInstanceContextValue}> + {children} + </MapInstanceContext.Provider> + ); +}; diff --git a/src/utils/convert/getHexStringColorFromRGBIntWithAlpha.test.ts b/src/utils/convert/getHexStringColorFromRGBIntWithAlpha.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b25bbe2aaa250963510220f32745b9f4ca3990b --- /dev/null +++ b/src/utils/convert/getHexStringColorFromRGBIntWithAlpha.test.ts @@ -0,0 +1,17 @@ +import { getHexStringColorFromRGBIntWithAlpha } from './getHexStringColorFromRGBIntWithAlpha'; + +const OPACITY_80 = 0.8; + +describe('getHexTricolorGradientColorWithAlpha ', () => { + it('should return the correct result with input with negative rgb integer', () => { + expect(getHexStringColorFromRGBIntWithAlpha({ rgbInt: -3342388, alpha: OPACITY_80 })).toEqual( + '#ccffcccc', + ); + }); + + it('should return the correct result with input with positive rgb integer', () => { + expect(getHexStringColorFromRGBIntWithAlpha({ rgbInt: 57, alpha: OPACITY_80 })).toEqual( + '#000039cc', + ); + }); +}); diff --git a/src/utils/convert/getHexStringColorFromRGBIntWithAlpha.ts b/src/utils/convert/getHexStringColorFromRGBIntWithAlpha.ts new file mode 100644 index 0000000000000000000000000000000000000000..1317bd89bb02372279f7fbafc1dc9dc28ca2b42f --- /dev/null +++ b/src/utils/convert/getHexStringColorFromRGBIntWithAlpha.ts @@ -0,0 +1,16 @@ +import { convertDecimalToHexColor } from './convertDecimalToHex'; +import { addAlphaToHexString } from './addAlphaToHexString'; + +type GetHexStringColorFromRGBIntWithAlphaProps = { + rgbInt: number; + alpha: number; +}; + +export const getHexStringColorFromRGBIntWithAlpha = ({ + rgbInt, + alpha, +}: GetHexStringColorFromRGBIntWithAlphaProps): string => { + const hexStringColor = convertDecimalToHexColor(rgbInt); + const hexStringColorWithAlpha = addAlphaToHexString(hexStringColor, alpha); + return hexStringColorWithAlpha; +}; diff --git a/src/utils/map/useSetBounds.test.ts b/src/utils/map/useSetBounds.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e00469d4c7df59c3b33135a5c6da8182b1e0db5 --- /dev/null +++ b/src/utils/map/useSetBounds.test.ts @@ -0,0 +1,109 @@ +/* eslint-disable no-magic-numbers */ +import { ONE } from '@/constants/common'; +import { MAP_DATA_INITIAL_STATE } from '@/redux/map/map.constants'; +import { renderHook } from '@testing-library/react'; +import { Map } from 'ol'; +import { Coordinate } from 'ol/coordinate'; +import { getReduxWrapperWithStore } from '../testing/getReduxWrapperWithStore'; +import { useSetBounds } from './useSetBounds'; + +describe('useSetBounds - hook', () => { + const coordinates: Coordinate[] = [ + [128, 128], + [192, 192], + ]; + + describe('when mapInstance is not set', () => { + it('setBounds should return void', () => { + const { Wrapper } = getReduxWrapperWithStore( + { + map: { + data: { + ...MAP_DATA_INITIAL_STATE, + size: { + width: 256, + height: 256, + tileSize: 256, + minZoom: 1, + maxZoom: 1, + }, + }, + loading: 'idle', + error: { + name: '', + message: '', + }, + openedMaps: [], + }, + }, + { + mapInstanceContextValue: { + mapInstance: undefined, + setMapInstance: () => {}, + }, + }, + ); + + const { + result: { current: setBounds }, + } = renderHook(() => useSetBounds(), { wrapper: Wrapper }); + + expect(setBounds(coordinates)).toBe(undefined); + }); + }); + + describe('when mapInstance is set', () => { + const dummyElement = document.createElement('div'); + const mapInstance = new Map({ target: dummyElement }); + const view = mapInstance.getView(); + const getViewSpy = jest.spyOn(mapInstance, 'getView'); + const fitSpy = jest.spyOn(view, 'fit'); + + it('setBounds should set return void', () => { + const { Wrapper } = getReduxWrapperWithStore( + { + map: { + data: { + ...MAP_DATA_INITIAL_STATE, + size: { + width: 256, + height: 256, + tileSize: 256, + minZoom: 1, + maxZoom: 1, + }, + }, + loading: 'idle', + error: { + name: '', + message: '', + }, + openedMaps: [], + }, + }, + { + mapInstanceContextValue: { + mapInstance, + setMapInstance: () => {}, + }, + }, + ); + + const { + result: { current: setBounds }, + } = renderHook(() => useSetBounds(), { wrapper: Wrapper }); + + expect(setBounds(coordinates)).toStrictEqual({ + extent: [128, 128, 192, 192], + options: { maxZoom: 1, padding: [128, 128, 128, 128], size: undefined }, + // size is real size on the screen, so it'll be undefined in the jest + }); + expect(getViewSpy).toHaveBeenCalledTimes(ONE); + expect(fitSpy).toHaveBeenCalledWith([128, 128, 192, 192], { + maxZoom: 1, + padding: [128, 128, 128, 128], + size: undefined, + }); + }); + }); +}); diff --git a/src/utils/map/useSetBounds.ts b/src/utils/map/useSetBounds.ts new file mode 100644 index 0000000000000000000000000000000000000000..29ee4727a75618bfd9cff8ba17e0ec5d727ecf1e --- /dev/null +++ b/src/utils/map/useSetBounds.ts @@ -0,0 +1,48 @@ +import { HALF } from '@/constants/dividers'; +import { DEFAULT_TILE_SIZE } from '@/constants/map'; +import { mapDataSizeSelector } from '@/redux/map/map.selectors'; +import { MapInstance } from '@/types/map'; +import { FitOptions } from 'ol/View'; +import { Coordinate } from 'ol/coordinate'; +import { Extent, boundingExtent } from 'ol/extent'; +import { useSelector } from 'react-redux'; +import { useMapInstance } from '../context/mapInstanceContext'; + +export interface SetBoundsResult { + extent: Extent; + options: FitOptions; +} + +type SetBounds = (coordinates: Coordinate[]) => SetBoundsResult | undefined; + +const BOUNDS_PADDING = DEFAULT_TILE_SIZE / HALF; +const DEFAULT_PADDING = [BOUNDS_PADDING, BOUNDS_PADDING, BOUNDS_PADDING, BOUNDS_PADDING]; + +/* prettier-ignore */ +export const handleSetBounds = + (mapInstance: MapInstance, maxZoom: number, coordinates: Coordinate[]): SetBoundsResult | undefined => { + if (!mapInstance) { + return undefined; + } + + const extent = boundingExtent(coordinates); + + const options: FitOptions = { + size: mapInstance.getSize(), + padding: DEFAULT_PADDING, + maxZoom, + }; + + mapInstance.getView().fit(extent, options); + return { extent, options }; + }; + +export const useSetBounds = (): SetBounds => { + const { mapInstance } = useMapInstance(); + const { maxZoom } = useSelector(mapDataSizeSelector); + + const setBounds = (coordinates: Coordinate[]): SetBoundsResult | undefined => + handleSetBounds(mapInstance, maxZoom, coordinates); + + return setBounds; +}; diff --git a/src/utils/point/isPointValid.test.ts b/src/utils/point/isPointValid.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa5a1809cbc1a79bbc26ca9d85d95f155fa1f9d4 --- /dev/null +++ b/src/utils/point/isPointValid.test.ts @@ -0,0 +1,21 @@ +/* eslint-disable no-magic-numbers */ +import { Point } from '@/types/map'; +import { isPointValid } from './isPointValid'; + +describe('isPointValid - util', () => { + const cases = [ + [true, 1, 1, undefined], // x, y valid, z undefined + [true, 1, 1, 1], // x, y, z valid + [false, 1, undefined, 1], // y undefined + [false, undefined, 1, 1], // x undefined + [false, undefined, undefined, 1], // x, y undefined + [false, 1, -1, 1], // y negative + [false, -1, 1, 1], // x negative + [false, -1, -1, 1], // x, y negative + [false, -1, -1, -1], // x, y, z negative + ]; + + it.each(cases)('should return %s for point x=%s, y=%s, z=%s', (result, x, y, z) => { + expect(isPointValid({ x, y, z } as Point)).toBe(result); + }); +}); diff --git a/src/utils/point/isPointValid.ts b/src/utils/point/isPointValid.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3db3d22c569c9f254a039629617b3e8889e837a --- /dev/null +++ b/src/utils/point/isPointValid.ts @@ -0,0 +1,7 @@ +import { mapPointSchema } from '@/models/mapPoint'; +import { Point } from '@/types/map'; + +export const isPointValid = (point: Point): boolean => { + const { success } = mapPointSchema.safeParse(point); + return success; +}; diff --git a/src/utils/testing/getReduxWrapperWithStore.tsx b/src/utils/testing/getReduxWrapperWithStore.tsx index d1f0c3dfe1529bbe9cb64a9d09ec1f16ac219951..18c3beb8cf9e415abdd6e5820e9360a981e1b70e 100644 --- a/src/utils/testing/getReduxWrapperWithStore.tsx +++ b/src/utils/testing/getReduxWrapperWithStore.tsx @@ -1,20 +1,29 @@ import { RootState, StoreType, middlewares, reducers } from '@/redux/store'; import { configureStore } from '@reduxjs/toolkit'; import { Provider } from 'react-redux'; +import { MapInstanceContext, MapInstanceProvider } from '../context/mapInstanceContext'; interface WrapperProps { children: React.ReactNode; } export type InitialStoreState = Partial<RootState>; +export type ReduxComponentWrapper = ({ children }: WrapperProps) => JSX.Element; +export interface Options { + mapInstanceContextValue?: MapInstanceContext; +} -export type GetReduxWrapperUsingSliceReducer = (initialState?: InitialStoreState) => { - Wrapper: ({ children }: WrapperProps) => JSX.Element; +export type GetReduxWrapperUsingSliceReducer = ( + initialState?: InitialStoreState, + options?: Options, +) => { + Wrapper: ReduxComponentWrapper; store: StoreType; }; export const getReduxWrapperWithStore: GetReduxWrapperUsingSliceReducer = ( preloadedState: InitialStoreState = {}, + options: Options = {}, ) => { const testStore = configureStore({ reducer: reducers, @@ -23,7 +32,9 @@ export const getReduxWrapperWithStore: GetReduxWrapperUsingSliceReducer = ( }); const Wrapper = ({ children }: WrapperProps): JSX.Element => ( - <Provider store={testStore}>{children}</Provider> + <MapInstanceProvider initialValue={options.mapInstanceContextValue}> + <Provider store={testStore}>{children}</Provider> + </MapInstanceProvider> ); return { Wrapper, store: testStore }; diff --git a/tailwind.config.ts b/tailwind.config.ts index 75ce9dc54480bc8bb8e9b0da255d2e772bec2ac2..80376a72e62b6e23b6a7a7d560dee0650e4d5d92 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -36,6 +36,9 @@ const config: Config = { boxShadow: { primary: '4px 8px 32px 0px rgba(0, 0, 0, 0.12)', }, + dropShadow: { + primary: '0px 4px 24px rgba(0, 0, 0, 0.08)', + }, }, fontFamily: { manrope: ['var(--font-manrope)'],