({
htmlIdGenerator: () => () => 'mockId',
@@ -31,24 +31,25 @@ jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({
const { kibana, observability, security, management } = DEFAULT_APP_CATEGORIES;
-function mockLink(label: string, category?: AppCategory) {
+function mockLink({ label = 'discover', category, onClick }: Partial) {
return {
key: label,
label,
href: label,
isActive: true,
- onClick: () => {},
+ onClick: onClick || (() => {}),
category,
'data-test-subj': label,
};
}
-function mockRecentNavLink(label: string) {
+function mockRecentNavLink({ label = 'recent', onClick }: Partial) {
return {
href: label,
label,
title: label,
'aria-label': label,
+ onClick,
};
}
@@ -67,6 +68,20 @@ function mockProps() {
};
}
+function expectShownNavLinksCount(component: ReactWrapper, count: number) {
+ expect(
+ component.find('.euiAccordion-isOpen a[data-test-subj^="collapsibleNavAppLink"]').length
+ ).toEqual(count);
+}
+
+function expectNavIsClosed(component: ReactWrapper) {
+ expectShownNavLinksCount(component, 0);
+}
+
+function clickGroup(component: ReactWrapper, group: string) {
+ component.find(`[data-test-subj="collapsibleNavGroup-${group}"] button`).simulate('click');
+}
+
describe('CollapsibleNav', () => {
// this test is mostly an "EUI works as expected" sanity check
it('renders the default nav', () => {
@@ -88,16 +103,19 @@ describe('CollapsibleNav', () => {
it('renders links grouped by category', () => {
// just a test of category functionality, categories are not accurate
const navLinks = [
- mockLink('discover', kibana),
- mockLink('siem', security),
- mockLink('metrics', observability),
- mockLink('monitoring', management),
- mockLink('visualize', kibana),
- mockLink('dashboard', kibana),
- mockLink('canvas'), // links should be able to be rendered top level as well
- mockLink('logs', observability),
+ mockLink({ label: 'discover', category: kibana }),
+ mockLink({ label: 'siem', category: security }),
+ mockLink({ label: 'metrics', category: observability }),
+ mockLink({ label: 'monitoring', category: management }),
+ mockLink({ label: 'visualize', category: kibana }),
+ mockLink({ label: 'dashboard', category: kibana }),
+ mockLink({ label: 'canvas' }), // links should be able to be rendered top level as well
+ mockLink({ label: 'logs', category: observability }),
+ ];
+ const recentNavLinks = [
+ mockRecentNavLink({ label: 'recent 1' }),
+ mockRecentNavLink({ label: 'recent 2' }),
];
- const recentNavLinks = [mockRecentNavLink('recent 1'), mockRecentNavLink('recent 2')];
const component = mount(
{
});
it('remembers collapsible section state', () => {
- function expectNavLinksCount(component: ReactWrapper, count: number) {
- expect(
- component.find('.euiAccordion-isOpen a[data-test-subj="collapsibleNavAppLink"]').length
- ).toEqual(count);
- }
-
- const navLinks = [
- mockLink('discover', kibana),
- mockLink('siem', security),
- mockLink('metrics', observability),
- mockLink('monitoring', management),
- mockLink('visualize', kibana),
- mockLink('dashboard', kibana),
- mockLink('logs', observability),
- ];
- const component = mount();
- expectNavLinksCount(component, 7);
- component.find('[data-test-subj="collapsibleNavGroup-kibana"] button').simulate('click');
- expectNavLinksCount(component, 4);
+ const navLinks = [mockLink({ category: kibana }), mockLink({ category: observability })];
+ const recentNavLinks = [mockRecentNavLink({})];
+ const component = mount(
+
+ );
+ expectShownNavLinksCount(component, 3);
+ clickGroup(component, 'kibana');
+ clickGroup(component, 'recentlyViewed');
+ expectShownNavLinksCount(component, 1);
component.setProps({ isOpen: false });
- expectNavLinksCount(component, 0); // double check the nav closed
+ expectNavIsClosed(component);
+ component.setProps({ isOpen: true });
+ expectShownNavLinksCount(component, 1);
+ });
+
+ it('closes the nav after clicking a link', () => {
+ const onClick = sinon.spy();
+ const onIsOpenUpdate = sinon.spy();
+ const navLinks = [mockLink({ category: kibana, onClick })];
+ const recentNavLinks = [mockRecentNavLink({ onClick })];
+ const component = mount(
+
+ );
+ component.setProps({
+ onIsOpenUpdate: (isOpen: boolean) => {
+ component.setProps({ isOpen });
+ onIsOpenUpdate();
+ },
+ });
+
+ component.find('[data-test-subj="collapsibleNavGroup-recentlyViewed"] a').simulate('click');
+ expect(onClick.callCount).toEqual(1);
+ expect(onIsOpenUpdate.callCount).toEqual(1);
+ expectNavIsClosed(component);
component.setProps({ isOpen: true });
- expectNavLinksCount(component, 4);
+ component.find('[data-test-subj="collapsibleNavGroup-kibana"] a').simulate('click');
+ expect(onClick.callCount).toEqual(2);
+ expect(onIsOpenUpdate.callCount).toEqual(2);
});
});
diff --git a/src/core/public/chrome/ui/header/collapsible_nav.tsx b/src/core/public/chrome/ui/header/collapsible_nav.tsx
index 9adcc19b0f0e7..81970bc4a2675 100644
--- a/src/core/public/chrome/ui/header/collapsible_nav.tsx
+++ b/src/core/public/chrome/ui/header/collapsible_nav.tsx
@@ -159,18 +159,23 @@ export function CollapsibleNav({
isCollapsible={true}
initialIsOpen={getIsCategoryOpen('recentlyViewed', storage)}
onToggle={isCategoryOpen => setIsCategoryOpen('recentlyViewed', isCategoryOpen, storage)}
+ data-test-subj="collapsibleNavGroup-recentlyViewed"
>
{recentNavLinks.length > 0 ? (
{
- // TODO #64541
- // Can remove icon from recent links completely
- const { iconType, ...linkWithoutIcon } = link;
- return linkWithoutIcon;
- })}
+ // TODO #64541
+ // Can remove icon from recent links completely
+ listItems={recentNavLinks.map(({ iconType, onClick = () => {}, ...link }) => ({
+ 'data-test-subj': 'collapsibleNavAppLink--recent',
+ onClick: (e: React.MouseEvent) => {
+ onIsOpenUpdate(false);
+ onClick(e);
+ },
+ ...link,
+ }))}
maxWidth="none"
color="subdued"
gutterSize="none"
@@ -191,7 +196,7 @@ export function CollapsibleNav({
{orderedCategories.map((categoryName, i) => {
const category = categoryDictionary[categoryName]!;
const links = allCategorizedLinks[categoryName].map(
- ({ label, href, isActive, isDisabled, onClick }: NavLink) => ({
+ ({ label, href, isActive, isDisabled, onClick }) => ({
label,
href,
isActive,
diff --git a/src/core/public/chrome/ui/header/nav_link.tsx b/src/core/public/chrome/ui/header/nav_link.tsx
index 22708c796d7dc..8003c22b99a36 100644
--- a/src/core/public/chrome/ui/header/nav_link.tsx
+++ b/src/core/public/chrome/ui/header/nav_link.tsx
@@ -142,6 +142,7 @@ export interface RecentNavLink {
title: string;
'aria-label': string;
iconType?: string;
+ onClick?(event: React.MouseEvent): void;
}
/**