diff --git a/packages/components/package.json b/packages/components/package.json index 2f7ec823..fc963aa7 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -2,7 +2,7 @@ "name": "@dolthub/react-components", "author": "DoltHub", "description": "A collection of React components for common tasks", - "version": "0.1.0", + "version": "0.1.1", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "types": "dist/index.d.ts", diff --git a/packages/components/src/Popup/index.tsx b/packages/components/src/Popup/index.tsx index 93b9232e..bd2625f9 100644 --- a/packages/components/src/Popup/index.tsx +++ b/packages/components/src/Popup/index.tsx @@ -1,7 +1,7 @@ import React from "react"; import ReactPopup from "reactjs-popup"; import "reactjs-popup/dist/index.css"; -import { PopupProps } from "reactjs-popup/dist/types"; +import type { PopupProps } from "reactjs-popup/dist/types.d"; export default function Popup(props: PopupProps) { return ( diff --git a/packages/components/src/SmallLoader/index.tsx b/packages/components/src/SmallLoader/index.tsx index aa839abe..a4b80d05 100644 --- a/packages/components/src/SmallLoader/index.tsx +++ b/packages/components/src/SmallLoader/index.tsx @@ -1,5 +1,5 @@ import cx from "classnames"; -import React from "react"; +import React, { ReactNode } from "react"; import ReactLoader from "react-loader"; import css from "./index.module.css"; @@ -29,7 +29,7 @@ type Props = { loaded: boolean; className?: string; options?: Partial; - tableLoader?: boolean; + children?: ReactNode; }; export default function SmallLoader(props: Props) { @@ -53,7 +53,7 @@ function WithText(props: WithTextProps) { return (
- {props.text} + {!props.loaded && {props.text}}
); } diff --git a/packages/components/src/__tests__/Loader.test.tsx b/packages/components/src/__tests__/Loader.test.tsx new file mode 100644 index 00000000..d75e100e --- /dev/null +++ b/packages/components/src/__tests__/Loader.test.tsx @@ -0,0 +1,16 @@ +import { render, screen } from "@testing-library/react"; +import React from "react"; +import Loader from "../Loader"; + +describe("test Loader", () => { + it("does not render child if loading", () => { + render(Loading...); + const el = screen.queryByText("Loading..."); + expect(el).not.toBeInTheDocument(); + }); + it("does render child if not loading", () => { + render(Loading...); + const el = screen.getByText("Loading..."); + expect(el).toBeVisible(); + }); +}); diff --git a/packages/components/src/__tests__/Popup.test.tsx b/packages/components/src/__tests__/Popup.test.tsx new file mode 100644 index 00000000..b8ffc621 --- /dev/null +++ b/packages/components/src/__tests__/Popup.test.tsx @@ -0,0 +1,228 @@ +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import React from "react"; +import Popup, { PopupProps } from "../Popup"; + +// Taken from https://github.com/yjose/reactjs-popup/blob/master/__test__/index.test.tsx + +const SimplePopup = ({ ...props }: Partial) => ( + trigger } {...props}> + popup Content + +); +const popupContentShouldntExist = () => { + expect(screen.queryByText(/popup Content/)).toBeNull(); +}; +const popupContentShouldExist = () => { + expect(screen.getByText(/popup Content/)).toBeInTheDocument(); +}; + +describe("Popup Component Render ", () => { + test("should render trigger correctly", () => { + render(); + expect(screen.getByText(/trigger/)).toBeInTheDocument(); + }); + + test("should be a tooltip by default", () => { + render(); + fireEvent.click(screen.getByText("trigger")); + expect(screen.getByRole("tooltip")).toBeInTheDocument(); + }); + + test("no Arrow for modal", () => { + render(); + fireEvent.click(screen.getByText("trigger")); + expect(screen.getByRole("dialog")).toBeInTheDocument(); + expect(screen.queryByTestId("arrow")).toBeNull(); + }); + + test("no Arrow on arrow= false", () => { + render(); + fireEvent.click(screen.getByText("trigger")); + expect(screen.getByRole("tooltip")).toBeInTheDocument(); + expect(screen.queryByTestId("arrow")).toBeNull(); + }); + + test("should render a Modal on modal=true", () => { + render(); + fireEvent.click(screen.getByText("trigger")); + expect(screen.getByRole("dialog")).toBeInTheDocument(); + }); + + test("it should be closed on disabled = true ", () => { + render(); + popupContentShouldntExist(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldntExist(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldntExist(); + }); + test("should be open by default on defaultOpen= true ", () => { + render(); + popupContentShouldExist(); + }); + + test("should call onOpen & onClose functions ", async () => { + const onOpen = jest.fn(); + const onClose = jest.fn(); + render(); + + fireEvent.click(screen.getByText("trigger")); + await waitFor(() => { + expect(onOpen).toHaveBeenCalled(); + const [event] = onOpen.mock.calls[0]; + expect("target" in event).toBe(true); + }); + fireEvent.click(screen.getByText("trigger")); + await waitFor(() => { + expect(onClose).toHaveBeenCalled(); + const [event] = onClose.mock.calls[0]; + expect("target" in event).toBe(true); + }); + // expect(screen.getByRole('tooltip')).toBeInTheDocument(); + }); + + test("should be closed on Escape", async () => { + render(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldExist(); + fireEvent.keyUp(document, { key: "Escape", code: "Escape" }); + popupContentShouldntExist(); + }); + test("shouldnt close on Escape if closeOnEscape=false", async () => { + render(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldExist(); + fireEvent.keyUp(document, { key: "Escape", code: "Escape" }); + popupContentShouldExist(); + }); + + test("should be closed on ClickOutside ", async () => { + render(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldExist(); + fireEvent.mouseDown(document); + popupContentShouldntExist(); + }); + test("shouldnt close on ClickOutside if closeOnDocumentClick=false", async () => { + render(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldExist(); + fireEvent.mouseDown(document); + popupContentShouldExist(); + }); + + test("should lock Document Scroll on lockScroll=true", async () => { + render(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldExist(); + expect(document.body).toHaveStyle(`overflow: hidden`); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldntExist(); + expect(document.body).toHaveStyle(`overflow: auto`); + }); +}); + +// test for "on" props status +describe('Popup Component with "on" Prop ', () => { + test("it should be opened only on Click as default value ", () => { + render(); + popupContentShouldntExist(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldExist(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldntExist(); + }); + + test('it should be opened only on Click where on="click" ', () => { + render(); + popupContentShouldntExist(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldExist(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldntExist(); + }); + test('it should be opened only on Right-Click where on="right-click" ', () => { + render(); + popupContentShouldntExist(); + fireEvent.contextMenu(screen.getByText("trigger")); + popupContentShouldExist(); + fireEvent.contextMenu(screen.getByText("trigger")); + popupContentShouldntExist(); + }); + test('it should be opened only on Hover where on="hover" ', async () => { + render(); + popupContentShouldntExist(); + fireEvent.mouseOver(screen.getByText("trigger")); + await waitFor( + () => popupContentShouldExist(), + { timeout: 120 }, // default delay = "100" + ); + fireEvent.mouseLeave(screen.getByText("trigger")); + + await waitFor( + () => expect(screen.queryByText(/popup Content/)).toBeNull(), + { timeout: 120 }, + ); + // should not show on click + fireEvent.click(screen.getByText("trigger")); + popupContentShouldntExist(); + }); + test('it should be opened only on Focus where on="focus" ', async () => { + render(); + popupContentShouldntExist(); + fireEvent.focus(screen.getByText("trigger")); + await waitFor( + () => popupContentShouldExist(), + { timeout: 120 }, // default delay = "100" + ); + fireEvent.blur(screen.getByText("trigger")); + await waitFor(() => popupContentShouldntExist(), { timeout: 120 }); + // should not show content on click + fireEvent.click(screen.getByText("trigger")); + popupContentShouldntExist(); + }); + test('it should be opened on Focus & click & focus where on=["focus","click","hover"] ', async () => { + render(); + popupContentShouldntExist(); + // on focus + fireEvent.focus(screen.getByText("trigger")); + await waitFor( + () => popupContentShouldExist(), + { timeout: 120 }, // default delay = "100" + ); + fireEvent.blur(screen.getByText("trigger")); + await waitFor(() => popupContentShouldntExist(), { timeout: 120 }); + // on click + fireEvent.click(screen.getByText("trigger")); + popupContentShouldExist(); + fireEvent.click(screen.getByText("trigger")); + popupContentShouldntExist(); + + // on Hover + fireEvent.mouseOver(screen.getByText("trigger")); + await waitFor( + () => popupContentShouldExist(), + { timeout: 120 }, // default delay = "100" + ); + fireEvent.mouseLeave(screen.getByText("trigger")); + + await waitFor( + () => expect(screen.queryByText(/popup Content/)).toBeNull(), + { timeout: 120 }, + ); + }); + + test("should respect mouseEnterDelay mouseLeaveDelay on Hover ", async () => { + render( + , + ); + popupContentShouldntExist(); + fireEvent.mouseOver(screen.getByText("trigger")); + await waitFor(() => popupContentShouldntExist(), { timeout: 120 }); + await waitFor(() => popupContentShouldExist(), { timeout: 1000 }); + fireEvent.mouseLeave(screen.getByText("trigger")); + + await waitFor(() => popupContentShouldExist(), { timeout: 120 }); + await waitFor(() => popupContentShouldntExist(), { timeout: 1000 }); + }); +}); diff --git a/packages/components/src/__tests__/SmallLoader.test.tsx b/packages/components/src/__tests__/SmallLoader.test.tsx new file mode 100644 index 00000000..1b9ab5a6 --- /dev/null +++ b/packages/components/src/__tests__/SmallLoader.test.tsx @@ -0,0 +1,29 @@ +import { render, screen } from "@testing-library/react"; +import React from "react"; +import SmallLoader from "../SmallLoader"; + +describe("test SmallLoader", () => { + it("does not render child if loading", () => { + render(Loading...); + const el = screen.queryByText("Loading..."); + expect(el).not.toBeInTheDocument(); + }); + it("does render child if not loading", () => { + render(Loading...); + const el = screen.getByText("Loading..."); + expect(el).toBeVisible(); + }); +}); + +describe("test SmallLoader.WithText", () => { + it("does render text if loading", () => { + render(); + const el = screen.getByText("Loading..."); + expect(el).toBeVisible(); + }); + it("does not render text if not loading", () => { + render(); + const el = screen.queryByText("Loading..."); + expect(el).not.toBeInTheDocument(); + }); +});