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");
});
});
});