Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

components: Fix SmallLoader, unit tests #46

Merged
merged 2 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/Popup/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down
6 changes: 3 additions & 3 deletions packages/components/src/SmallLoader/index.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -29,7 +29,7 @@ type Props = {
loaded: boolean;
className?: string;
options?: Partial<typeof smallLoaderDefaultOptions>;
tableLoader?: boolean;
children?: ReactNode;
};

export default function SmallLoader(props: Props) {
Expand All @@ -53,7 +53,7 @@ function WithText(props: WithTextProps) {
return (
<div className={cx(css.loading, props.outerClassName)}>
<SmallLoader {...props} />
<span>{props.text}</span>
{!props.loaded && <span>{props.text}</span>}
</div>
);
}
Expand Down
16 changes: 16 additions & 0 deletions packages/components/src/__tests__/Loader.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<Loader loaded={false}>Loading...</Loader>);
const el = screen.queryByText("Loading...");
expect(el).not.toBeInTheDocument();
});
it("does render child if not loading", () => {
render(<Loader loaded>Loading...</Loader>);
const el = screen.getByText("Loading...");
expect(el).toBeVisible();
});
});
228 changes: 228 additions & 0 deletions packages/components/src/__tests__/Popup.test.tsx
Original file line number Diff line number Diff line change
@@ -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<PopupProps>) => (
<Popup trigger={<button> trigger </button>} {...props}>
<span> popup Content </span>
</Popup>
);
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(<SimplePopup />);
expect(screen.getByText(/trigger/)).toBeInTheDocument();
});

test("should be a tooltip by default", () => {
render(<SimplePopup />);
fireEvent.click(screen.getByText("trigger"));
expect(screen.getByRole("tooltip")).toBeInTheDocument();
});

test("no Arrow for modal", () => {
render(<SimplePopup modal />);
fireEvent.click(screen.getByText("trigger"));
expect(screen.getByRole("dialog")).toBeInTheDocument();
expect(screen.queryByTestId("arrow")).toBeNull();
});

test("no Arrow on arrow= false", () => {
render(<SimplePopup arrow={false} />);
fireEvent.click(screen.getByText("trigger"));
expect(screen.getByRole("tooltip")).toBeInTheDocument();
expect(screen.queryByTestId("arrow")).toBeNull();
});

test("should render a Modal on modal=true", () => {
render(<SimplePopup modal />);
fireEvent.click(screen.getByText("trigger"));
expect(screen.getByRole("dialog")).toBeInTheDocument();
});

test("it should be closed on disabled = true ", () => {
render(<SimplePopup disabled />);
popupContentShouldntExist();
fireEvent.click(screen.getByText("trigger"));
popupContentShouldntExist();
fireEvent.click(screen.getByText("trigger"));
popupContentShouldntExist();
});
test("should be open by default on defaultOpen= true ", () => {
render(<SimplePopup defaultOpen />);
popupContentShouldExist();
});

test("should call onOpen & onClose functions ", async () => {
const onOpen = jest.fn();
const onClose = jest.fn();
render(<SimplePopup onOpen={onOpen} onClose={onClose} />);

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(<SimplePopup />);
fireEvent.click(screen.getByText("trigger"));
popupContentShouldExist();
fireEvent.keyUp(document, { key: "Escape", code: "Escape" });
popupContentShouldntExist();
});
test("shouldnt close on Escape if closeOnEscape=false", async () => {
render(<SimplePopup closeOnEscape={false} />);
fireEvent.click(screen.getByText("trigger"));
popupContentShouldExist();
fireEvent.keyUp(document, { key: "Escape", code: "Escape" });
popupContentShouldExist();
});

test("should be closed on ClickOutside ", async () => {
render(<SimplePopup />);
fireEvent.click(screen.getByText("trigger"));
popupContentShouldExist();
fireEvent.mouseDown(document);
popupContentShouldntExist();
});
test("shouldnt close on ClickOutside if closeOnDocumentClick=false", async () => {
render(<SimplePopup closeOnDocumentClick={false} />);
fireEvent.click(screen.getByText("trigger"));
popupContentShouldExist();
fireEvent.mouseDown(document);
popupContentShouldExist();
});

test("should lock Document Scroll on lockScroll=true", async () => {
render(<SimplePopup lockScroll={true} modal />);
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(<SimplePopup />);
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(<SimplePopup on="click" />);
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(<SimplePopup on="right-click" />);
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(<SimplePopup on="hover" />);
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(<SimplePopup on="focus" />);
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(<SimplePopup on={["focus", "click", "hover"]} />);
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(
<SimplePopup on="hover" mouseEnterDelay={800} mouseLeaveDelay={800} />,
);
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 });
});
});
29 changes: 29 additions & 0 deletions packages/components/src/__tests__/SmallLoader.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<SmallLoader loaded={false}>Loading...</SmallLoader>);
const el = screen.queryByText("Loading...");
expect(el).not.toBeInTheDocument();
});
it("does render child if not loading", () => {
render(<SmallLoader loaded>Loading...</SmallLoader>);
const el = screen.getByText("Loading...");
expect(el).toBeVisible();
});
});

describe("test SmallLoader.WithText", () => {
it("does render text if loading", () => {
render(<SmallLoader.WithText loaded={false} text="Loading..." />);
const el = screen.getByText("Loading...");
expect(el).toBeVisible();
});
it("does not render text if not loading", () => {
render(<SmallLoader.WithText loaded text="Loading..." />);
const el = screen.queryByText("Loading...");
expect(el).not.toBeInTheDocument();
});
});
Loading