import React, { FC } from "react"; import { render } from "@testing-library/react"; import usePreviousFocus, { FocusFallback } from "../usePreviousFocus"; const requestAnimationFrame = jest.spyOn(window, "requestAnimationFrame"); beforeEach(() => { requestAnimationFrame.mockClear(); // need the frame to be run sync for testing this requestAnimationFrame.mockImplementation((cb) => { cb(0); return 0; }); }); afterAll(requestAnimationFrame.mockRestore); interface TestProps { disabled: boolean; fallback?: FocusFallback; previousElement?: HTMLElement | null; } const Test: FC = ({ disabled, fallback, previousElement = null, }) => { usePreviousFocus(disabled, fallback, previousElement); return ( ); }; interface TestComponentProps extends TestProps { mounted: boolean; buttonMounted?: boolean; } const TestComponent: FC = ({ mounted, buttonMounted = true, ...props }) => { return ( <> {buttonMounted && ( )} {mounted && } ); }; describe.skip("usePreviousFocus", () => { it("should attempt to focus the previous active element in the dom when the component unmounts", () => { const { rerender, queryByText } = render( ); const button1 = queryByText("Button 1"); expect(button1).not.toBeNull(); expect(document.activeElement).toBe(button1); rerender(); const button2 = queryByText("Button 2"); expect(document.activeElement).toBe(button2); rerender(); expect(document.activeElement).toBe(button1); }); it("should request an animation frame and then check if the previous focus exists in the dom", () => { const docContains = jest.spyOn(document, "contains"); const { rerender, queryByText } = render( ); expect(requestAnimationFrame).not.toBeCalled(); rerender(); expect(requestAnimationFrame).not.toBeCalled(); // start testing unmount... rerender(); expect(requestAnimationFrame).toBeCalledTimes(1); expect(docContains).toBeCalledWith(queryByText("Button 1")); docContains.mockRestore(); }); it("should use the fallback value if the previous focus no longer exists in the dom when the component unmounts for string fallbacks", () => { const fallbackEl = document.createElement("button"); document.body.appendChild(fallbackEl); const docContains = jest.spyOn(document, "contains"); const querySelector = jest.spyOn(document, "querySelector"); querySelector.mockImplementation((query) => query === "#fallback" ? fallbackEl : null ); const { rerender, queryByText } = render( ); rerender(); const button1 = queryByText("Button 1"); docContains.mockImplementation((el) => el !== button1); rerender( ); expect(docContains).toBeCalledWith(button1); expect(querySelector).toBeCalledWith("#fallback"); expect(document.activeElement).toBe(fallbackEl); docContains.mockRestore(); document.body.removeChild(fallbackEl); }); it("should use the fallback value if the previous focus no longer exists in the dom when the component unmounts for function fallbacks", () => { const fallbackEl = document.createElement("button"); document.body.appendChild(fallbackEl); const docContains = jest.spyOn(document, "contains"); const getFallback = jest.fn(() => fallbackEl); const { rerender, queryByText } = render( ); rerender(); const button1 = queryByText("Button 1"); docContains.mockImplementation((el) => el !== button1); rerender( ); expect(docContains).toBeCalledWith(button1); expect(getFallback).toBeCalledTimes(1); expect(document.activeElement).toBe(fallbackEl); docContains.mockRestore(); document.body.removeChild(fallbackEl); }); it("should use the fallback value if the previous focus no longer exists in the dom when the component unmounts for HTMLElement fallbacks", () => { const fallbackEl = document.createElement("button"); document.body.appendChild(fallbackEl); const docContains = jest.spyOn(document, "contains"); const { rerender, queryByText } = render( ); rerender(); const button1 = queryByText("Button 1"); docContains.mockImplementation((el) => el !== button1); rerender( ); expect(docContains).toBeCalledWith(button1); expect(document.activeElement).toBe(fallbackEl); docContains.mockRestore(); document.body.removeChild(fallbackEl); }); it("should do nothing if disabled", () => { const { rerender } = render(); expect(requestAnimationFrame).not.toBeCalled(); rerender(); expect(requestAnimationFrame).not.toBeCalled(); rerender(); expect(requestAnimationFrame).not.toBeCalled(); }); });