diff --git a/app/soapbox/components/ui/icon-button/icon-button.tsx b/app/soapbox/components/ui/icon-button/icon-button.tsx index 291b0b4f8..10d08fc80 100644 --- a/app/soapbox/components/ui/icon-button/icon-button.tsx +++ b/app/soapbox/components/ui/icon-button/icon-button.tsx @@ -22,6 +22,7 @@ const IconButton = React.forwardRef((props: IIconButton, ref: React.ForwardedRef 'bg-white dark:bg-transparent': !transparent, }, className)} {...filteredProps} + data-testid='icon-button' > diff --git a/app/soapbox/components/ui/modal/__tests__/modal.test.tsx b/app/soapbox/components/ui/modal/__tests__/modal.test.tsx new file mode 100644 index 000000000..3894a4604 --- /dev/null +++ b/app/soapbox/components/ui/modal/__tests__/modal.test.tsx @@ -0,0 +1,138 @@ +import userEvent from '@testing-library/user-event'; +import React from 'react'; + +import { render, screen } from '../../../../jest/test-helpers'; +import Modal from '../modal'; + +describe('', () => { + it('renders', () => { + render(); + expect(screen.getByTestId('modal')).toBeInTheDocument(); + }); + + it('renders children', () => { + render(
); + expect(screen.getByTestId('child')).toBeInTheDocument(); + }); + + it('focuses the primary action', () => { + render( + null} + confirmationText='Click me' + />, + ); + + expect(screen.getByRole('button')).toHaveFocus(); + }); + + describe('onClose prop', () => { + it('renders the Icon to close the modal', async() => { + const mockFn = jest.fn(); + const user = userEvent.setup(); + + render(); + expect(screen.getByTestId('icon-button')).toBeInTheDocument(); + + expect(mockFn).not.toBeCalled(); + await user.click(screen.getByTestId('icon-button')); + expect(mockFn).toBeCalled(); + }); + + it('does not render the Icon to close the modal', () => { + render(); + expect(screen.queryAllByTestId('icon-button')).toHaveLength(0); + }); + }); + + describe('confirmationAction prop', () => { + it('renders the confirmation button', async() => { + const mockFn = jest.fn(); + const user = userEvent.setup(); + + render( + , + ); + + expect(mockFn).not.toBeCalled(); + await user.click(screen.getByRole('button')); + expect(mockFn).toBeCalled(); + }); + + it('does not render the actions to', () => { + render(); + expect(screen.queryAllByTestId('modal-actions')).toHaveLength(0); + }); + + describe('with secondaryAction', () => { + it('renders the secondary button', async() => { + const confirmationAction = jest.fn(); + const secondaryAction = jest.fn(); + const user = userEvent.setup(); + + render( + , + ); + + await user.click(screen.getByText(/secondary/i)); + expect(secondaryAction).toBeCalled(); + expect(confirmationAction).not.toBeCalled(); + }); + + it('does not render the secondary action', () => { + render( + null} + confirmationText='Click me' + />, + ); + expect(screen.queryAllByRole('button')).toHaveLength(1); + }); + }); + + describe('with cancelAction', () => { + it('renders the cancel button', async() => { + const confirmationAction = jest.fn(); + const cancelAction = jest.fn(); + const user = userEvent.setup(); + + render( + , + ); + + await user.click(screen.getByText(/cancel/i)); + expect(cancelAction).toBeCalled(); + expect(confirmationAction).not.toBeCalled(); + }); + + it('does not render the cancel action', () => { + render( + null} + confirmationText='Click me' + />, + ); + expect(screen.queryAllByRole('button')).toHaveLength(1); + }); + }); + }); +}); diff --git a/app/soapbox/components/ui/modal/modal.tsx b/app/soapbox/components/ui/modal/modal.tsx index d6d23ce92..efe580c23 100644 --- a/app/soapbox/components/ui/modal/modal.tsx +++ b/app/soapbox/components/ui/modal/modal.tsx @@ -17,7 +17,7 @@ interface IModal { confirmationDisabled?: boolean, confirmationText?: string, confirmationTheme?: 'danger', - onClose: () => void, + onClose?: () => void, secondaryAction?: () => void, secondaryText?: string, title: string | React.ReactNode, @@ -46,7 +46,7 @@ const Modal: React.FC = ({ }, [buttonRef]); return ( -
+
@@ -71,7 +71,7 @@ const Modal: React.FC = ({
{confirmationAction && ( -
+
{cancelAction && (