diff --git a/.all-contributorsrc b/.all-contributorsrc index 534f3a591b6c..45ab46897104 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1277,6 +1277,15 @@ "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" + ] } ], "commitConvention": "none" diff --git a/README.md b/README.md index f1441bf2fc36..8e91d7e0a996 100644 --- a/README.md +++ b/README.md @@ -319,6 +319,7 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our
Mariat

💻
Thamjith Thaha

💻
Zoë Gathercole

💻 +
Ashna Thomas

💻 diff --git a/packages/react/src/components/UIShell/__tests__/SideNav-test.js b/packages/react/src/components/UIShell/__tests__/SideNav-test.js index 02d727ae319d..0a0d6d62cda4 100644 --- a/packages/react/src/components/UIShell/__tests__/SideNav-test.js +++ b/packages/react/src/components/UIShell/__tests__/SideNav-test.js @@ -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'; @@ -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(), @@ -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(); + expect(container.childNodes.length).toBe(1); + }); + it('should toggle the overlay-active class when `expanded` is true', () => { const { container } = render(); expect(container.firstChild).toHaveClass('cds--side-nav__overlay-active'); @@ -64,4 +69,225 @@ describe('SideNav', () => { render(); expect(ref).toHaveBeenCalledWith(screen.getByRole('navigation')); }); + + it('should call onOverlayClick when overlay is clicked', () => { + const onOverlayClick = jest.fn(); + const { container } = render( + + ); + 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( + + ); + 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(); + 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(); + const sideNav = screen.getByRole('navigation'); + expect(sideNav).toHaveClass('cds--side-nav--rail'); + }); + + it('should correctly handle `isRail` when false', () => { + render(); + const sideNav = screen.getByRole('navigation'); + expect(sideNav).not.toHaveClass('cds--side-nav--rail'); + }); + + it('should toggle the expanded state when uncontrolled', () => { + const { container } = render(); + 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( + +
No Errors Here!
+
+ ); + expect(container).toBeInTheDocument(); + }); + + it('should pass isSideNavExpanded to Carbon SideNav children', () => { + const TestChild = React.forwardRef(({ isSideNavExpanded }, ref) => ( +
+ {isSideNavExpanded ? 'Expanded' : 'Collapsed'} +
+ )); + render( + + + + ); + expect(screen.getByTestId('child')).toHaveTextContent('Collapsed'); + }); + + it('should not pass isSideNavExpanded to non-CarbsideNav children', () => { + const NonCarbonChild = () =>
; + render( + + + + ); + expect(screen.getByTestId('non-carbon-child')).toBeInTheDocument(); + }); + + it('should pass isSideNavExpanded correctly based on controlled state', () => { + const TestChild = React.forwardRef(({ isSideNavExpanded }, ref) => ( +
+ {isSideNavExpanded ? 'Expanded' : 'Collapsed'} +
+ )); + const { rerender } = render( + + + + ); + expect(screen.getByTestId('child')).toHaveTextContent('Collapsed'); + rerender( + + + + ); + expect(screen.getByTestId('child')).toHaveTextContent('Collapsed'); + }); + + it('should call handleToggle and onSideNavBlur when blurred', () => { + const onSideNavBlurMock = jest.fn(); + const TestChild = () =>
Child
; + const { getByRole } = render( + + + + ); + 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 = () =>
Child
; + const { getByRole } = render( + + + + ); + 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 = () =>
Child
; + const { getByRole } = render( + + + + ); + 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 = () =>
Child
; + const { getByRole } = render( + + + + ); + 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 = () =>
Child
; + const { getByRole } = render( + + + + ); + const sideNav = getByRole('navigation'); + expect(sideNav).toHaveClass('cds--side-nav__navigation'); + fireEvent.mouseLeave(sideNav); + expect(sideNav).toHaveClass('cds--side-nav__navigation'); + }); + + it('should not call handleToggle if isRail is false', () => { + const onToggleMock = jest.fn(); + const TestChild = () =>
Child
; + const { getByRole } = render( + + + + ); + const sideNav = getByRole('navigation'); + fireEvent.mouseLeave(sideNav); + expect(onToggleMock).not.toHaveBeenCalled(); + }); + + it('should expand the SideNav immediately on click', () => { + const TestChild = () =>
Child
; + const onToggleMock = jest.fn(); + const { getByRole } = render( + + + + ); + 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'); + }); });