import { render, screen } from '@testing-library/react'; import { Button, ButtonState, ButtonVariant } from '../Button'; import styles from '@patternfly/react-styles/css/components/Button/button'; const { primary, secondary, tertiary, danger, warning, link, plain, control, stateful } = ButtonVariant; const validDangerVariants = [secondary, link]; const invalidDangerVariants = [primary, tertiary, warning, plain, control, stateful]; const invalidInlineVariants = [primary, secondary, tertiary, danger, warning, plain, control, stateful]; Object.values(ButtonVariant).forEach((variant) => { if (variant !== 'primary') { test(`Does not render with class ${styles.modifiers[variant]} by default`, () => { render(); expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers[variant]); }); } test(`Renders with class ${styles.modifiers[variant]} when variant=${variant}`, () => { render(); expect(screen.getByRole('button')).toHaveClass(styles.modifiers[variant]); }); }); test('Renders without children', () => { render(
); expect(screen.getByTestId('container').firstChild).toBeVisible(); }); test(`Renders with class ${styles.button} by default`, () => { render(); expect(screen.getByRole('button')).toHaveClass(styles.button); }); test(`Renders with class ${styles.modifiers.primary} by default`, () => { render(); expect(screen.getByText('Button').parentElement).toHaveClass(styles.modifiers.primary); }); test('Renders with custom class', () => { render(); expect(screen.getByRole('button')).toHaveClass('custom-class'); }); test('Renders with an aria-label', () => { const label = 'aria-label test'; render(); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.block); }); test(`Renders with class ${styles.modifiers.clicked} when isClicked = true`, () => { render(); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.clicked); }); test(`Does not render with class ${styles.modifiers.disabled} by default when isDisabled = true`, () => { render(); expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.disabled); }); test(`Renders with class ${styles.modifiers.disabled} when isDisabled = true and component is not a button`, () => { render( ); expect(screen.getByText('Disabled Anchor Button').parentElement).toHaveClass(styles.modifiers.disabled); }); test(`aria-disabled and class ${styles.modifiers.ariaDisabled} are not rendered when isAriaDisabled is not passed by default`, () => { render(); const button = screen.getByRole('button'); expect(button).not.toHaveAttribute('aria-disabled'); expect(button).not.toHaveClass(styles.modifiers.ariaDisabled); }); test(`aria-disabled and class ${styles.modifiers.ariaDisabled} are not rendered when isDisabled is true, but isAriaDisabled is not passed`, () => { render(); const button = screen.getByRole('button'); expect(button).not.toHaveAttribute('aria-disabled'); expect(button).not.toHaveClass(styles.modifiers.ariaDisabled); }); test(`Renders with class ${styles.modifiers.ariaDisabled} and aria-disabled attribute when isAriaDisabled = true`, () => { render(); const button = screen.getByRole('button'); expect(button).toHaveAttribute('aria-disabled', 'true'); expect(button).toHaveClass(styles.modifiers.ariaDisabled); }); test('Does not disable button when isDisabled = true and component = a', () => { render( ); expect(screen.getByText('Disabled yet focusable button')).not.toHaveProperty('disabled'); }); test(`Renders with class ${styles.modifiers.unread} by default when variant = stateful`, () => { render(); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.unread); }); Object.values(ButtonState).forEach((state) => { test(`Renders with class ${styles.modifiers[state]} when state = ${state} and variant = stateful`, () => { render( ); expect(screen.getByRole('button')).toHaveClass(styles.modifiers[state]); }); }); Object.values(validDangerVariants).forEach((validDangerVariant) => { test(`Renders with class ${styles.modifiers.danger} when isDanger is true and variant = ${validDangerVariant}`, () => { render( ); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.danger); }); }); Object.values(invalidDangerVariants).forEach((invalidDangerVariant) => { test(`Does not render with class ${styles.modifiers.danger} when isDanger is true and variant = ${invalidDangerVariant}`, () => { render( ); expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.danger); }); }); test(`Renders with class ${styles.modifiers.inline} when isInline = true and variant = link`, () => { render( ); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.inline); }); Object.values(invalidInlineVariants).forEach((invalidInlineVariant) => { test(`Does not render with class ${styles.modifiers.inline} when isInline is true and variant = ${invalidInlineVariants}`, () => { render( ); expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.inline); }); }); test(`Renders with class ${styles.modifiers.small} when size = sm`, () => { render(); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.small); }); test(`Renders with class ${styles.modifiers.displayLg} when size = lg`, () => { render(); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.displayLg); }); test(`Renders with classes ${styles.modifiers.inProgress} when isLoading = true`, () => { render( ); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.inProgress); }); test(`Renders with class ${styles.modifiers.progress} when isLoading is true`, () => { render( ); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.progress); }); test(`Renders with class ${styles.modifiers.progress} when isLoading is defined and isLoading = false`, () => { render( ); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.progress); }); test(`Renders without class ${styles.modifiers.progress} when isLoading = false and variant = plain`, () => { render( ); expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.progress); }); test(`Renders with class ${styles.modifiers.circle} when isCircle is true`, () => { render(); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.circle); }); test(`Renders custom icon with class ${styles.modifiers.inProgress} when isLoading = true and icon is present`, () => { render( ); expect(screen.getByText('anchor button').parentElement?.tagName).toBe('A'); }); test('aria-disabled is set to true and tabIndex to -1 if component is not a button and is disabled', () => { render( ); const anchor = screen.getByText('Disabled Anchor Button').parentElement; expect(anchor).toHaveAttribute('tabindex', '-1'); expect(anchor).toHaveAttribute('aria-disabled', 'true'); }); test('setting tab index through props', () => { render(); expect(screen.getByRole('button')).toHaveAttribute('tabindex', '0'); }); test('Does not render aria-expanded by default', () => { render(); expect(screen.getByRole('button')).not.toHaveAttribute('aria-expanded'); }); test('Renders with aria-expanded when isExpanded is true', () => { render(); expect(screen.getByRole('button')).toHaveAttribute('aria-expanded', 'true'); }); test('Renders with aria-expanded when isExpanded is false', () => { render(); expect(screen.getByRole('button')).toHaveAttribute('aria-expanded', 'false'); }); // Remove this test when isExpanded prop in Button code is moved to after the spread props test('Passing aria-expanded overrides isExpanded', () => { render( ); expect(screen.getByRole('button')).toHaveAttribute('aria-expanded', 'false'); }); describe('Hamburger button', () => { test('Throws console error when isHamburger is true and isExpanded is not passed', () => { const consoleError = jest.spyOn(console, 'error').mockImplementation(); render( ); expect(consoleError).not.toHaveBeenCalledWith( 'Button: you must provide either visible text content or an accessible name via the aria-label or aria-labelledby properties.' ); }); // TODO: Remove isHamburger in breaking change to throw error for any button that does not have children or aria name test('Does not throw console error when isHamburger is true and aria-label is passed', () => { const consoleError = jest.spyOn(console, 'error').mockImplementation(); render(); expect(consoleError).not.toHaveBeenCalledWith( 'Button: you must provide either visible text content or an accessible name via the aria-label or aria-labelledby properties.' ); }); // TODO: Remove isSettings in breaking change to throw error for any button that does not have children or aria name test('Does not throw console error when isSettings is true and aria-label is passed', () => { const consoleError = jest.spyOn(console, 'error').mockImplementation(); render(); expect(consoleError).not.toHaveBeenCalledWith( 'Button: you must provide either visible text content or an accessible name via the aria-label or aria-labelledby properties.' ); }); // TODO: Remove isFavorite in breaking change to throw error for any button that does not have children or aria name test('Does not throw console error when isFavorite is true and aria-label is passed', () => { const consoleError = jest.spyOn(console, 'error').mockImplementation(); render(); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.docked); }); test(`Does not render with class ${styles.modifiers.docked} when isDocked is not passed`, () => { render(); expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.docked); }); test(`Renders with class ${styles.modifiers.textExpanded} when isTextExpanded = true and isDocked = true`, () => { render( ); expect(screen.getByRole('button')).toHaveClass(styles.modifiers.textExpanded); }); test(`Does not render with class ${styles.modifiers.textExpanded} when isTextExpanded is not passed`, () => { render(); expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.textExpanded); }); test(`Does not render with class ${styles.modifiers.textExpanded} when isTextExpanded = true but isDocked is not passed`, () => { render(); expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.textExpanded); }); test(`Renders with both ${styles.modifiers.docked} and ${styles.modifiers.textExpanded} when both props are true`, () => { render( ); const button = screen.getByRole('button'); expect(button).toHaveClass(styles.modifiers.docked); expect(button).toHaveClass(styles.modifiers.textExpanded); }); }); test(`Renders basic button`, () => { const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); });