@testing-library/react-hooks#cleanup JavaScript Examples

The following examples show how to use @testing-library/react-hooks#cleanup. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: avatar.jest.js    From monday-ui-react-core with MIT License 6 votes vote down vote up
describe("avatar", () => {
  afterEach(() => {
    cleanup();
  });

  it("onClick callback should be called after clicking the element", () => {
    const onClickCallback = jest.fn();
    const { getByTestId } = renderComponent({ onClick: onClickCallback });
    const component = getByTestId(ELEMENT_TYPES.CLICKABLE);
    fireEvent.click(component);
    expect(onClickCallback.mock.calls.length).toBe(1);
  });
});
Example #2
Source File: useActiveDescendantListFocus.jest.js    From monday-ui-react-core with MIT License 6 votes vote down vote up
describe("useActiveDescendantListFocus", () => {
  afterEach(() => {
    element.remove();
    cleanup();
  });

  describe("Vertical list", () => {
    const isHorizontal = false;
    runListUnitTest(isHorizontal);
  });
  describe("Horizontal list", () => {
    const isHorizontal = true;
    runListUnitTest(isHorizontal);
  });
});
Example #3
Source File: useClickOutside.jest.js    From monday-ui-react-core with MIT License 5 votes vote down vote up
describe("useClickOutside", () => {
  let element;
  let callbackStub;

  beforeEach(() => {
    callbackStub = jest.fn();
    element = document.createElement("div");
    document.body.appendChild(element);
    renderHook(() => useOnClickOutside({ ref: { current: element }, callback: callbackStub }));
  });

  afterEach(() => {
    element.remove();
    cleanup();
  });
  describe("mouseDown", () => {
    it("should call the callback when click outside the element", () => {
      act(() => {
        fireEvent.click(document.body);
      });
      return expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it("should not call the callback when clicking the element", () => {
      act(() => {
        fireEvent.click(element);
      });
      return expect(callbackStub.mock.calls.length).toEqual(0);
    });
  });

  describe("touchStart", () => {
    it("should call the callback when click outside the element", () => {
      act(() => {
        fireEvent.touchEnd(document.body);
      });
      return expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it("should not call the callback when clicking the element", () => {
      act(() => {
        fireEvent.touchEnd(element);
      });
      return expect(callbackStub.mock.calls.length).toEqual(0);
    });
  });
});
Example #4
Source File: GridKeyboardNavigationContext.jest.js    From monday-ui-react-core with MIT License 4 votes vote down vote up
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 = NAV_DIRECTIONS.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 = NAV_DIRECTIONS.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 = NAV_DIRECTIONS.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 = NAV_DIRECTIONS.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 };
  }
});
Example #5
Source File: useFocusGridItemByActiveStatus.jest.js    From monday-ui-react-core with MIT License 4 votes vote down vote up
describe("useFocusGridItemByActiveStatus", () => {
  let element, childElement, wrapperRef, childRef;

  beforeEach(() => {
    element = document.createElement("div");
    document.body.appendChild(element);
    jest.spyOn(element, "blur");
    jest.spyOn(element, "focus");

    childElement = document.createElement("input");
    element.appendChild(childElement);
    jest.spyOn(childElement, "focus");

    wrapperRef = { current: element };
    childRef = { current: childElement };

    jest.spyOn(useLastNavigationDirectionModule, "useLastNavigationDirection");
  });

  afterEach(() => {
    element.remove();
    childElement.remove();
    cleanup();
    jest.restoreAllMocks();
  });

  it("it should blur the wrapper element if index != activeItemIndex", () => {
    renderHook(() => useFocusGridItemByActiveStatus({ index: 0, activeItemIndex: 1, wrapperRef, childRef }));

    expect(element.blur).toHaveBeenCalledTimes(1);
  });

  it("it should do nothing if useDocumentEventListeners and index != activeItemIndex", () => {
    renderHook(() =>
      useFocusGridItemByActiveStatus({
        index: 0,
        activeItemIndex: 1,
        wrapperRef,
        childRef,
        useDocumentEventListeners: true
      })
    );

    expect(element.blur).not.toHaveBeenCalled();
    expect(element.focus).not.toHaveBeenCalled();
  });

  it("it should blur the wrapper element if activeItemIndex changes from the given index to a different one", () => {
    const props = { index: 0, activeItemIndex: 0, wrapperRef, childRef };
    const { rerender } = renderHook(() => useFocusGridItemByActiveStatus(props));
    expect(element.blur).not.toBeCalled();

    props.activeItemIndex = props.index + 1;
    rerender();

    expect(element.blur).toHaveBeenCalledTimes(1);
  });

  it("should focus the child element, with current direction, when mounting and index === activeItemIndex", () => {
    mockLastNavigationDirection("some direction");
    renderHook(() => useFocusGridItemByActiveStatus({ index: 1, activeItemIndex: 1, wrapperRef, childRef }));

    expect(childElement.focus).toHaveBeenCalledTimes(1);
  });

  it("should focus the child element, with current direction, when activeItemIndex changes to given index", () => {
    mockLastNavigationDirection("some direction");
    const props = { index: 1, activeItemIndex: 0, wrapperRef, childRef };
    const { rerender } = renderHook(() => useFocusGridItemByActiveStatus(props));
    expect(childElement.focus).not.toHaveBeenCalled();

    props.activeItemIndex = props.index;
    rerender();

    expect(childElement.focus).toHaveBeenCalledTimes(1);
  });

  function mockLastNavigationDirection(currentDirectionValue) {
    useLastNavigationDirectionModule.useLastNavigationDirection.mockReturnValue({
      lastNavigationDirectionRef: { current: currentDirectionValue }
    });
  }
});
Example #6
Source File: useMenuGridItemNavContext.jest.js    From monday-ui-react-core with MIT License 4 votes vote down vote up
describe("useMenuGridItemNavContext", () => {
  let element;
  let elementRef;

  beforeEach(() => {
    element = document.createElement("div");
    document.body.appendChild(element);

    elementRef = { current: element };
  });

  afterEach(() => {
    element.remove();
    cleanup();
    jest.resetAllMocks();
  });

  describe("onOutboundNavigation", () => {
    const outBoundingElement = document.createElement("span");

    it("should call the parent GridKeyboardNavigationContext", () => {
      const mockedInnerUseContext = { onOutboundNavigation: jest.fn() };
      const { result } = renderHookForTest({ mockedInnerUseContext });

      result.current.onOutboundNavigation(outBoundingElement, NAV_DIRECTIONS.UP);

      expect(mockedInnerUseContext.onOutboundNavigation).toHaveBeenCalledWith(outBoundingElement, NAV_DIRECTIONS.UP);
    });

    it("should set the previous item as active when navigating up", () => {
      const getPreviousSelectableIndex = jest.fn().mockReturnValue(10);
      const setActiveItemIndex = jest.fn();
      const { result } = renderHookForTest({ activeItemIndex: 15, getPreviousSelectableIndex, setActiveItemIndex });

      result.current.onOutboundNavigation(outBoundingElement, NAV_DIRECTIONS.UP);

      expect(getPreviousSelectableIndex).toHaveBeenCalledTimes(1);
      expect(getPreviousSelectableIndex).toHaveBeenCalledWith(15);
      expect(setActiveItemIndex).toHaveBeenCalledTimes(1);
      expect(setActiveItemIndex).toHaveBeenCalledWith(10);
    });

    it("should set the next item as active when navigating down", () => {
      const getNextSelectableIndex = jest.fn().mockReturnValue(20);
      const setActiveItemIndex = jest.fn();
      const { result } = renderHookForTest({ activeItemIndex: 15, getNextSelectableIndex, setActiveItemIndex });

      result.current.onOutboundNavigation(outBoundingElement, NAV_DIRECTIONS.DOWN);

      expect(getNextSelectableIndex).toHaveBeenCalledTimes(1);
      expect(getNextSelectableIndex).toHaveBeenCalledWith(15);
      expect(setActiveItemIndex).toHaveBeenCalledTimes(1);
      expect(setActiveItemIndex).toHaveBeenCalledWith(20);
    });

    it("should do nothing when not under a sub menu and pressing left", () => {
      const setActiveItemIndex = jest.fn();
      const closeMenu = jest.fn();
      const { result } = renderHookForTest({ setActiveItemIndex, closeMenu });

      result.current.onOutboundNavigation(outBoundingElement, NAV_DIRECTIONS.LEFT);

      expect(setActiveItemIndex).not.toHaveBeenCalled();
      expect(closeMenu).not.toHaveBeenCalled();
    });

    it("should close the sub menu and pressing left", () => {
      const closeMenu = jest.fn();
      const { result } = renderHookForTest({ closeMenu, isUnderSubMenu: true });

      result.current.onOutboundNavigation(outBoundingElement, NAV_DIRECTIONS.LEFT);

      expect(closeMenu).toHaveBeenCalledTimes(1);
    });

    function renderHookForTest({
      setActiveItemIndex = jest.fn(),
      getNextSelectableIndex = jest.fn(),
      getPreviousSelectableIndex = jest.fn(),
      activeItemIndex = 0,
      isUnderSubMenu = false,
      closeMenu = jest.fn(),
      mockedInnerUseContext = { onOutboundNavigation: jest.fn() }
    }) {
      jest
        .spyOn(GridKeyboardNavigationContextModule, "useGridKeyboardNavigationContext")
        .mockReturnValue(mockedInnerUseContext);

      return renderHook(() =>
        useMenuGridItemNavContext({
          wrapperRef: elementRef,
          setActiveItemIndex,
          getNextSelectableIndex,
          getPreviousSelectableIndex,
          activeItemIndex,
          isUnderSubMenu,
          closeMenu
        })
      );
    }
  });
});
Example #7
Source File: useDebounceEvent.jest.js    From monday-ui-react-core with MIT License 4 votes vote down vote up
describe("useDebounceEvent", () => {
  const delay = 0;
  const initialStateValue = "";
  let onChangeCallbackStub;
  let hookResult;

  beforeEach(() => {
    onChangeCallbackStub = jest.fn();
    hookResult = renderHook(() =>
      useDebounceEvent({
        delay,
        initialStateValue,
        onChange: onChangeCallbackStub
      })
    );
  });

  afterEach(() => {
    cleanup();
  });

  describe("return types", () => {
    it("should give a callback function", () => {
      expect(typeof hookResult.result.current.onEventChanged).toEqual("function");
    });

    it("should give a clear function", () => {
      expect(typeof hookResult.result.current.clearValue).toEqual("function");
    });

    it("should give a update function", () => {
      expect(typeof hookResult.result.current.updateValue).toEqual("function");
    });

    it("should give the value ", () => {
      expect(typeof hookResult.result.current.inputValue).toEqual("string");
    });
  });
  describe("updating the value with input event", () => {
    it("should update the value", () => {
      const { onEventChanged } = hookResult.result.current;
      const newInputValue = "input value";

      act(() => {
        onEventChanged(getEventObject(newInputValue));
      });

      expect(hookResult.result.current.inputValue).toEqual(newInputValue);
    });

    it("should trim the value", () => {
      const hookRes = renderHook(() =>
        useDebounceEvent({
          delay: 0,
          trim: true,
          onChange: onChangeCallbackStub,
          initialStateValue: ""
        })
      );

      const { onEventChanged } = hookRes.result.current;
      const newInputValue = "value     ";
      act(() => {
        onEventChanged(getEventObject(newInputValue));
      });
      expect(hookRes.result.current.inputValue).toEqual(newInputValue.trim());
    });

    it("should clear the value", () => {
      const { clearValue } = hookResult.result.current;

      act(() => {
        clearValue();
      });

      expect(hookResult.result.current.inputValue).toEqual("");
    });

    it("should call onChange with the correct value", () => {
      const { onEventChanged } = hookResult.result.current;
      const newInputValue = "input value";

      act(() => {
        onEventChanged(getEventObject(newInputValue));
      });

      expect(onChangeCallbackStub.mock.calls[0][0]).toEqual(newInputValue);
    });
  });
  describe("debounced", () => {
    const additionalDelay = 200;

    beforeEach(() => {
      jest.useFakeTimers("modern");

      hookResult = renderHook(() =>
        useDebounceEvent({
          delay: additionalDelay,
          initialStateValue,
          onChange: onChangeCallbackStub
        })
      );
    });

    afterEach(() => {
      jest.useRealTimers();
    });

    it("should not call the onChange immediately ", () => {
      const { onEventChanged } = hookResult.result.current;
      const newInputValue = "input value";
      act(() => {
        onEventChanged(getEventObject(newInputValue));
      });
      expect(onChangeCallbackStub.mock.calls.length).toEqual(0);
    });

    it("should not call the onChange before the timer passes ", () => {
      const { onEventChanged } = hookResult.result.current;
      const newInputValue = "input value";
      act(() => {
        onEventChanged(getEventObject(newInputValue));
      });
      jest.advanceTimersByTime(additionalDelay - 1);

      expect(onChangeCallbackStub.mock.calls.length).toEqual(0);
    });

    it("should be called after the timeout ", () => {
      const { onEventChanged } = hookResult.result.current;
      const newInputValue = "input value";
      act(() => {
        onEventChanged(getEventObject(newInputValue));
      });

      jest.runOnlyPendingTimers();

      expect(onChangeCallbackStub.mock.calls.length).toEqual(1);
    });
  });
});
Example #8
Source File: useEventListener.jest.js    From monday-ui-react-core with MIT License 4 votes vote down vote up
describe("useEventListener", () => {
  let element;
  let callbackStub;
  describe("click", () => {
    beforeEach(() => {
      callbackStub = jest.fn();
      element = document.createElement("div");
      document.body.appendChild(element);
      renderHook(() =>
        useEventListener({
          eventName: "click",
          ref: { current: element },
          callback: callbackStub
        })
      );
    });

    afterEach(() => {
      element.remove();
      cleanup();
    });

    it("should call the callback when clicking", () => {
      act(() => {
        fireEvent.click(element);
      });
      return expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it("should not call callback on a different (not click) event", () => {
      act(() => {
        fireEvent.keyDown(element);
      });
      return expect(callbackStub.mock.calls.length).toEqual(0);
    });
  });

  describe("custom event", () => {
    const customEventName = "testEvent";
    const differentEventName = "testEvent-different";
    beforeEach(() => {
      callbackStub = jest.fn();
      element = document.createElement("div");
      document.body.appendChild(element);
      renderHook(() =>
        useEventListener({
          eventName: customEventName,
          ref: { current: element },
          callback: callbackStub
        })
      );
    });

    afterEach(() => {
      element.remove();
      cleanup();
    });

    it("should call the callback when clicking", () => {
      act(() => {
        fireEvent(
          element,
          new Event(customEventName, {
            bubbles: true,
            cancelable: true
          })
        );
      });
      return expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it("should not call callback on a different custom event event", () => {
      act(() => {
        fireEvent(
          element,
          new Event(differentEventName, {
            bubbles: true,
            cancelable: true
          })
        );
      });
      return expect(callbackStub.mock.calls.length).toEqual(0);
    });
  });
});
Example #9
Source File: useKeyEvent.jest.js    From monday-ui-react-core with MIT License 4 votes vote down vote up
describe("useKeyEvent", () => {
  let element;
  let callbackStub;
  describe("single key", () => {
    const keys = ["Enter"];
    beforeEach(() => {
      callbackStub = jest.fn();
      element = document.createElement("div");
      document.body.appendChild(element);
      renderHook(() =>
        useKeyEvent({
          keys,
          keyEventName: "keyup",
          ref: { current: element },
          callback: callbackStub
        })
      );
    });

    afterEach(() => {
      element.remove();
      cleanup();
    });

    it(`should call the callback with the ${keys[0]} key`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0]
        });
      });
      expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it(`should not call the callback with a different key`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: "Escape"
        });
      });

      expect(callbackStub.mock.calls.length).toEqual(0);
    });

    it("should not call on keyDown", () => {
      act(() => {
        fireEvent.keyDown(element, {
          key: keys[0]
        });
      });
      expect(callbackStub.mock.calls.length).toEqual(0);
    });
  });

  describe("single key with ALT modifier", () => {
    const keys = ["Enter"];
    beforeEach(() => {
      callbackStub = jest.fn();
      element = document.createElement("div");
      document.body.appendChild(element);
      renderHook(() =>
        useKeyEvent({
          keys,
          keyEventName: "keyup",
          ref: { current: element },
          callback: callbackStub,
          modifier: useKeyEvent.modifiers.ALT
        })
      );
    });

    afterEach(() => {
      element.remove();
      cleanup();
    });

    it(`should call the callback with the ${keys[0]} key and ALT key`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0],
          altKey: true
        });
      });
      expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it(`should not call the callback with the key but without modifiers`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0]
        });
      });

      expect(callbackStub.mock.calls.length).toEqual(0);
    });

    it(`should not call the callback with the key but with other modifier`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0],
          shiftKey: true
        });
      });

      expect(callbackStub.mock.calls.length).toEqual(0);
    });
  });

  describe("single key with CTRL_OR_META modifier", () => {
    const keys = ["Enter"];
    beforeEach(() => {
      callbackStub = jest.fn();
      element = document.createElement("div");
      document.body.appendChild(element);
      renderHook(() =>
        useKeyEvent({
          keys,
          keyEventName: "keyup",
          ref: { current: element },
          callback: callbackStub,
          modifier: useKeyEvent.modifiers.CTRL_OR_META
        })
      );
    });

    afterEach(() => {
      element.remove();
      cleanup();
    });

    it(`should call the callback with the ${keys[0]} key and CTRL key`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0],
          ctrlKey: true
        });
      });
      expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it(`should call the callback with the ${keys[0]} key and META key`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0],
          metaKey: true
        });
      });
      expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it(`should not call the callback with the key but without modifiers`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0]
        });
      });

      expect(callbackStub.mock.calls.length).toEqual(0);
    });

    it(`should not call the callback with the key but with other modifier`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0],
          shiftKey: true
        });
      });

      expect(callbackStub.mock.calls.length).toEqual(0);
    });

    it(`should not call the callback with other key but with modifiers`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: "Esc",
          metaKey: true
        });
      });

      expect(callbackStub.mock.calls.length).toEqual(0);
    });
  });

  describe("multiple keys", () => {
    const keys = ["Enter", "Esc", "Escape"];
    beforeEach(() => {
      callbackStub = jest.fn();
      element = document.createElement("div");
      document.body.appendChild(element);
      renderHook(() => {
        useKeyEvent({
          keys,
          keyEventName: "keyup",
          ref: { current: element },
          callback: callbackStub
        });
      });
    });

    afterEach(() => {
      element.remove();
      cleanup();
    });

    it(`should not call the callback with the ${keys[0]} key`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[0]
        });
      });
      expect(callbackStub.mock.calls.length).toEqual(1);
    });

    it(`should call the callback with a different key - ${keys[1]}`, () => {
      act(() => {
        fireEvent.keyUp(element, {
          key: keys[1]
        });
      });

      expect(callbackStub.mock.calls.length).toEqual(1);
    });
  });
});
Example #10
Source File: useGridKeyboardNavigation.jest.js    From monday-ui-react-core with MIT License 4 votes vote down vote up
describe("useGridKeyboardNavigation", () => {
  let element;

  afterEach(() => {
    element.remove();
    cleanup();
  });

  it("should consider the last navigation direction when focusing the element", () => {
    const items = itemsArray(9);
    const { result } = renderHookForTest({ items, numberOfItemsInLine: 3 });

    act(() => {
      userEvent.keyboard("{ArrowLeft}"); // make sure there's a value for lastNavigationDirection
      element.focus();
    });

    expect(result.current.activeIndex).toBe(5); // last index of the right-most line
  });

  it("should do nothing when focusing the element when it is already focused", () => {
    const items = itemsArray(9);
    const { result } = renderHookForTest({ items, numberOfItemsInLine: 3 });

    act(() => {
      // this should set the activeIndex to 5. Focusing the element after pressing "left", is like like the user pressed left to focus into the wrapper element.
      userEvent.keyboard("{ArrowLeft}");
      element.focus();
    });
    expect(result.current.activeIndex).toBe(5);
    act(() => {
      // this would have set the active index to 1 - but it should be ignored, since the wrapper element is already focused.
      element.focus();
    });

    expect(result.current.activeIndex).toBe(5);
  });

  it("should return a callback wrapper that sets the activeIndex to the keyboard selected element, ", () => {
    const { result } = renderHookForTest({});

    act(() => result.current.onSelectionAction(3, true));

    expect(result.current.activeIndex).toBe(3);
  });

  it("should select the currently active item when navigating and selecting using the keyboard", () => {
    const onItemClicked = jest.fn();
    const items = ["a", "b", "c", "d"];
    renderHookForTest({ items, focusOnMount: true, focusItemIndexOnMount: 0, onItemClicked });

    act(() => {
      fireEvent.keyDown(element, { key: "ArrowRight" }); // activeIndex should be set to 1
    });
    act(() => {
      fireEvent.keyDown(element, { key: " " }); // perform selection
    });

    expect(onItemClicked).toHaveBeenCalledTimes(1);
    expect(onItemClicked).toHaveBeenCalledWith("b", 1);
  });

  it("should ignore keyboard selections which are performed after selecting with the mouse", () => {
    const onItemClicked = jest.fn();
    const items = ["a", "b", "c", "d"];
    const { result } = renderHookForTest({ items, focusOnMount: true, focusItemIndexOnMount: 0, onItemClicked });
    act(() => result.current.onSelectionAction(1)); // select without the keyboard
    expect(onItemClicked).toHaveBeenCalledTimes(1);

    act(() => {
      fireEvent.keyDown(element, { key: " " }); // perform selection - which should be ignored
    });

    expect(onItemClicked).toHaveBeenCalledTimes(1); // no new calls
  });

  it("should return a callback wrapper that calls onItemClicked with the item and the index", () => {
    const onItemClicked = jest.fn();
    const items = ["a", "b", "c", "d"];
    const { result } = renderHookForTest({ onItemClicked, items });

    act(() => result.current.onSelectionAction(2));

    expect(onItemClicked).toHaveBeenCalledTimes(1);
    expect(onItemClicked).toHaveBeenCalledWith("c", 2);
  });

  it("should update the activeIndex when keyboard-navigating inside the element", () => {
    const items = ["a", "b", "c", "d"];
    const { result } = renderHookForTest({ items, numberOfItemsInLine: 2 });

    act(() => result.current.onSelectionAction(0)); // set the activeIndex to 0
    act(() => {
      fireEvent.keyDown(element, { key: "ArrowRight" });
    });

    expect(result.current.activeIndex).toBe(1);
  });

  it("should not update the activeIndex when performing outbound navigation with the keyboard", () => {
    const items = ["a", "b", "c", "d"];
    const { result } = renderHookForTest({ items, numberOfItemsInLine: 2 });

    act(() => result.current.onSelectionAction(0)); // set the activeIndex to 0
    act(() => {
      fireEvent.keyDown(element, { key: "ArrowUp" });
    });

    expect(result.current.activeIndex).toBe(0);
  });

  it("should skip disabled indexes when navigating with the keyboard", () => {
    const items = ["0", "1", "2", "3", "4", "5", "6", "7", "8"];
    const disabledIndexes = [1, 4];
    const { result } = renderHookForTest({
      items,
      numberOfItemsInLine: 3,
      focusItemIndexOnMount: 0,
      focusOnMount: true,
      disabledIndexes
    });

    act(() => {
      fireEvent.keyDown(element, { key: "ArrowRight" }); // moving right from index 0 should skip disabled index 1, and set activeIndex to 2
    });

    expect(result.current.activeIndex).toBe(2);
  });

  it("should ignore a keyboard selection action if the user is currently not using the keyboard", () => {
    const { result } = renderHookForTest({ focusItemIndexOnMount: 2, focusOnMount: true });

    act(() => result.current.onSelectionAction(3, true)); // set the activeIndex to 3
    act(() => result.current.onSelectionAction(2)); // perform a non-keyboard action

    expect(result.current.isInitialActiveState).toBe(false);
  });

  describe("focusItemIndexOnMount", () => {
    it("should set the active index according to focusItemIndexOnMount on mount, when focusOnMount is true", () => {
      const items = ["a", "b", "c", "d"];

      const { result } = renderHookForTest({ items, focusItemIndexOnMount: 2, focusOnMount: true });

      expect(result.current.activeIndex).toBe(2);
    });

    it("should ignore the value of focusItemIndexOnMount, when focusOnMount is false", () => {
      const items = ["a", "b", "c", "d"];

      const { result } = renderHookForTest({ items, focusItemIndexOnMount: 2, focusOnMount: false });

      expect(result.current.activeIndex).toBe(-1);
    });

    it("should return isInitialActiveState = false when focusItemIndexOnMount option is missing", () => {
      const items = ["a", "b", "c", "d"];

      const { result } = renderHookForTest({ items, focusOnMount: true });

      expect(result.current.isInitialActiveState).toBe(false);
    });

    it("should return isInitialActiveState = false when focusOnMount = false and focusItemIndexOnMount option exists", () => {
      const items = ["a", "b", "c", "d"];

      const { result } = renderHookForTest({ items, focusItemIndexOnMount: 2, focusOnMount: false });

      expect(result.current.isInitialActiveState).toBe(false);
    });

    it("should return isInitialActiveState = true when focusOnMount and focusItemIndexOnMount option exists", () => {
      const items = ["a", "b", "c", "d"];

      const { result } = renderHookForTest({ items, focusItemIndexOnMount: 2, focusOnMount: true });

      expect(result.current.isInitialActiveState).toBe(true);
    });

    it("should return isInitialActiveState = false when focusOnMount and focusItemIndexOnMount option exists, and activeIndex changed afterwards", () => {
      const items = ["a", "b", "c", "d"];

      const { result } = renderHookForTest({ items, focusItemIndexOnMount: 2, focusOnMount: true });
      act(() => {
        fireEvent.keyDown(element, { key: "ArrowLeft" });
      });

      expect(result.current.isInitialActiveState).toBe(false);
    });
  });

  function itemsArray(length) {
    return range(length);
  }

  function renderHookForTest({
    items = itemsArray(4),
    numberOfItemsInLine = 3,
    onItemClicked = jest.fn(),
    focusOnMount = false,
    focusItemIndexOnMount = undefined,
    disabledIndexes = []
  }) {
    const itemsCount = items.length;
    const getItemByIndex = index => items[index];

    element = document.createElement("div");
    element.tabIndex = -1; // some tests focus the element - a tabIndex value is required for updating the document.activeIndex value
    document.body.appendChild(element);

    return renderHook(() =>
      useGridKeyboardNavigation({
        ref: { current: element },
        itemsCount,
        getItemByIndex,
        onItemClicked,
        focusOnMount,
        numberOfItemsInLine,
        focusItemIndexOnMount,
        disabledIndexes
      })
    );
  }
});
Example #11
Source File: useSetFocus.jest.js    From monday-ui-react-core with MIT License 4 votes vote down vote up
describe("useSetFocus", () => {
  let element;
  const focusCallback = jest.fn();
  const blurCallback = jest.fn();

  afterEach(() => {
    element.remove();
    cleanup();
  });

  it("default isFocused value is false", () => {
    const { result } = renderHookForTest();
    expect(result.current.isFocused).toBe(false);
  });

  it("focusCallback should be called after focusing the element", () => {
    renderHookForTest();

    act(() => {
      element.focus();
    });

    expect(focusCallback.mock.calls.length).toBe(1);
  });

  it("isFocused should be true after focusing the element", () => {
    const { result } = renderHookForTest();

    act(() => {
      element.focus();
    });

    expect(result.current.isFocused).toBe(true);
  });

  it("blurCallback should not be called after focusing the element", () => {
    renderHookForTest();

    act(() => {
      element.focus();
    });

    expect(blurCallback.mock.calls.length).toBe(0);
  });

  it("blurCallback should be called after blurring element", () => {
    const { result } = renderHookForTest();

    act(() => {
      element.focus();
    });

    act(() => {
      element.blur();
    });

    expect(blurCallback.mock.calls.length).toBe(1);
    expect(result.current.isFocused).toBe(false);
  });

  it("isFocused should be false after blurring element", () => {
    const { result } = renderHookForTest();

    act(() => {
      element.focus();
    });

    act(() => {
      element.blur();
    });

    expect(result.current.isFocused).toBe(false);
  });

  it("element should be focused after calling hook.focus()", () => {
    const { result } = renderHookForTest();

    act(() => {
      result.current.focus();
    });

    expect(result.current.isFocused).toBe(true);
    expect(document.activeElement).toBe(element);
  });

  it("element should not be focused after calling hook.blur()", () => {
    const { result } = renderHookForTest();

    act(() => {
      result.current.focus();
    });

    act(() => {
      result.current.blur();
    });

    expect(result.current.isFocused).toBe(false);
    expect(document.activeElement).not.toBe(element);
  });

  function renderHookForTest() {
    element = document.createElement("input");
    document.body.appendChild(element);

    return renderHook(() =>
      useSetFocus({
        ref: { current: element },
        focusCallback: focusCallback,
        blurCallback: blurCallback
      })
    );
  }
});