import * as React from 'react' import { render, screen } from '@testing-library/react' import '@testing-library/jest-dom' import { CFocusTrap } from '../CFocusTrap' // Helper function to create a test component with focusable elements interface TestComponentProps { children?: React.ReactNode [key: string]: any } const TestComponent = ({ children, ...props }: TestComponentProps) => (
Link {children}
) describe('CFocusTrap', () => { beforeEach(() => { // Reset document focus before each test document.body.focus() }) test('loads and displays CFocusTrap component', () => { const { container } = render(
Test Content
) expect(container).toMatchSnapshot() expect(screen.getByTestId('test-content')).toBeInTheDocument() }) test('CFocusTrap with custom props', () => { const onActivate = jest.fn() const onDeactivate = jest.fn() const { container } = render(
Custom Content
) expect(container).toMatchSnapshot() expect(onActivate).toHaveBeenCalledTimes(1) }) test('focuses container when focusFirstElement is false (default)', () => { const mockFocus = jest.fn() const originalFocus = HTMLElement.prototype.focus HTMLElement.prototype.focus = mockFocus render() const container = screen.getByTestId('container') expect(container).toBeInTheDocument() expect(mockFocus).toHaveBeenCalledWith({ preventScroll: true }) HTMLElement.prototype.focus = originalFocus }) test('does not trap focus when active is false', () => { render() // Focus should not be moved to any element expect(screen.getByTestId('container')).not.toHaveFocus() expect(screen.getByTestId('first-button')).not.toHaveFocus() }) test('handles container with no tabbable elements', () => { const mockFocus = jest.fn() const originalFocus = HTMLElement.prototype.focus HTMLElement.prototype.focus = mockFocus render(
No focusable elements
) const container = screen.getByTestId('empty-container') expect(container).toBeInTheDocument() expect(mockFocus).toHaveBeenCalledWith({ preventScroll: true }) HTMLElement.prototype.focus = originalFocus }) test('calls onActivate callback when trap becomes active', () => { const onActivate = jest.fn() const { rerender } = render() expect(onActivate).not.toHaveBeenCalled() // Re-render with active=true rerender() expect(onActivate).toHaveBeenCalledTimes(1) }) test('calls onDeactivate callback when trap becomes inactive', () => { const onDeactivate = jest.fn() const { rerender } = render() expect(onDeactivate).not.toHaveBeenCalled() // Deactivate the trap rerender() expect(onDeactivate).toHaveBeenCalledTimes(1) }) test('cleans up event listeners on unmount', () => { const removeEventListenerSpy = jest.spyOn(document, 'removeEventListener') const { unmount } = render() unmount() expect(removeEventListenerSpy).toHaveBeenCalledWith('focusin', expect.any(Function), true) removeEventListenerSpy.mockRestore() }) test('focuses first element when focusFirstElement is true', () => { const mockFocus = jest.fn() const originalFocus = HTMLElement.prototype.focus HTMLElement.prototype.focus = mockFocus render() const firstButton = screen.getByTestId('first-button') expect(firstButton).toBeInTheDocument() expect(mockFocus).toHaveBeenCalledWith({ preventScroll: true }) HTMLElement.prototype.focus = originalFocus }) test('works with additionalContainer prop', () => { const additionalRef = React.createRef() render(
) const mainContainer = screen.getByTestId('main-container') const additionalContainer = screen.getByTestId('additional-container') expect(mainContainer).toBeInTheDocument() expect(additionalContainer).toBeInTheDocument() }) test('restores focus when restoreFocus is true', () => { // Mock document.activeElement to simulate a focused element const focusButton = document.createElement('button') focusButton.dataset.testid = 'focus-button' document.body.appendChild(focusButton) const mockFocus = jest.fn() focusButton.focus = mockFocus // Mock document.activeElement Object.defineProperty(document, 'activeElement', { value: focusButton, writable: true, configurable: true, }) const { rerender } = render() // Activate the trap (should store the previous focused element) rerender() // Deactivate the trap (should restore focus) rerender() // Verify focus restoration was attempted expect(mockFocus).toHaveBeenCalledWith({ preventScroll: true }) focusButton.remove() }) test('does not restore focus when restoreFocus is false', () => { // Mock document.activeElement to simulate a focused element const focusButton = document.createElement('button') focusButton.dataset.testid = 'focus-button' document.body.appendChild(focusButton) const mockFocus = jest.fn() focusButton.focus = mockFocus // Mock document.activeElement Object.defineProperty(document, 'activeElement', { value: focusButton, writable: true, configurable: true, }) const { rerender } = render() // Activate the trap (should store the previous focused element) rerender() // Deactivate the trap (should NOT restore focus) rerender() // Verify focus restoration was not attempted expect(mockFocus).not.toHaveBeenCalledWith({ preventScroll: true }) focusButton.remove() }) })