Skip to content

Instantly share code, notes, and snippets.

@createdbymahmood
Last active October 5, 2020 04:04
Show Gist options
  • Save createdbymahmood/0344bde8d182c679a5eaf3fb2cc5bd0f to your computer and use it in GitHub Desktop.
Save createdbymahmood/0344bde8d182c679a5eaf3fb2cc5bd0f to your computer and use it in GitHub Desktop.
This is how I'm testing a button component
import React from "react";
import {
cleanup,
fireEvent,
render,
RenderResult,
} from "@testing-library/react";
import { Button, ButtonProps } from "./Button";
describe("<DangerButton />", () => {
let wrapper: RenderResult;
const onClickHandler = jest.fn();
const buttonText = "button";
const buttonProps: ButtonProps = {
onClick: onClickHandler,
type: "danger",
size: "lg",
};
beforeEach(() => {
wrapper = render(<Button {...buttonProps}>{buttonText}</Button>);
});
afterAll(cleanup);
it("Should render the button correctly", () => {
const { getByTestId } = wrapper;
const button = getByTestId("btn");
expect(button).toBeInTheDocument();
});
it("Should fire the onClickHandler on click ", () => {
const { getByTestId } = wrapper;
const button = getByTestId("btn");
fireEvent.click(button);
/* to have beed called */
expect(onClickHandler).toHaveBeenCalled();
/* to have beed called only one time */
expect(onClickHandler).toHaveBeenCalledTimes(1);
});
it("Should have the lg specified classnames", () => {
const { queryByText } = wrapper;
const button = queryByText("button") as HTMLButtonElement;
expect(button.className).toContain("p-8 py-4 text-lg");
});
});
import React from "react";
import classnames from "classnames";
// * these are the base custom button props
type ButtonSizeType = "xs" | "sm" | "md" | "lg" | "xl";
type ButtonTypeType =
| "primary"
| "info"
| "light-info"
| "warning"
| "danger"
| "success"
| "dark-info"
| "default";
type ButtonExtraProps = {
size: ButtonSizeType;
type: ButtonTypeType;
block: boolean;
rounded: boolean;
};
// * integrate HTML button props with our custom props
export type ButtonProps = Omit<
React.HtmlHTMLAttributes<HTMLButtonElement>,
keyof ButtonExtraProps
> &
Partial<ButtonExtraProps>;
const defaultProps: ButtonProps = {
size: "sm",
type: "default",
block: false,
rounded: true,
};
export const Button: React.FC<ButtonProps> = props => {
// * destruct needed props
const {
size,
type,
block,
rounded,
className: nativeClassName,
...restProps
} = props;
// * switch on the types and make suitable size & types
let sizeClassname = makeSize(size);
let typeClassname = makeType(type);
// * check if our button is fullwidth or rounded
let blockClassname = block ? "w-full" : "";
let roundedClassname = rounded ? "rounded-full" : "";
const classNames = [
nativeClassName,
sizeClassname,
typeClassname,
blockClassname,
roundedClassname,
];
// * render the button 🔥
return (
<button
data-testid="btn"
className={classnames(classNames)}
{...restProps}
/>
);
};
function makeSize(size: ButtonSizeType) {
switch (size) {
case "xs":
return ["px-2", "py-1", "text-xs"];
case "sm":
return ["p-4", "py-2", "text-sm"];
case "md":
return ["p-6", "py-3", "text-md"];
case "lg":
return ["p-8", "py-4", "text-lg"];
case "xl":
return ["p-10", "py-5", "text-xl"];
// sm by default
default:
return ["p-4", "py-2", "text-sm"];
}
}
function makeType(type: ButtonTypeType) {
switch (type) {
case "default":
return ["bg-white", "text-black"];
case "danger":
return ["text-white", "bg-red"];
case "info":
return ["text-white", "bg-blue-700"];
case "light-info":
return ["text-black", "bg-light-blue"];
case "primary":
return ["text-white", "bg-blue"];
case "success":
return ["text-white", "bg-green"];
case "warning":
return ["text-white", "bg-orange"];
case "dark-info":
return ["text-white", "bg-dark-blue"];
// default button type, the most simple 🎈
default:
return ["bg-white", "text-black"];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment