UNPKG

@vertisanpro/flowbite-react

Version:

Non-Official React components built for Flowbite and Tailwind CSS

255 lines (254 loc) 11.8 kB
/* 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');