import React, { useState } from 'react'; import { act, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { axe } from 'jest-axe'; import MarketingModal from '..'; const WrappedModal = ({ open: initialOpen, buttonProps: buttonPropsProp, ...props }: Partial>) => { const [open, setOpen] = useState(initialOpen); const defaultButtonProps = Object.freeze({ children: 'Button action', onClick: () => setOpen(false), }); const buttonProps = buttonPropsProp ? buttonPropsProp : defaultButtonProps; return ( setOpen(false)} onLinkClick={() => setOpen(false)} graphic={} {...props} > {props.children ?? 'Content text'} ); }; function renderModal( props: Partial> = {}, ) { return render(); } describe('packages/marketing-modal', () => { // Mock dialog methods for JSDOM environment beforeAll(() => { HTMLDialogElement.prototype.show = jest.fn(function mock( this: HTMLDialogElement, ) { this.open = true; }); HTMLDialogElement.prototype.showModal = jest.fn(function mock( this: HTMLDialogElement, ) { this.open = true; }); HTMLDialogElement.prototype.close = jest.fn(function mock( this: HTMLDialogElement, ) { this.open = false; }); }); describe('a11y', () => { test('does not have basic accessibility issues', async () => { const { container, getByText } = renderModal({ open: true }); const results = await axe(container); expect(results).toHaveNoViolations(); let newResults = null as any; act(() => void userEvent.click(getByText('Button action'))); await act(async () => { newResults = await axe(container); }); expect(newResults).toHaveNoViolations(); }); }); test('does not render if closed', () => { const { queryByText } = renderModal(); expect(queryByText('Content text')).toBeNull(); }); test('renders if open', () => { const { getByText, getByLabelText } = renderModal({ open: true }); expect(getByLabelText('Image graphic')).toBeVisible(); expect(getByText('Title text')).toBeVisible(); expect(getByText('Content text')).toBeVisible(); expect(getByText('Button action')).toBeVisible(); expect(getByText('Link action')).toBeVisible(); }); describe('buttonProps', () => { test('fires `onClick` when button is clicked', () => { const buttonClickSpy = jest.fn(); const { getByText } = renderModal({ open: true, buttonProps: { children: 'Custom button text', onClick: buttonClickSpy, }, }); const button = getByText('Custom button text'); expect(button).toBeVisible(); userEvent.click(button); expect(buttonClickSpy).toHaveBeenCalledTimes(1); }); test('renders custom button text', () => { const { getByText } = renderModal({ open: true, buttonProps: { children: 'custom button text', }, }); expect(getByText('custom button text')).toBeVisible(); }); }); test('fires `onLinkClick` when link is clicked', () => { const linkClickSpy = jest.fn(); const closeSpy = jest.fn(); const { getByText } = renderModal({ open: true, onLinkClick: linkClickSpy, onClose: closeSpy, }); const button = getByText('Link action'); expect(button).toBeVisible(); userEvent.click(button); expect(linkClickSpy).toHaveBeenCalledTimes(1); expect(closeSpy).not.toHaveBeenCalled(); }); describe('closes when', () => { test('escape key is pressed', async () => { const { getByRole } = renderModal({ open: true }); const modal = getByRole('dialog'); userEvent.keyboard('{Escape}'); await waitFor(() => expect(modal).not.toBeVisible()); }); test('x icon is clicked', async () => { const { getByLabelText, getByRole } = renderModal({ open: true }); const modal = getByRole('dialog'); const x = getByLabelText('Close modal'); userEvent.click(x); await waitFor(() => expect(modal).not.toBeVisible()); }); }); test('renders blob when `showBlob` is true', () => { const { getByTestId } = renderModal({ open: true, showBlob: true, }); expect(getByTestId('svg-blob')).toBeVisible(); }); describe('initial focus', () => { test('focuses button when modal opens', async () => { renderModal({ open: true }); const button = screen.getByRole('button', { name: 'Button action' }); await waitFor(() => { expect(button).toHaveFocus(); }); }); test('can be customized with initialFocus prop', async () => { const customFocusRef = React.createRef(); renderModal({ open: true, initialFocus: customFocusRef, children: ( <> Content text ), }); const customButton = screen.getByRole('button', { name: 'Custom action', }); const defaultButton = screen.getByRole('button', { name: 'Button action', }); await waitFor(() => { expect(customButton).toHaveFocus(); expect(defaultButton).not.toHaveFocus(); }); }); }); });