diff --git a/src/__tests__/drawer-test.tsx b/src/__tests__/drawer-test.tsx new file mode 100644 index 000000000..f6dca5f14 --- /dev/null +++ b/src/__tests__/drawer-test.tsx @@ -0,0 +1,115 @@ +import * as React from 'react'; +import {makeTheme} from './test-utils'; +import {render, screen, waitFor} from '@testing-library/react'; +import ThemeContextProvider from '../theme-context-provider'; +import Drawer from '../drawer'; +import userEvent from '@testing-library/user-event'; + +const DrawerTest = ({ + onDismiss, + onButtonPrimaryPress, + onButtonSecondaryPress, + onButtonLinkPress, +}: { + onDismiss?: () => void; + onButtonPrimaryPress?: () => void; + onButtonSecondaryPress?: () => void; + onButtonLinkPress?: () => void; +}) => { + const [isOpen, setIsOpen] = React.useState(false); + return ( + + + {isOpen && ( + setIsOpen(false)} + button={{text: 'Primary', onPress: onButtonPrimaryPress}} + secondaryButton={{text: 'Secondary', onPress: onButtonSecondaryPress}} + buttonLink={{text: 'Link', onPress: onButtonLinkPress}} + /> + )} + + ); +}; + +test.each(['esc', 'overlay', 'x'])('Drawer dismiss: %s', async (dismissMethod: string) => { + const onDismissSpy = jest.fn(); + render(); + + const openButton = screen.getByRole('button', {name: 'open'}); + await userEvent.click(openButton); + + const drawer = await screen.findByRole('dialog'); + + switch (dismissMethod) { + case 'esc': + await userEvent.keyboard('{Escape}'); + break; + case 'overlay': + await userEvent.click(screen.getByTestId('drawerOverlay')); + break; + case 'x': + await userEvent.click(screen.getByRole('button', {name: 'CustomDismissLabel'})); + break; + default: + throw new Error('unexpected dismiss method'); + } + + await waitFor(() => { + expect(onDismissSpy).toHaveBeenCalledTimes(1); + expect(drawer).not.toBeInTheDocument(); + }); +}); + +test.each(['primary', 'secondary', 'link'])('Drawer close: %s', async (closeMethod: string) => { + const onButtonPrimaryPress = jest.fn(); + const onButtonSecondaryPress = jest.fn(); + const onButtonLinkPress = jest.fn(); + + render( + + ); + + const openButton = screen.getByRole('button', {name: 'open'}); + await userEvent.click(openButton); + + const drawer = await screen.findByRole('dialog'); + + switch (closeMethod) { + case 'primary': + await userEvent.click(screen.getByRole('button', {name: 'Primary'})); + break; + case 'secondary': + await userEvent.click(screen.getByRole('button', {name: 'Secondary'})); + break; + case 'link': + await userEvent.click(screen.getByRole('button', {name: 'Link'})); + break; + default: + throw new Error('unexpected dismiss method'); + } + + await waitFor(() => { + expect(drawer).not.toBeInTheDocument(); + }); + + switch (closeMethod) { + case 'primary': + expect(onButtonPrimaryPress).toHaveBeenCalledTimes(1); + break; + case 'secondary': + expect(onButtonSecondaryPress).toHaveBeenCalledTimes(1); + break; + case 'link': + expect(onButtonLinkPress).toHaveBeenCalledTimes(1); + break; + default: + throw new Error('unexpected dismiss method'); + } +}); diff --git a/src/__tests__/testid-test.tsx b/src/__tests__/testid-test.tsx index 63c981c76..8f2e6f359 100644 --- a/src/__tests__/testid-test.tsx +++ b/src/__tests__/testid-test.tsx @@ -22,6 +22,7 @@ import { CoverHero, Header, MainSectionHeader, + Drawer, } from '..'; import {makeTheme} from './test-utils'; @@ -288,3 +289,12 @@ test('Meter test ids', () => { }, ]); }); + +test('Drawer test ids', () => { + checkTestIds( {}} />, [ + { + componentName: 'Drawer', + internalTestIds: ['title', 'subtitle', 'description'], + }, + ]); +}); diff --git a/src/drawer.tsx b/src/drawer.tsx index 2fb6629f4..97fe526ac 100644 --- a/src/drawer.tsx +++ b/src/drawer.tsx @@ -19,7 +19,7 @@ import Divider from './divider'; import {getPrefixedDataAttributes} from './utils/dom'; import * as tokens from './text-tokens'; -import type {DataAttributes, TrackingEvent} from './utils/types'; +import type {DataAttributes, HeadingType, TrackingEvent} from './utils/types'; const PADDING_X_DESKTOP = 40; const PADDING_X_MOBILE = 16; @@ -131,13 +131,15 @@ type ButtonProps = { text: string; trackingEvent?: TrackingEvent | ReadonlyArray; trackEvent?: boolean; - onPress: () => unknown; + onPress?: () => unknown; }; type DrawerProps = { title?: string; subtitle?: string; description?: string; + titleAs?: HeadingType; + dismissLabel?: string; /** * this handler is mandatory. You should unmount the Drawer component on close. */ @@ -164,6 +166,8 @@ const Drawer = ({ title, subtitle, description, + titleAs = 'h2', + dismissLabel, width, onClose, onDismiss, @@ -186,8 +190,8 @@ const Drawer = ({ desktop: PADDING_X_DESKTOP, } as const; - const handleButtonPress = (pressHandlerFromProps: () => unknown) => { - layoutRef.current?.close().then(pressHandlerFromProps); + const handleButtonPress = (pressHandlerFromProps?: () => unknown) => { + layoutRef.current?.close().then(() => pressHandlerFromProps?.()); }; const showTitleDivider = !useIsInViewport(topScrollSignalRef, true, { @@ -214,7 +218,7 @@ const Drawer = ({ dataAttributes={{testid: 'dismissButton'}} onPress={() => layoutRef.current?.dismiss()} Icon={IconCloseRegular} - aria-label={texts.modalClose || t(tokens.modalClose)} + aria-label={dismissLabel || texts.modalClose || t(tokens.modalClose)} type="neutral" backgroundType="transparent" /> @@ -223,7 +227,9 @@ const Drawer = ({ {title && (
- {title} + + {title} +
)}