monday-ui-react-core
Version:
Official monday.com UI resources for application development in React.js
143 lines (113 loc) • 5.41 kB
JavaScript
import React from "react";
import { act, cleanup, renderHook } from "@testing-library/react-hooks";
import userEvent from "@testing-library/user-event";
import { NavDirections } from "../../../hooks/useFullKeyboardListeners";
import { GridKeyboardNavigationContext, useGridKeyboardNavigationContext } from "../GridKeyboardNavigationContext";
describe("GridKeyboardNavigationContext", () => {
let wrapperRef;
let ref1;
let ref2;
let ref3;
let ref4;
let ref5;
beforeEach(() => {
ref1 = createElementRef("ref1");
ref2 = createElementRef("ref2");
ref3 = createElementRef("ref3");
ref4 = createElementRef("ref4");
ref5 = createElementRef("ref5");
});
afterEach(() => {
[wrapperRef, ref1, ref2, ref3, ref4, ref5].forEach(ref => ref?.current?.remove());
cleanup();
});
describe("useGridKeyboardNavigationContext", () => {
it("should focus the element positioned on the direction of onOutboundNavigation", () => {
const positions = [{ leftElement: ref2, rightElement: ref4 }];
const keyboardDirection = NavDirections.RIGHT;
const { result } = renderHookForTest(positions);
result.current.onOutboundNavigation(ref2, keyboardDirection);
expect(ref2.current.blur).toHaveBeenCalled();
expect(ref4.current.focus).toHaveBeenCalled();
});
it("should do nothing if there is no element on the direction of onOutboundNavigation", () => {
const positions = [{ leftElement: ref2, rightElement: ref4 }];
const keyboardDirection = NavDirections.UP;
const { result } = renderHookForTest(positions);
result.current.onOutboundNavigation(ref2, keyboardDirection);
expect(ref2.current.blur).not.toHaveBeenCalled();
});
it("should do nothing if onOutboundNavigation is called when disabled", () => {
const positions = [{ leftElement: ref2, rightElement: ref4 }];
const keyboardDirection = NavDirections.RIGHT;
const { result } = renderHookForTest(positions, true);
result.current.onOutboundNavigation(ref2, keyboardDirection);
expect(ref2.current.blur).not.toHaveBeenCalled();
expect(ref4.current.blur).not.toHaveBeenCalled();
});
it("should call the upper context's onOutboundNavigation if there is no element in that direction", () => {
const positions = [{ leftElement: ref2, rightElement: ref4 }];
const keyboardDirection = NavDirections.UP;
const fakeUpperContext = { onOutboundNavigation: jest.fn() };
const { result } = renderHookWithContext(positions, fakeUpperContext);
result.current.onOutboundNavigation(ref2, keyboardDirection);
expect(fakeUpperContext.onOutboundNavigation).toHaveBeenCalledWith(wrapperRef, keyboardDirection);
});
it("should not focus any other element when the is no last direction of keyboard navigation, after the wrapper element is focused", () => {
const positions = [
{ leftElement: ref2, rightElement: ref4 },
{ topElement: ref1, rightElement: ref3 }
];
renderHookForTest(positions);
focusWrapperElement();
expect(ref1.current.focus).not.toHaveBeenCalled();
expect(ref2.current.focus).not.toHaveBeenCalled();
expect(ref3.current.focus).not.toHaveBeenCalled();
expect(ref4.current.focus).not.toHaveBeenCalled();
});
it("should do nothing if the wrapper element is focused, and the hook is disabled", () => {
const positions = [{ leftElement: ref2, rightElement: ref4 }];
renderHookForTest(positions, true);
act(() => {
userEvent.keyboard("{ArrowLeft}"); // make sure there's a value for lastNavigationDirection
});
focusWrapperElement();
expect(ref2.current.blur).not.toHaveBeenCalled();
expect(ref4.current.blur).not.toHaveBeenCalled();
});
it("should focus the element in the last direction of keyboard navigation, when the wrapper element is focused", () => {
const positions = [{ leftElement: ref2, rightElement: ref4 }];
renderHookForTest(positions);
act(() => {
userEvent.keyboard("{ArrowLeft}"); // if the user navigated left, the right-most element should be focused
});
focusWrapperElement();
expect(ref2.current.focus).not.toHaveBeenCalled();
expect(ref4.current.focus).toHaveBeenCalled();
});
function renderHookForTest(positions, disabled = false) {
wrapperRef = createElementRef("wrapper");
return renderHook(() => useGridKeyboardNavigationContext(positions, wrapperRef, { disabled }));
}
function renderHookWithContext(positions, contextValue) {
wrapperRef = createElementRef();
const wrapper = ({ children }) => (
<GridKeyboardNavigationContext.Provider value={contextValue}>{children}</GridKeyboardNavigationContext.Provider>
);
return renderHook(() => useGridKeyboardNavigationContext(positions, wrapperRef), { wrapper });
}
function focusWrapperElement() {
act(() => {
wrapperRef.current.dispatchEvent(new Event("focus")); //jsdom's .focus() isn't working as it should, so we fire our own event
});
}
});
function createElementRef(id) {
const element = document.createElement("div");
element.id = id;
document.body.appendChild(element);
jest.spyOn(element, "blur");
jest.spyOn(element, "focus");
return { current: element };
}
});