@vertisanpro/flowbite-react
Version:
Non-Official React components built for Flowbite and Tailwind CSS
255 lines (254 loc) • 11.8 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { AiOutlineLoading } from '@vertisanpro/react-icons/ai';
import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import { Flowbite } from '../Flowbite';
import { Button } from './Button';
describe('Components / Button', () => {
describe('A11y', () => {
it('should have `role="button"` by default', () => {
render(React.createElement(Button, null, "Hi there"));
expect(button()).toBeInTheDocument();
});
it('should be able to use any other role permitted for `<button>`s', () => {
render(React.createElement(Button, { role: "menuitem" }, "Hi there"));
const button = screen.getByRole('menuitem');
expect(button).toBeInTheDocument();
});
});
describe('Keyboard interactions', () => {
it('should trigger `onClick` when `Space` is pressed', async () => {
const user = userEvent.setup();
const onClick = vi.fn();
render(React.createElement(Button, { onClick: onClick }, "Hi there"));
await user.click(button());
expect(onClick).toHaveBeenCalledTimes(1);
});
it('should focus when `Tab` is pressed', async () => {
const user = userEvent.setup();
render(React.createElement(Button, null, "Hi there"));
await user.tab();
expect(button()).toHaveFocus();
});
it('should be possible to `Tab` out', async () => {
const user = userEvent.setup();
render(React.createElement(React.Fragment, null,
React.createElement(Button, null, "Hi there"),
React.createElement(Button, null, "Hello there"),
React.createElement("button", { type: "submit" }, "Submit")));
await user.tab();
expect(buttons()[0]).toHaveFocus();
await user.tab();
expect(buttons()[1]).toHaveFocus();
await user.tab();
expect(buttons()[2]).toHaveFocus();
});
});
describe('Props', () => {
it('should allow HTML attributes for `<button>`s', () => {
render(React.createElement(Button, { formAction: "post.php", type: "submit" }, "Hi there"));
expect(button()).toHaveAttribute('formAction', 'post.php');
expect(button()).toHaveAttribute('type', 'submit');
});
it('should be disabled when `disabled={true}`', () => {
render(React.createElement(Button, { disabled: true }, "Hi there"));
expect(button()).toBeDisabled();
});
it('should show <Spinner /> when `isProcessing={true}`', () => {
render(React.createElement(Button, { isProcessing: true }, "Hi there"));
expect(screen.getByText(/Hi there/)).toBeInTheDocument();
expect(screen.getByRole('status')).toBeInTheDocument();
});
it('should show custom spinner when `isProcessing={true}` and `processingSpinner` is present', () => {
render(React.createElement(Button, { isProcessing: true, processingSpinner: React.createElement(AiOutlineLoading, { "data-testid": "spinner" }) }, "Hi there"));
expect(screen.getByText(/Hi there/)).toBeInTheDocument();
expect(screen.getByTestId('spinner')).toBeInTheDocument();
});
});
describe('Rendering', () => {
it('should render when `children={0}`', () => {
render(React.createElement(Button, null, "0"));
expect(button()).toHaveTextContent('0');
});
it('should render when `children={undefined}`', () => {
render(React.createElement(Button, { label: "Something or other" }));
expect(button()).toHaveTextContent('Something or other');
});
describe('`as` and `href` props', () => {
it('should render an anchor `<a>` when `href=".."`', () => {
render(React.createElement(Button, { href: "#", label: "Something or other" }));
expect(buttonLink()).toBeInTheDocument();
});
it('should render component defined in `as`', () => {
const CustomComponent = ({ children }) => {
return React.createElement("li", null, children);
};
render(React.createElement("ul", null,
React.createElement(Button, { as: CustomComponent, uniqueProp: true }, "Something or other")));
const button = buttonListItem();
expect(button).toBeInTheDocument();
expect(button).toHaveTextContent('Something or other');
});
it('should render component defined in `as` prop even though `href` is defined', () => {
const CustomComponent = ({ children }) => {
return React.createElement("li", null, children);
};
render(React.createElement("ul", null,
React.createElement(Button, { href: "#", as: CustomComponent, label: "Something or other" })));
expect(buttonListItem()).toBeInTheDocument();
});
it('should render tag element defined in `as`', () => {
render(React.createElement("ul", null,
React.createElement(Button, { as: "li", label: "Something or other" })));
expect(buttonListItem()).toBeInTheDocument();
});
it('should render as button `as={null}`', () => {
render(React.createElement("ul", null,
React.createElement(Button, { as: null, label: "Something or other" })));
expect(button()).toBeInTheDocument();
});
});
});
describe('Theme', () => {
it('should use `base` classes', () => {
const theme = {
button: {
base: 'font-extralight',
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, null)));
expect(button()).toHaveClass('font-extralight');
});
it('should use `color` classes', () => {
const theme = {
button: {
color: {
primary: 'bg-red-300',
},
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, { color: "primary" })));
expect(button()).toHaveClass('bg-red-300');
});
it('should use `disabled` classes', () => {
const theme = {
button: {
disabled: 'opacity-10',
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, { disabled: true })));
expect(button()).toHaveClass('opacity-10');
});
it('should use `gradient` classes', () => {
const theme = {
button: {
gradient: {
yellowToPink: 'font-extralight',
},
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, { gradientMonochrome: "yellowToPink" })));
expect(button()).toHaveClass('font-extralight');
});
it('should use `gradientDuoTone` classes', () => {
const theme = {
button: {
gradientDuoTone: {
yellowToPink: 'font-extralight',
},
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, { gradientDuoTone: "yellowToPink" })));
expect(button()).toHaveClass('font-extralight');
});
it('should use `inner` classes', () => {
const theme = {
button: {
inner: {
base: 'font-extralight',
},
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, null, "Hi there")));
const buttonInnerContent = screen.getByText('Hi there');
expect(buttonInnerContent).toHaveClass('font-extralight');
});
it('should use `label` classes', () => {
const theme = {
button: {
label: 'font-extralight',
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, { label: "Hi there" })));
const buttonLabel = screen.getByText('Hi there');
expect(buttonLabel).toHaveClass('font-extralight');
});
it('should use `outline` classes', () => {
const theme = {
button: {
outline: {
off: 'font-extralight',
on: 'font-extrabold',
pill: {
off: 'text-purple-300',
on: 'text-purple-600',
},
},
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, null, "Normal button"),
React.createElement(Button, { outline: true }, "Outline button"),
React.createElement(Button, { outline: true, pill: true }, "Outline pill button")));
const normalButton = screen.getByText('Normal button');
const outlineButton = screen.getByText('Outline button');
const outlinePillButton = screen.getByText('Outline pill button');
expect(normalButton).toHaveClass('font-extralight text-purple-300');
expect(outlineButton).toHaveClass('font-extrabold text-purple-300');
expect(outlinePillButton).toHaveClass('font-extrabold text-purple-600');
});
it('should use `pill` classes', () => {
const theme = {
button: {
pill: {
off: 'font-extralight',
on: 'font-extrabold',
},
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, { label: "Normal button" }),
React.createElement(Button, { label: "Pill", pill: true })));
const normalButton = buttons()[0];
const pill = buttons()[1];
expect(normalButton).toHaveClass('font-extralight');
expect(pill).toHaveClass('font-extrabold');
});
it('should use `size` classes', () => {
const theme = {
button: {
size: {
xxl: 'font-extrabold',
},
},
};
render(React.createElement(Flowbite, { theme: { theme } },
React.createElement(Button, { size: "xxl" }, "Hello")));
const button = screen.getByText('Hello');
expect(button).toHaveClass('font-extrabold');
});
});
});
const button = () => screen.getByRole('button');
const buttonLink = () => screen.getByRole('link');
const buttonListItem = () => screen.getByRole('listitem');
const buttons = () => screen.getAllByRole('button');