import React, { FC } from "react"; import { render, fireEvent } from "@testing-library/react"; import useTabFocusWrap from "../useTabFocusWrap"; interface Props { disabled?: boolean; disableFocusCache?: boolean; onKeyDown?: React.KeyboardEventHandler; count: 1 | 2 | 3; } const Test: FC = ({ onKeyDown, disableFocusCache, disabled, count }) => { const handleKeyDown = useTabFocusWrap({ onKeyDown, disabled, disableFocusCache, }); return (
{count >= 1 && } {count >= 2 && } {count >= 3 && }
); }; describe("useTabFocusWrap", () => { it("should not focus a different element if there is only one focusable child", () => { const { getByTestId } = render(); const input = getByTestId("input-1"); input.focus(); expect(document.activeElement).toBe(input); const inputFocus = jest.spyOn(input, "focus"); fireEvent.keyDown(input, { key: "Tab" }); expect(inputFocus).not.toBeCalled(); expect(document.activeElement).toBe(input); }); it("should not override default browser behavior until the first or last element is focused", () => { const { getByTestId } = render(); const input1 = getByTestId("input-1"); const input2 = getByTestId("input-2"); const input3 = getByTestId("input-3"); // set up intial focus... input1.focus(); expect(document.activeElement).toBe(input1); // start tracking focus changes const focus1 = jest.spyOn(input1, "focus"); const focus2 = jest.spyOn(input2, "focus"); const focus3 = jest.spyOn(input3, "focus"); fireEvent.keyDown(input1, { key: "Tab" }); // can't test document.activeElement focus here since JSDom doesn't implement tab focusing expect(focus1).not.toBeCalled(); expect(focus2).not.toBeCalled(); expect(focus3).not.toBeCalled(); fireEvent.keyDown(input2, { key: "Tab" }); expect(focus1).not.toBeCalled(); expect(focus2).not.toBeCalled(); expect(focus3).not.toBeCalled(); fireEvent.keyDown(input3, { key: "Tab", shiftKey: true }); expect(focus1).not.toBeCalled(); expect(focus2).not.toBeCalled(); expect(focus3).not.toBeCalled(); fireEvent.keyDown(input2, { key: "Tab", shiftKey: true }); expect(focus1).not.toBeCalled(); expect(focus2).not.toBeCalled(); expect(focus3).not.toBeCalled(); }); it("should contain focus by wrapping around", () => { const { getByTestId } = render(); const input1 = getByTestId("input-1"); const input2 = getByTestId("input-2"); // set up intial focus... input1.focus(); expect(document.activeElement).toBe(input1); // start tracking focus changes const focus1 = jest.spyOn(input1, "focus"); const focus2 = jest.spyOn(input2, "focus"); fireEvent.keyDown(input1, { key: "Tab", shiftKey: true }); expect(document.activeElement).toBe(input2); expect(focus2).toBeCalledTimes(1); fireEvent.keyDown(input2, { key: "Tab" }); expect(document.activeElement).toBe(input1); expect(focus1).toBeCalledTimes(1); }); it("should call the optional onKeyDown function as well", () => { const onKeyDown = jest.fn(); const { getByTestId } = render(); const input1 = getByTestId("input-1"); const input2 = getByTestId("input-2"); // set up intial focus... input1.focus(); expect(document.activeElement).toBe(input1); // start tracking focus changes const focus1 = jest.spyOn(input1, "focus"); const focus2 = jest.spyOn(input2, "focus"); fireEvent.keyDown(input1, { key: "Tab", shiftKey: true }); expect(document.activeElement).toBe(input2); expect(focus2).toBeCalledTimes(1); expect(onKeyDown).toBeCalledTimes(1); // it should still be called if it's not a tab key press fireEvent.keyDown(input2, { key: "Enter" }); expect(onKeyDown).toBeCalledTimes(2); expect(focus1).not.toBeCalled(); expect(focus2).toBeCalledTimes(1); fireEvent.keyDown(input2, { key: "Tab" }); expect(document.activeElement).toBe(input1); expect(focus1).toBeCalledTimes(1); expect(onKeyDown).toBeCalledTimes(3); }); });