import React, { createRef } from 'react';
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
import { SideNav, SideNavGroup, SideNavItem } from '..';
type renderedElement = HTMLElement | null;
interface RenderedElements {
containerEl?: renderedElement;
navEl?: renderedElement;
groupEl?: renderedElement;
headerContentEl?: renderedElement;
defaultHeaderEl?: renderedElement;
itemEl?: renderedElement;
childEl?: renderedElement;
collapseToggle?: renderedElement;
}
describe('packages/side-nav', () => {
const testIds = {
sideNavContainer: 'side-nav-container',
sideNavGroup: 'side-nav-group',
sideNavHeader: 'side-nav-header',
sideNavItem: 'side-nav-item',
sideNavLink: 'side-nav-link',
collapseToggle: 'side-nav-collapse-toggle',
};
const className = 'test-class-name';
let renderedEls: RenderedElements = {};
afterEach(() => {
document.body.innerHTML = '';
renderedEls = {};
cleanup();
});
describe('SideNav', () => {
describe('when rendered to the dom', () => {
beforeEach(() => {
const {
sideNavGroup,
sideNavItem,
sideNavLink,
sideNavContainer,
collapseToggle,
} = testIds;
const { getByTestId, getByRole } = render(
Clusters
,
);
renderedEls.containerEl = getByTestId(sideNavContainer);
renderedEls.navEl = getByRole('navigation');
renderedEls.groupEl = getByTestId(sideNavGroup);
renderedEls.itemEl = getByTestId(sideNavItem);
renderedEls.childEl = getByTestId(sideNavLink);
renderedEls.collapseToggle = getByTestId(collapseToggle);
});
test('renders the side nav to the dom', () => {
expect(renderedEls.navEl).toBeInTheDocument();
});
test('renders the children of the side nav', () => {
const { groupEl, itemEl, childEl } = renderedEls;
expect(groupEl).toBeInTheDocument();
expect(itemEl).toBeInTheDocument();
expect(childEl).toBeInTheDocument();
});
test('it renders with the provided className', () => {
expect(renderedEls.containerEl).toHaveClass(className);
});
test('when the collapse toggle is clicked, the navigation is expanded', () => {
const { collapseToggle } = renderedEls;
if (collapseToggle == null) {
// TS was showing that collapseToggle could be null or undefined.
throw new ReferenceError('collapseToggle is not defined.');
}
expect(collapseToggle.getAttribute('aria-expanded')).toEqual('true');
fireEvent.click(collapseToggle);
expect(collapseToggle.getAttribute('aria-expanded')).toEqual('false');
fireEvent.click(collapseToggle);
expect(collapseToggle.getAttribute('aria-expanded')).toEqual('true');
});
});
describe('it properly handles nested SideNavItem components', () => {
test('when an active SideNavItem has nested items, they are rendered', () => {
render(
Parent
Child
,
);
expect(screen.getByText('Parent')).toBeInTheDocument();
expect(screen.getByText('Child')).toBeInTheDocument();
});
test('when an inactive SideNavItem has nested items, they are not rendered by default', () => {
render(
Parent
Child
,
);
expect(screen.getByText('Parent')).toBeInTheDocument();
expect(screen.queryByText('Children')).not.toBeInTheDocument();
});
test('when a SideNavItem has an active child, it is rendered to the DOM', () => {
render(
Parent
Child
Grandchild
,
);
expect(screen.getByText('Parent')).toBeInTheDocument();
expect(screen.getByText('Child')).toBeInTheDocument();
expect(screen.getByText('Grandchild')).toBeInTheDocument();
});
});
describe('when controlled', () => {
const setCollapsed = jest.fn();
const collapsed = true;
beforeEach(() => {
render(
Clusters
,
);
});
test('renders based on the "collapsed" props when supplied', () => {
expect(screen.getByText('Clusters')).toBeInTheDocument();
});
test('setCollapsed function is called when XX is clicked', () => {
expect(screen.getByText('Clusters')).toBeInTheDocument();
fireEvent.click(screen.getByTestId('side-nav-collapse-toggle'));
expect(setCollapsed).toHaveBeenCalled();
// it is an empty function so side nav should remain visible in the DOM
expect(screen.getByText('Clusters')).toBeInTheDocument();
});
});
test('accepts a ref', () => {
const ref = createRef();
render(Sidenav Content);
expect(ref.current).toBeDefined();
});
});
});