feat(search drawer: content accordion): implemented content accordion with dummy data
Description
Added accordion component to search drawer to display content data. Data is dummy due to missing data in redux store which is going to be introduced in next PR
Things done
- Moved search drawer content to separate component
- Proposed dynamic loaded content to drawers in
drawer.component
- refactored drawer redux -> idea is to open drawers by triggering action "open" + "drawerName"
- added
jest-watch-typeahead
to allow search by filename during test watch - added helper function
getReduxWrapperUsingSliceReducer
to allow creation of redux store for given reducer and use it for test purposes with wrapped component
Things not done
- Decided to skip tests for search drawer content component. I'm going to introduce changes in PR where I connect data to API
Merge request reports
Activity
requested review from @AdrianOrlow and @mateuszmiko
1 1 export type DrawerState = { 2 2 open: boolean; 3 pathName: 'none' | 'search' | 'project-info' | 'plugins' | 'export' | 'legend'; 3 drawerName: 'none' | 'search' | 'project-info' | 'plugins' | 'export' | 'legend'; - Resolved by Adrian Orłów
- Resolved by Adrian Orłów
11 27 expect(screen.getByRole('drawer')).toBeInTheDocument(); 12 28 }); 13 29 14 it('should close Drawer', async () => { 30 it('should not display drawer when its not open', () => { 15 31 renderComponent(); 16 32 17 const button = screen.getByRole('close-drawer-button'); 33 expect(screen.getByRole('drawer')).not.toHaveClass('translate-x-0'); Weird conditional. Why having class
translate-x-0
defines if the drawer is opened?If we change drawer style a bit and
translate-x-0
won't be used anymore, this test will fail.IMO we should use some other conditional, for eg.
data-
attribute or class namedopened
Let's imagine scenario: You create css class
.open { @apply translate-x-0 (...other properties here) }
and in test you check for existence of the class (it might be also attribute, it's the same for this example). Now... someone works with the component and styles, and removes
@apply translate-x-0
. The test will pass but code is broken - it's false positive test. It's because you test code instead of behaviour.Translate-x-0 is now main class that is responsible for showing drawer. I know it's not perfect and it would be better to mount / dismount entire component
someone works with the component and styles, and removes
@apply translate-x-0
. The test will pass but code is broken - it's false positive test. It's because you test code instead of behaviour.That's exactly the case also right now. That is why I proposed using
opened
css class name - both in the component and its test, for eg.:expect(screen.getByRole('drawer')).not.toHaveClass('opened');
In the case above false positive result of the test is not possible, only in case if someone removes
opened
class but that's is probably impossible.
- Resolved by Adrian Orłów
29 26 role={DRAWER_ROLE} 30 27 > 31 <div className="flex items-center justify-between border-b border-b-divide px-6 py-8 text-xl"> 32 <div> 33 <span className="font-normal">Search: </span> 34 <span className="font-semibold">NADH</span> 35 </div> 36 <IconButton 37 className="bg-white-pearl" 38 classNameIcon="fill-font-500" 39 icon="close" 40 role={CLOSE_BUTTON_ROLE} 41 onClick={handleCloseDrawer} 42 /> 43 </div> 28 {open && drawerName === 'search' && <SearchDrawerContent />} There are some issues:
- If we add more conditionals like this, it will look very unclean
{open && drawerName === 'search' && <SearchDrawerContent />} {open && drawerName === 'other' && <OtherDrawerContent />} {open && drawerName === 'random' && <RandomDrawerContent />}
So I propose to exclude this logic to function and memoize it with use of useMemo to prevent unnecessary rerenders
- IMO it's a good idea to make
drawerName
a constant. If we will ever want to change some drawer content component name, it will be much easier to do this with use of a constant than a string
@teoMiesiac
isSearchDrawerOpened
is not a solution for this problem.There will be more possible drawer contents and we should not create a new function for each one of them
That's why I proposed excluding whole logic (of getting final content component) to other function and memoize it. For eg:
const getDrawerContent = (drawerName: DrawerType): React.FC => { const contentConfig: Record<DrawerType, React.FC> = { search: SearchDrawerContent, other: SearchDrawerContent, random: RandomDrawerContent } return contentConfig[drawerName] } const Content = useMemo(() => getDrawerContent(drawerName), [drawerName]) ... return ( ... {open && <Content/>} ... )
Ofc this is only an example
The second comment is not outdated IMO because it applies to readability of the code only - constant would only replace magic strings but won't change logic. In the example above:
const contentConfig: Record<DrawerType, React.FC> = { [DrawerName.Search]: SearchDrawerContent, [DrawerName.Other]: SearchDrawerContent, [DrawerName.Random]: RandomDrawerContent }
- Resolved by Tadeusz Miesiąc
mentioned in commit 66410e7a