Skip to content

Commit

Permalink
test(SideNav): #17491 increased unit test coverage (#17869)
Browse files Browse the repository at this point in the history
* test(SideNav): #17491 increased unit test coverage

* test(SideNav): #17491 increased unit test coverage

* test(SideNav): increased coverage

* Update packages/react/src/components/UIShell/__tests__/SideNav-test.js

* Update packages/react/src/components/UIShell/__tests__/SideNav-test.js

* Update packages/react/src/components/UIShell/__tests__/SideNav-test.js

* fix(test): format

---------

Co-authored-by: Ariella Gilmore <[email protected]>
Co-authored-by: Nikhil Tomar <[email protected]>
  • Loading branch information
3 people authored Dec 6, 2024
1 parent 5c44a20 commit 224b1e6
Show file tree
Hide file tree
Showing 3 changed files with 283 additions and 3 deletions.
7 changes: 7 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -1721,6 +1721,13 @@
"name": "Zoë Gathercole",
"avatar_url": "https://avatars.githubusercontent.com/u/56911544?v=4",
"profile": "https://github.com/Zoe-Gathercole",
"contributions": ["code"]
},
{
"login": "ashna000",
"name": "Ashna Thomas",
"avatar_url": "https://avatars.githubusercontent.com/u/12691034?s=96&v=4",
"profile": "https://github.com/ashna000",
"contributions": [
"code"
]
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our
<td align="center"><a href="https://github.com/Zoe-Gathercole"><img src="https://avatars.githubusercontent.com/u/56911544?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zoë Gathercole</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=Zoe-Gathercole" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/a88zach"><img src="https://avatars.githubusercontent.com/u/1724822?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zach Tindall</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=a88zach" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ashna000"><img src="https://avatars.githubusercontent.com/u/12691034?s=96&v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ashna Thomas</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=ashna000" title="Code">💻</a></td>
</tr>
</table>

<!-- markdownlint-restore -->
Expand Down
276 changes: 273 additions & 3 deletions packages/react/src/components/UIShell/__tests__/SideNav-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import { render, screen } from '@testing-library/react';
import { render, screen, fireEvent } from '@testing-library/react';
import React from 'react';
import SideNav from '../SideNav';

Expand All @@ -15,8 +15,8 @@ Object.defineProperty(window, 'matchMedia', {
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
Expand All @@ -36,6 +36,11 @@ describe('SideNav', () => {
expect(container.childNodes.length).toBe(2);
});

it('should not render an overlay if `isFixedNav` is true', () => {
const { container } = render(<SideNav aria-label="test" isFixedNav />);
expect(container.childNodes.length).toBe(1);
});

it('should toggle the overlay-active class when `expanded` is true', () => {
const { container } = render(<SideNav aria-label="test" expanded />);
expect(container.firstChild).toHaveClass('cds--side-nav__overlay-active');
Expand Down Expand Up @@ -64,4 +69,269 @@ describe('SideNav', () => {
render(<SideNav aria-label="test" ref={ref} />);
expect(ref).toHaveBeenCalledWith(screen.getByRole('navigation'));
});

it('should call onOverlayClick when overlay is clicked', () => {
const onOverlayClick = jest.fn();
const { container } = render(
<SideNav aria-label="test" expanded onOverlayClick={onOverlayClick} />
);
const overlay = container.firstChild;
fireEvent.click(overlay);
expect(onOverlayClick).toHaveBeenCalledTimes(1);
});

it('should not add focus or mouse listeners when disabled', () => {
const onToggle = jest.fn();
render(
<SideNav
aria-label="test"
addFocusListeners={false}
addMouseListeners={false}
onToggle={onToggle}
/>
);
const sideNav = screen.getByRole('navigation');
fireEvent.focus(sideNav);
fireEvent.mouseEnter(sideNav);
expect(onToggle).not.toHaveBeenCalled();
});

it('should handle keyboard events like Escape', () => {
const onToggle = jest.fn();
render(
<SideNav
aria-label="test"
expanded
onToggle={onToggle}
href="#main-content"
/>
);
const sideNav = screen.getByRole('navigation');
fireEvent.keyDown(sideNav, { key: 'Escape', keyCode: 27 });
expect(onToggle).toHaveBeenCalledWith(expect.anything(), false);
});

it('should correctly handle `isRail` when true', () => {
render(<SideNav aria-label="test" isRail />);
const sideNav = screen.getByRole('navigation');
expect(sideNav).toHaveClass('cds--side-nav--rail');
});

it('should correctly handle `isRail` when false', () => {
render(<SideNav aria-label="test" isRail={false} />);
const sideNav = screen.getByRole('navigation');
expect(sideNav).not.toHaveClass('cds--side-nav--rail');
});

it('should toggle the expanded state when uncontrolled', () => {
const { container } = render(<SideNav aria-label="test" />);
const sideNav = screen.getByRole('navigation');
fireEvent.focus(sideNav);
expect(container.firstChild).toHaveClass('cds--side-nav__overlay');
});

it('should handle children without throwing error', () => {
const { container } = render(
<SideNav aria-label="test">
<div>No Errors Here!</div>
</SideNav>
);
expect(container).toBeInTheDocument();
});

it('should pass isSideNavExpanded to Carbon SideNav children', () => {
const TestChild = React.forwardRef(({ isSideNavExpanded }, ref) => (
<div data-testid="child" ref={ref}>
{isSideNavExpanded ? 'Expanded' : 'Collapsed'}
</div>
));
render(
<SideNav aria-label="test" expanded>
<TestChild />
</SideNav>
);
expect(screen.getByTestId('child')).toHaveTextContent('Collapsed');
});

it('should not pass isSideNavExpanded to non-CarbsideNav children', () => {
const NonCarbonChild = () => <div data-testid="non-carbon-child" />;
render(
<SideNav aria-label="test" expanded>
<NonCarbonChild />
</SideNav>
);
expect(screen.getByTestId('non-carbon-child')).toBeInTheDocument();
});

it('should pass isSideNavExpanded correctly based on controlled state', () => {
const TestChild = React.forwardRef(({ isSideNavExpanded }, ref) => (
<div data-testid="child" ref={ref}>
{isSideNavExpanded ? 'Expanded' : 'Collapsed'}
</div>
));
const { rerender } = render(
<SideNav aria-label="test" expanded>
<TestChild />
</SideNav>
);
expect(screen.getByTestId('child')).toHaveTextContent('Collapsed');
rerender(
<SideNav aria-label="test">
<TestChild />
</SideNav>
);
expect(screen.getByTestId('child')).toHaveTextContent('Collapsed');
});

it('should call handleToggle and onSideNavBlur when blurred', () => {
const onSideNavBlurMock = jest.fn();
const TestChild = () => <div data-testid="child">Child</div>;
const { getByRole } = render(
<SideNav aria-label="test" onSideNavBlur={onSideNavBlurMock}>
<TestChild />
</SideNav>
);
const sideNav = getByRole('navigation');
fireEvent.focus(sideNav);
fireEvent.blur(sideNav);
expect(onSideNavBlurMock).not.toHaveBeenCalled();
});

it('should not call onSideNavBlur if not expanded and isFixedNav is true', () => {
const onSideNavBlurMock = jest.fn();
const TestChild = () => <div data-testid="child">Child</div>;
const { getByRole } = render(
<SideNav aria-label="test" isFixedNav onSideNavBlur={onSideNavBlurMock}>
<TestChild />
</SideNav>
);
const sideNav = getByRole('navigation');
fireEvent.focus(sideNav);
fireEvent.blur(sideNav);
expect(onSideNavBlurMock).not.toHaveBeenCalled();
});

it('should call onSideNavBlur when blurred, is not fixed, and is expanded', () => {
const onSideNavBlurMock = jest.fn();
const TestChild = () => <div data-testid="child">Child</div>;
const { getByRole } = render(
<SideNav
aria-label="test"
onSideNavBlur={onSideNavBlurMock}
defaultExpanded>
<TestChild />
</SideNav>
);
const sideNav = getByRole('navigation');
fireEvent.focus(sideNav);
const unrelatedElement = document.createElement('div');
document.body.appendChild(unrelatedElement);
fireEvent.blur(sideNav, { relatedTarget: unrelatedElement });
expect(onSideNavBlurMock).toHaveBeenCalled();
document.body.removeChild(unrelatedElement);
});

it('should not call onSideNavBlur when isFixedNav is true', () => {
const onSideNavBlurMock = jest.fn();
const TestChild = () => <div data-testid="child">Child</div>;
const { getByRole } = render(
<SideNav
aria-label="test"
isFixedNav
onSideNavBlur={onSideNavBlurMock}
defaultExpanded>
<TestChild />
</SideNav>
);
const sideNav = getByRole('navigation');
fireEvent.focus(sideNav);
const unrelatedElement = document.createElement('div');
document.body.appendChild(unrelatedElement);
fireEvent.blur(sideNav, { relatedTarget: unrelatedElement });
expect(onSideNavBlurMock).not.toHaveBeenCalled();
document.body.removeChild(unrelatedElement);
});

it('should set expanded state to false on mouse leave', () => {
const onToggleMock = jest.fn();
const TestChild = () => <div data-testid="child">Child</div>;
const { getByRole } = render(
<SideNav aria-label="test" defaultExpanded onToggle={onToggleMock}>
<TestChild />
</SideNav>
);
const sideNav = getByRole('navigation');
expect(sideNav).toHaveClass('cds--side-nav__navigation');
fireEvent.mouseLeave(sideNav);
expect(sideNav).toHaveClass('cds--side-nav__navigation');
});

it('should handleToggle if isRail is true', () => {
const onToggleMock = jest.fn();
const TestChild = () => <div data-testid="child">Child</div>;
const { getByRole } = render(
<SideNav aria-label="test" onToggle={onToggleMock} isRail>
<TestChild />
</SideNav>
);
const sideNav = getByRole('navigation');
fireEvent.focus(sideNav);
expect(onToggleMock).toHaveBeenCalled();
fireEvent.mouseLeave(sideNav);
expect(onToggleMock).toHaveBeenCalledWith(false, false);
fireEvent.mouseEnter(sideNav);
expect(onToggleMock).toHaveBeenCalledWith(true, true);
});

it('should not call handleToggle if isRail is false', () => {
const onToggleMock = jest.fn();
const TestChild = () => <div data-testid="child">Child</div>;
const { getByRole } = render(
<SideNav
aria-label="test"
defaultExpanded
onToggle={onToggleMock}
isRail={false}>
<TestChild />
</SideNav>
);
const sideNav = getByRole('navigation');
fireEvent.mouseLeave(sideNav);
expect(onToggleMock).not.toHaveBeenCalled();
});

it('should expand the SideNav immediately on click', () => {
const TestChild = () => <div data-testid="child">Child</div>;
const onToggleMock = jest.fn();
const { getByRole } = render(
<SideNav aria-label="test" onToggle={onToggleMock} isRail>
<TestChild />
</SideNav>
);
const sideNav = getByRole('navigation');
expect(sideNav).not.toHaveClass('cds--side-nav--expanded');
fireEvent.click(sideNav);
expect(onToggleMock).toHaveBeenCalledWith(true, true);
expect(sideNav).toHaveClass('cds--side-nav--expanded');
});

it('should focus SideNav after tabbing from headerMenuButton', () => {
render(
<>
<button className="cds--header__menu-toggle"></button>
<SideNav
aria-label="test"
expanded
isFixedNav={false}
defaultExpanded
/>
</>
);
const mockHeaderMenuButton = screen.getByRole('button');
const sideNav = screen.getByRole('navigation');

mockHeaderMenuButton.focus();
fireEvent.keyDown(window, { key: 'Tab' });
expect(document.activeElement).toBe(sideNav);
});
});

0 comments on commit 224b1e6

Please sign in to comment.