import React, { useState, useRef } from 'react'; import { mount } from '@cypress/react'; import { useModalFocus } from '../useModalFocus'; it('keeps the focus loop inside a given modal component', () => { const Modal = () => { const ref = useRef(null); useModalFocus(ref); return (
); }; mount(
); // starts out with first modal element available cy.focused().should('have.attr', 'aria-modal', 'true') // cycles through the modal's focusable targets only cy.realPress('Tab'); cy.focused().contains('Focus 1'); cy.realPress('Tab'); cy.focused().contains('Focus 2'); cy.realPress('Tab'); cy.focused().contains('Focus 3'); cy.realPress('Tab'); cy.focused().contains('Focus 1'); cy.realPress(['Shift', 'Tab']); cy.focused().contains('Focus 3'); // prevents focus of outside elements cy.get('.outside').first().focus(); cy.focused().contains('Focus 1'); }); it('allows nested modals where the outer modal becomes inactive', () => { const ModalOne = () => { const ref = useRef(null); useModalFocus(ref); return (
); }; const ModalTwo = () => { const ref = useRef(null); useModalFocus(ref); return (
); }; mount(
); // starts out with first element available cy.focused().contains('Focus 1'); // keeps focus inside `ModalTwo` cy.realPress('Tab'); cy.focused().contains('Focus 1'); // prevents focus of `ModalOne` cy.get('.inside').first().focus(); cy.focused().contains('Focus 1'); // prevents focus of outside elements cy.get('.outside').first().focus(); cy.focused().contains('Focus 1'); }); it('allows modals in semantic order where the preceding modal becomes inactive', () => { const ModalOne = () => { const ref = useRef(null); useModalFocus(ref); return (
); }; const ModalTwo = () => { const ref = useRef(null); useModalFocus(ref); return (
); }; mount(
); // starts out with first element available cy.focused().contains('Focus 1'); // keeps focus inside `ModalTwo` cy.realPress('Tab'); cy.focused().contains('Focus 1'); // prevents focus of `ModalOne` cy.get('.inside').first().focus(); cy.focused().contains('Focus 1'); // prevents focus of outside elements cy.get('.outside').first().focus(); cy.focused().contains('Focus 1'); }); it('switches focus when nested modal closes', () => { const ModalOne = () => { const [nested, setNested] = useState(true); const ref = useRef(null); useModalFocus(ref); const onClose = () => { setNested(false); }; return (
{nested && }
); }; const ModalTwo = ({ onClose }) => { const ref = useRef(null); useModalFocus(ref); return (
); }; mount(
); // starts out with first element available cy.focused().contains('Inner Focus'); // keeps `InnerModal` focused cy.realPress('Tab'); cy.focused().contains('Inner Focus'); // switches focus when inner modal closes cy.focused().realClick(); cy.focused().contains('Outer Focus'); });