import { act, renderHook } from "@testing-library/react"; import { wait } from "../../__test__/utils/wait"; import { InputDeviceProvider, useInputDevice } from "."; const KNOWN_ERRORS = [ "InputDeviceProvider is missing in the tree", "Consider adding an error boundary to your tree", ]; const isKnownError = (arg: unknown) => { if (typeof arg !== "string") { return; } return KNOWN_ERRORS.some((err) => arg.includes(err)); }; describe("input device hook", () => { afterEach(() => { jest.restoreAllMocks(); }); it("throws without provider", () => { const originalError = console.error; jest.spyOn(console, "error").mockImplementation((...args: unknown[]) => { if (isKnownError(args[0])) { return; } return originalError(...args); }); expect(() => renderHook(() => useInputDevice())).toThrowError( "InputDeviceProvider is missing in the tree" ); }); it("returns defined default value", () => { const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); const { result } = renderHook(() => useInputDevice("none"), { wrapper }); expect(result.current).toEqual("none"); }); it("returns mouse by default", () => { const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); const { result } = renderHook(() => useInputDevice(), { wrapper }); expect(result.current).toEqual("mouse"); }); describe("reacts on different events", () => { it("touch event 1", () => { const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); const { result, rerender } = renderHook(() => useInputDevice("def"), { wrapper }); expect(result.current).toEqual("def"); const touchEvent1 = new Event("touchmove", { bubbles: true, }) as MediaQueryListEvent; act(() => { window.dispatchEvent(touchEvent1); }); rerender(); expect(result.current).toEqual("touch"); }); it("touch event 2", () => { const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); const { result, rerender } = renderHook(() => useInputDevice("def"), { wrapper }); expect(result.current).toEqual("def"); const touchEvent2 = new Event("touchend", { bubbles: true, }) as MediaQueryListEvent; act(() => { window.dispatchEvent(touchEvent2); }); rerender(); expect(result.current).toEqual("touch"); }); it("mouse event 1", () => { const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); const { result, rerender } = renderHook(() => useInputDevice("def"), { wrapper }); expect(result.current).toEqual("def"); const mouseEvent1 = new Event("mousemove", { bubbles: true, }) as MediaQueryListEvent; act(() => { window.dispatchEvent(mouseEvent1); }); rerender(); expect(result.current).toEqual("mouse"); }); it("mouse event 2", () => { const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); const { result, rerender } = renderHook(() => useInputDevice("def"), { wrapper }); expect(result.current).toEqual("def"); const mouseEvent2 = new Event("wheel", { bubbles: true, }) as MediaQueryListEvent; act(() => { window.dispatchEvent(mouseEvent2); }); rerender(); expect(result.current).toEqual("mouse"); }); it("instantly changes from mouse to touch", () => { const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); const { result, rerender } = renderHook(() => useInputDevice("def"), { wrapper }); expect(result.current).toEqual("def"); const mouseEvent2 = new Event("wheel", { bubbles: true, }) as MediaQueryListEvent; act(() => { window.dispatchEvent(mouseEvent2); }); rerender(); expect(result.current).toEqual("mouse"); const touchEvent1 = new Event("touchmove", { bubbles: true, }) as MediaQueryListEvent; act(() => { window.dispatchEvent(touchEvent1); }); rerender(); expect(result.current).toEqual("touch"); }); it("does not instantly changes from touch to mouse to prevent bugs", async () => { const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} ); const { result, rerender } = renderHook(() => useInputDevice("def"), { wrapper }); expect(result.current).toEqual("def"); const touchEvent1 = new Event("touchmove", { bubbles: true, }) as MediaQueryListEvent; act(() => { window.dispatchEvent(touchEvent1); }); rerender(); expect(result.current).toEqual("touch"); const mouseEvent1 = new Event("wheel", { bubbles: true, }) as MediaQueryListEvent; act(() => { window.dispatchEvent(mouseEvent1); }); rerender(); expect(result.current).toEqual("touch"); await wait(350); act(() => { window.dispatchEvent(mouseEvent1); }); rerender(); expect(result.current).toEqual("mouse"); }); }); });