// Copyright (c) 2025-2026, RTE (https://www.rte-france.com) // This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0. // If a copy of the Mozilla Public License, version 2.0 was not distributed with this file, // you can obtain one at http://mozilla.org/MPL/2.0/. // SPDX-License-Identifier: MPL-2.0 import { describe, it, expect, vi } from 'vitest'; import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom/vitest'; import { useModalKeyboard } from './useModalKeyboard'; function Modal({ isOpen, onClose, closeOnEscape }: { isOpen: boolean; onClose: () => void; closeOnEscape?: boolean }) { const { containerRef, dialogProps } = useModalKeyboard({ isOpen, onClose, closeOnEscape }); if (!isOpen) return null; return (
); } describe('useModalKeyboard (QW20)', () => { it('stamps role="dialog" + aria-modal on the container', () => { render(); const modal = screen.getByTestId('modal'); expect(modal).toHaveAttribute('role', 'dialog'); expect(modal).toHaveAttribute('aria-modal', 'true'); }); it('calls onClose on Escape when open', () => { const onClose = vi.fn(); render(); fireEvent.keyDown(document, { key: 'Escape' }); expect(onClose).toHaveBeenCalledTimes(1); }); it('does not call onClose on Escape when closeOnEscape is false', () => { const onClose = vi.fn(); render(); fireEvent.keyDown(document, { key: 'Escape' }); expect(onClose).not.toHaveBeenCalled(); }); it('does nothing on Escape when closed', () => { const onClose = vi.fn(); render(); fireEvent.keyDown(document, { key: 'Escape' }); expect(onClose).not.toHaveBeenCalled(); }); it('moves focus into the modal on open', () => { render(); // The container (tabIndex=-1) receives focus on open. expect(screen.getByTestId('modal')).toHaveFocus(); }); it('restores focus to the trigger element on close', () => { const trigger = document.createElement('button'); document.body.appendChild(trigger); trigger.focus(); expect(trigger).toHaveFocus(); const { rerender } = render(); expect(screen.getByTestId('modal')).toHaveFocus(); rerender(); expect(trigger).toHaveFocus(); document.body.removeChild(trigger); }); it('wraps Tab from last focusable back to first (focus trap)', () => { render(); const last = screen.getByTestId('last'); last.focus(); fireEvent.keyDown(document, { key: 'Tab' }); expect(screen.getByTestId('first')).toHaveFocus(); }); it('wraps Shift+Tab from first focusable to last', () => { render(); const first = screen.getByTestId('first'); first.focus(); fireEvent.keyDown(document, { key: 'Tab', shiftKey: true }); expect(screen.getByTestId('last')).toHaveFocus(); }); });