diff --git a/src/molecules/accessible-list/accessible-list.test.tsx b/src/molecules/accessible-list/accessible-list.test.tsx index 136639e..10a2f2f 100644 --- a/src/molecules/accessible-list/accessible-list.test.tsx +++ b/src/molecules/accessible-list/accessible-list.test.tsx @@ -1,7 +1,80 @@ -// import React from "react"; -// import { render } from "@testing-library/react"; -// import { AccessibleList } from "./accessible-list"; +import React, { Component } from "react"; +import faker from "faker"; +import { render, fireEvent, screen } from "@testing-library/react"; +import { AccessibleList } from "./accessible-list"; +import { KeyboardKeys } from "../../constants/keyboard-keys"; describe("AccessibleList", () => { - test.skip("TODO - https://github.com/AndcultureCode/AndcultureCode.JavaScript.React.Components/issues/19", () => {}); + test("when default props, renders items", () => { + // Arrange + const expected = faker.random.word(); + + // Act + const { getByText } = render( + + + + ); + + // Assert + expect(getByText(expected)).not.toBeNil(); + }); + + test("when onEsc set, calls handler upon escape pressed", () => { + // Arrange + let isChecked = false; + const buttonText = faker.random.word(); + const onEscHandler = () => { + isChecked = true; + }; + + // Act + const { getByText } = render( + + + + ); + fireEvent.keyDown(getByText(buttonText), { key: KeyboardKeys.Escape }); + + // Assert + expect(isChecked).toBeTrue(); + }); + + test("when invalid react element, does not render in list", () => { + // Arrange + const buttonText = [faker.random.word(), faker.random.word()]; + + // Act + const { container } = render( + + + {null} + {undefined} + + + ); + + // Assert + expect(container.childNodes).toHaveLength(2); + }); + + it("when onClick set, calls handler upon click", async () => { + // Arrange + let isChecked = false; + const handleClick = () => { + isChecked = true; + }; + const buttonText = faker.random.word(); + + // Act + const { getByText } = render( + + + + ); + fireEvent.click(getByText(buttonText)); + + // Assert + expect(isChecked).toBeTrue(); + }); }); diff --git a/src/molecules/accessible-list/accessible-list.tsx b/src/molecules/accessible-list/accessible-list.tsx index ab90c91..e61f524 100644 --- a/src/molecules/accessible-list/accessible-list.tsx +++ b/src/molecules/accessible-list/accessible-list.tsx @@ -37,47 +37,46 @@ const AccessibleList: React.FunctionComponent = ( }, [refArray, current, props.focusFirstItem]); const handleKeyDown = (e: KeyboardEvent) => { - if ( - e.key === KeyboardKeys.DownArrow && - current === refArray.length - 1 - ) { - e.preventDefault(); - setCurrent(0); - return; + switch (e.key) { + case KeyboardKeys.UpArrow: { + handleUpArrowPress(e); + break; + } + case KeyboardKeys.DownArrow: { + handleDownArrowPress(e); + break; + } + case KeyboardKeys.Escape: { + handleEscapePress(e); + break; + } + default: { + return; + } } + }; - if (e.key === KeyboardKeys.UpArrow && current === 0) { - e.preventDefault(); - setCurrent(refArray.length - 1); - return; - } + const handleDownArrowPress = (e: KeyboardEvent) => { + const isLastElementFocused = current === refArray.length - 1; + const indexToFocus = isLastElementFocused ? 0 : current + 1; - if ( - e.key === KeyboardKeys.DownArrow && - current !== refArray.length - 1 - ) { - e.preventDefault(); + setCurrentAndPreventDefault(e, indexToFocus); + }; - setCurrent(current + 1); - return; - } - - if (e.key === KeyboardKeys.UpArrow && current !== 0) { - e.preventDefault(); - - setCurrent(current - 1); - return; + const handleEscapePress = (e: KeyboardEvent) => { + setCurrentAndPreventDefault(e, 0); + if (props.onEsc != null) { + props.onEsc(); } + }; - if (e.key === KeyboardKeys.Escape) { - e.preventDefault(); - setCurrent(0); + const handleUpArrowPress = (e: KeyboardEvent) => { + const isFirstElementFocused = current === 0; + const indexToFocus = isFirstElementFocused + ? refArray.length - 1 + : current - 1; - if (props.onEsc != null) { - props.onEsc(); - } - return; - } + setCurrentAndPreventDefault(e, indexToFocus); }; const renderChildren = () => { @@ -87,19 +86,36 @@ const AccessibleList: React.FunctionComponent = ( return child; } - return React.cloneElement(child, { - ...child.props, - onClick: () => { - if (child.props.onClick != null) { - child.props.onClick(); - } - }, - onKeyDown: handleKeyDown, - ref: (el: HTMLElement) => (refArray[validElementIndex++] = el), - }); + const renderedChild = renderChild(child, validElementIndex); + validElementIndex++; + return renderedChild; + }); + }; + + const renderChild = (child: React.ReactElement, index: number) => { + return React.cloneElement(child, { + ...child.props, + onClick: () => { + if (child.props.onClick != null) { + child.props.onClick(); + } + }, + onKeyDown: handleKeyDown, + ref: (el: HTMLElement) => (refArray[index] = el), }); }; + const setCurrentAndPreventDefault = ( + e: KeyboardEvent, + indexToFocus: number + ) => { + if (indexToFocus < 0) { + return; + } + e.preventDefault(); + setCurrent(indexToFocus); + }; + return {renderChildren()}; };