Sidemenu: Refactor SideMenuDropDown (#38554)

* SideMenuDropDown: Refactor to be more component-ey + rewrite tests in RTL

* SideMenuDropDown: Rename childLinks -> items

* Rename mockChildLinks -> mockItems as well
This commit is contained in:
Ashley Harrison 2021-08-26 14:08:27 +01:00 committed by GitHub
parent b231afd50f
commit a583f7e160
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 142 deletions

View File

@ -1,50 +1,51 @@
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { BrowserRouter } from 'react-router-dom';
import SideMenuDropDown from './SideMenuDropDown'; import SideMenuDropDown from './SideMenuDropDown';
const setup = (propOverrides?: object) => { describe('SideMenuDropDown', () => {
const props = Object.assign( const mockHeaderText = 'MyHeaderText';
const mockHeaderUrl = '/route';
const mockOnHeaderClick = jest.fn();
const mockItems = [
{ {
link: { text: 'First link',
text: 'link',
},
}, },
propOverrides {
); text: 'Second link',
},
];
return shallow(<SideMenuDropDown {...props} />); it('displays the header text', () => {
}; render(<SideMenuDropDown headerText={mockHeaderText} />);
const text = screen.getByText(mockHeaderText);
describe('Render', () => { expect(text).toBeInTheDocument();
it('should render component', () => {
const wrapper = setup();
expect(wrapper).toMatchSnapshot();
}); });
it('should render children', () => { it('attaches the link to the header text if provided', () => {
const wrapper = setup({ render(
link: { <BrowserRouter>
text: 'link', <SideMenuDropDown headerText={mockHeaderText} headerUrl={mockHeaderUrl} />
children: [{ id: 1 }, { id: 2 }, { id: 3 }], </BrowserRouter>
}, );
}); const link = screen.getByRole('link', { name: mockHeaderText });
expect(link).toBeInTheDocument();
expect(wrapper).toMatchSnapshot();
}); });
it('should not render hideFromMenu children', () => { it('calls the onHeaderClick function when the header is clicked', () => {
const wrapper = setup({ render(<SideMenuDropDown headerText={mockHeaderText} onHeaderClick={mockOnHeaderClick} />);
link: { const text = screen.getByText(mockHeaderText);
text: 'link', expect(text).toBeInTheDocument();
children: [ userEvent.click(text);
{ id: 1, hideFromMenu: false }, expect(mockOnHeaderClick).toHaveBeenCalled();
{ id: 2, hideFromMenu: true }, });
{ id: 3, hideFromMenu: false },
],
},
});
expect(wrapper).toMatchSnapshot(); it('displays the items', () => {
render(<SideMenuDropDown headerText={mockHeaderText} items={mockItems} />);
mockItems.forEach(({ text }) => {
const childItem = screen.getByText(text);
expect(childItem).toBeInTheDocument();
});
}); });
}); });

View File

@ -1,44 +1,41 @@
import React, { FC } from 'react'; import React from 'react';
import { filter } from 'lodash';
import DropDownChild from './DropDownChild'; import DropDownChild from './DropDownChild';
import { NavModelItem } from '@grafana/data'; import { NavModelItem } from '@grafana/data';
import { IconName, Link } from '@grafana/ui'; import { IconName, Link } from '@grafana/ui';
interface Props { interface Props {
link: NavModelItem; items?: NavModelItem[];
headerText: string;
headerUrl?: string;
onHeaderClick?: () => void; onHeaderClick?: () => void;
} }
const SideMenuDropDown: FC<Props> = (props) => { const SideMenuDropDown = ({ items = [], headerText, headerUrl, onHeaderClick }: Props) => {
const { link, onHeaderClick } = props; const headerContent = <span className="sidemenu-item-text">{headerText}</span>;
let childrenLinks: NavModelItem[] = []; const header = headerUrl ? (
if (link.children) { <Link href={headerUrl} onClick={onHeaderClick} className="side-menu-header-link">
childrenLinks = filter(link.children, (item) => !item.hideFromMenu); {headerContent}
}
const linkContent = <span className="sidemenu-item-text">{link.text}</span>;
const anchor = link.url ? (
<Link href={link.url} onClick={onHeaderClick} className="side-menu-header-link">
{linkContent}
</Link> </Link>
) : ( ) : (
<a onClick={onHeaderClick} className="side-menu-header-link"> <a onClick={onHeaderClick} className="side-menu-header-link">
{linkContent} {headerContent}
</a> </a>
); );
return ( return (
<ul className="dropdown-menu dropdown-menu--sidemenu" role="menu"> <ul className="dropdown-menu dropdown-menu--sidemenu" role="menu">
<li className="side-menu-header">{anchor}</li> <li className="side-menu-header">{header}</li>
{childrenLinks.map((child, index) => ( {items
<DropDownChild .filter((item) => !item.hideFromMenu)
key={`${child.url}-${index}`} .map((child, index) => (
isDivider={child.divider} <DropDownChild
icon={child.icon as IconName} key={`${child.url}-${index}`}
text={child.text} isDivider={child.divider}
url={child.url} icon={child.icon as IconName}
/> text={child.text}
))} url={child.url}
/>
))}
</ul> </ul>
); );
}; };

View File

@ -43,7 +43,7 @@ const TopSectionItem: FC<Props> = ({ link, onClick }) => {
return ( return (
<div className="sidemenu-item dropdown"> <div className="sidemenu-item dropdown">
{anchor} {anchor}
<SideMenuDropDown link={link} onHeaderClick={onClick} /> <SideMenuDropDown items={link.children} headerText={link.text} headerUrl={link.url} onHeaderClick={onClick} />
</div> </div>
); );
}; };

View File

@ -1,79 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should not render hideFromMenu children 1`] = `
<ul
className="dropdown-menu dropdown-menu--sidemenu"
role="menu"
>
<li
className="side-menu-header"
>
<a
className="side-menu-header-link"
>
<span
className="sidemenu-item-text"
>
link
</span>
</a>
</li>
<DropDownChild
key="undefined-0"
/>
<DropDownChild
key="undefined-1"
/>
</ul>
`;
exports[`Render should render children 1`] = `
<ul
className="dropdown-menu dropdown-menu--sidemenu"
role="menu"
>
<li
className="side-menu-header"
>
<a
className="side-menu-header-link"
>
<span
className="sidemenu-item-text"
>
link
</span>
</a>
</li>
<DropDownChild
key="undefined-0"
/>
<DropDownChild
key="undefined-1"
/>
<DropDownChild
key="undefined-2"
/>
</ul>
`;
exports[`Render should render component 1`] = `
<ul
className="dropdown-menu dropdown-menu--sidemenu"
role="menu"
>
<li
className="side-menu-header"
>
<a
className="side-menu-header-link"
>
<span
className="sidemenu-item-text"
>
link
</span>
</a>
</li>
</ul>
`;