import { screen, render } from '@testing-library/react'; import { ClipboardCopy, ClipboardCopyVariant } from '../ClipboardCopy'; import styles from '@patternfly/react-styles/css/components/ClipboardCopy/clipboard-copy'; import truncateStyles from '@patternfly/react-styles/css/components/Truncate/truncate'; import userEvent from '@testing-library/user-event'; jest.mock('../../../helpers/GenerateId/GenerateId'); jest.mock('../ClipboardCopyButton', () => ({ ClipboardCopyButton: ({ 'aria-label': ariaLabel, children, entryDelay, exitDelay, maxWidth, position, onClick }) => (

{`exitDelay: ${exitDelay}`}

{`entryDelay: ${entryDelay}`}

{`maxWidth: ${maxWidth}`}

{`position: ${position}`}

{`button-ariaLabel: ${ariaLabel}`}

{`children: ${children}`}
) })); jest.mock('../ClipboardCopyToggle', () => ({ ClipboardCopyToggle: ({ 'aria-label': ariaLabel }) => (

{`toggle-ariaLabel: ${ariaLabel}`}

) })); jest.mock('../../Truncate', () => ({ Truncate: ({ className, trailingNumChars, content, position, tooltipPosition, ...props }) => (

{`Truncate content: ${content}`}

{`Truncate className: ${className}`}

{`Truncate position: ${position}`}

{`Truncate trailingNumChars: ${trailingNumChars}`}

{`Truncate tooltipPosition: ${tooltipPosition}`}

{children}
) })); const children = 'Copyable text'; const testId = 'clipboard-copy'; test(`Renders with class ${styles.clipboardCopy} by default`, () => { render({children}); expect(screen.getByTestId(testId)).toHaveClass(styles.clipboardCopy, { exact: true }); }); test(`Renders with custom class when className is passed`, () => { render( {children} ); expect(screen.getByTestId(testId)).toHaveClass('test-class'); }); test(`Does not render with class ${styles.modifiers.inline} by default`, () => { render({children}); expect(screen.getByTestId(testId)).not.toHaveClass(styles.modifiers.inline); }); test(`Does not render with class ${styles.modifiers.inline} if variant is not inline-compact`, () => { render( {children} ); expect(screen.getByTestId(testId)).not.toHaveClass(styles.modifiers.inline); }); test(`Renders with class ${styles.modifiers.inline} when variant is inline-compact`, () => { render( {children} ); expect(screen.getByTestId(testId)).toHaveClass(styles.modifiers.inline); }); test(`Does not render with class ${styles.modifiers.expanded} by default`, () => { render({children}); expect(screen.getByTestId(testId)).not.toHaveClass(styles.modifiers.expanded); }); test(`Renders with class ${styles.modifiers.expanded} when isExpanded is passed`, () => { render( {children} ); expect(screen.getByTestId(testId)).toHaveClass(styles.modifiers.expanded); }); test(`Does not render with class ${styles.modifiers.block} by default`, () => { render({children}); expect(screen.getByTestId(testId)).not.toHaveClass(styles.modifiers.block); }); test(`Renders with class ${styles.modifiers.block} when isBlock is passed`, () => { render( {children} ); expect(screen.getByTestId(testId)).toHaveClass(styles.modifiers.block); }); test('Spreads additional props to container div', () => { render( {children} ); expect(screen.getByTestId(testId)).toHaveAttribute('role', 'group'); }); test(`Renders children without class ${styles.modifiers.code} when variant is inline-compact and isCode is not passed`, () => { render( {children} ); expect(screen.getByText(children)).not.toHaveClass(styles.modifiers.code); }); test(`Renders children with class ${styles.modifiers.code} when variant is inline-compact and isCode is passed`, () => { render( {children} ); expect(screen.getByText(children)).toHaveClass(styles.modifiers.code); }); test('Does not render content passed to additionalActions by default', () => { render({children}); expect(screen.queryByText('Additional action')).toBeNull(); }); test('Does not render content passed to additionalActions when variant is not inline-compact', () => { render( {children} ); expect(screen.queryByText('Additional action')).toBeNull(); }); test('Renders content passed to additionalActions when variant is inline-compact', () => { render( {children} ); expect(screen.getByText('Additional action')).toBeVisible(); }); test('Passes hoverTip to ClipboardCopyButton by default', () => { render({children}); expect(screen.getByText('button-ariaLabel: hover tip')).toBeVisible(); expect(screen.getByText('children: hover tip')).toBeVisible(); }); test('Passes hoverTip to ClipboardCopyButton when variant is inline-compact', () => { render( {children} ); expect(screen.getByText('button-ariaLabel: hover tip')).toBeVisible(); expect(screen.getByText('children: hover tip')).toBeVisible(); }); test('Passes clickTip when ClipboardCopyButton clicked', async () => { const user = userEvent.setup(); render({children}); await user.click(screen.getByRole('button', { name: 'Test CCB clicker' })); expect(screen.getByText('children: click tip')).toBeVisible(); }); test('Passes entryDelay to ClipboardCopyButton by default', () => { render({children}); expect(screen.getByText('entryDelay: 100')).toBeVisible(); }); test('Passes entryDelay to ClipboardCopyButton when variant is inline-compact', () => { render( {children} ); expect(screen.getByText('entryDelay: 100')).toBeVisible(); }); test('Passes exitDelay to ClipboardCopyButton by default', () => { render({children}); expect(screen.getByText('exitDelay: 100')).toBeVisible(); }); test('Passes exitDelay to ClipboardCopyButton when variant is inline-compact', () => { render( {children} ); expect(screen.getByText('exitDelay: 100')).toBeVisible(); }); test('Passes maxWidth to ClipboardCopyButton by default', () => { render({children}); expect(screen.getByText('maxWidth: 100')).toBeVisible(); }); test('Passes maxWidth to ClipboardCopyButton when variant is inline-compact', () => { render( {children} ); expect(screen.getByText('maxWidth: 100')).toBeVisible(); }); test('Passes position to ClipboardCopyButton by default', () => { render({children}); expect(screen.getByText('position: bottom')).toBeVisible(); }); test('Passes position to ClipboardCopyButton when variant is inline-compact', () => { render( {children} ); expect(screen.getByText('position: bottom')).toBeVisible(); }); test('Passes copyAriaLabel to ClipboardCopyButton', () => { render({children}); expect(screen.getByText('button-ariaLabel: Copy text')).toBeVisible(); }); test('Passes copyAriaLabel over hoverTip to ClipboardCopyButton when both are provided', () => { render( {children} ); expect(screen.getByText('button-ariaLabel: Copy text')).toBeVisible(); }); test('Passes toggleAriaLabel to ClipboardCopyToggle when variant is expansion', () => { render( {children} ); expect(screen.getByText('toggle-ariaLabel: toggle label')).toBeVisible(); }); test('Does not set textinput to readonly when isReadOnly is not passed', () => { render({children}); expect(screen.getByRole('textbox')).not.toHaveAttribute('readonly'); }); test('Passes isReadOnly to TextInput', () => { render({children}); expect(screen.getByRole('textbox')).toHaveAttribute('readonly'); }); test('Passes textAriaLabel to TextInput', () => { render({children}); expect(screen.getByRole('textbox')).toHaveAccessibleName('text label'); }); test('Passes inputId to TextInput', () => { render({children}); expect(screen.getByRole('textbox')).toHaveAttribute('id', 'custom-input-id'); }); test('Passes inputName to TextInput', () => { render({children}); expect(screen.getByRole('textbox')).toHaveAttribute('name', 'custom-input-name'); }); test('Calls onChange when ClipboardCopy textinput is typed in', async () => { const onChangeMock = jest.fn(); const user = userEvent.setup(); const typedText = 'stuff'; render({children}); await user.type(screen.getByRole('textbox'), typedText); expect(onChangeMock).toHaveBeenCalledTimes(typedText.length); }); test('Does not call onChange when ClipboardCopy textinput is not typed in', async () => { const onChangeMock = jest.fn(); const user = userEvent.setup(); const typedText = 'stuff'; render( <> {children} ); await user.type(screen.getByRole('textbox', { name: 'native input' }), typedText); expect(onChangeMock).not.toHaveBeenCalled(); }); test('Calls onFocus when ClipboardCopy textinput is focused', async () => { const onFocusMock = jest.fn(); const user = userEvent.setup(); render({children}); await user.click(screen.getByRole('textbox')); expect(onFocusMock).toHaveBeenCalledTimes(1); }); test('Does not call onFocus when ClipboardCopy textinput is not focused', async () => { const onFocusMock = jest.fn(); const user = userEvent.setup(); render( <> {children} ); await user.click(screen.getByRole('textbox', { name: 'native input' })); expect(onFocusMock).not.toHaveBeenCalled(); }); test('Calls onBlur when ClipboardCopy textinput loses focus', async () => { const onBlurMock = jest.fn(); const user = userEvent.setup(); render( <> {children} ); await user.click(screen.getByRole('textbox', { name: 'Copyable input' })); await user.click(screen.getByRole('textbox', { name: 'native input' })); expect(onBlurMock).toHaveBeenCalledTimes(1); }); test('Does not call onBlur when ClipboardCopy textinput does not lose focus', async () => { const onBlurMock = jest.fn(); const user = userEvent.setup(); render( <> {children} ); await user.click(screen.getByRole('textbox', { name: 'native input' })); expect(onBlurMock).not.toHaveBeenCalled(); }); test('Calls onCopy when ClipboardCopyButton is clicked', async () => { const onCopyMock = jest.fn(); const user = userEvent.setup(); render({children}); await user.click(screen.getByRole('button', { name: 'Test CCB clicker' })); expect(onCopyMock).toHaveBeenCalledTimes(1); }); test('Does not call onCopy when ClipboardCopyButton is not clicked', async () => { const onCopyMock = jest.fn(); const user = userEvent.setup(); render( <> {children} ); await user.click(screen.getByRole('button', { name: 'Test native clicker' })); expect(onCopyMock).not.toHaveBeenCalled(); }); test('Can take array of strings as children', async () => { const onCopyMock = jest.fn(); const user = userEvent.setup(); const childrenArray = children.split(' '); // sanity check to ensure we are checking an array with at least 2 elements expect(childrenArray.length).toBeGreaterThan(1); render({childrenArray}); await user.click(screen.getByRole('button', { name: 'Test CCB clicker' })); expect(onCopyMock).toHaveBeenCalledWith(expect.any(Object), children); }); describe('ClipboardCopy with truncation', () => { test(`Does not render ClipboardCopy component with class ${styles.modifiers.truncate} by default`, () => { render({children}); expect(screen.getByTestId(testId)).not.toHaveClass(styles.modifiers.truncate); }); test(`Does not render ClipboardCopy component with class ${styles.modifiers.truncate} for expansion variant`, () => { render( {children} ); expect(screen.getByTestId(testId)).not.toHaveClass(styles.modifiers.truncate); }); test(`Does not render ClipboardCopy component with class ${styles.modifiers.truncate} for inlinecompact variant and truncation is false`, () => { render( {children} ); expect(screen.getByTestId(testId)).not.toHaveClass(styles.modifiers.truncate); }); test(`Renders ClipboardCopy component with class ${styles.modifiers.truncate} when truncation is true and variant is inline-compact`, () => { render( {children} ); expect(screen.getByTestId(testId)).toHaveClass(styles.modifiers.truncate); }); test(`Renders ClipboardCopy component with class ${styles.modifiers.truncate} when truncation is an object and variant is inlinecompact`, () => { render( {children} ); expect(screen.getByTestId(testId)).toHaveClass(styles.modifiers.truncate); }); test('Does not render with Truncate component by default', () => { render({children}); expect(screen.queryByTestId('Truncate-mock')).not.toBeInTheDocument(); }); test('Does not render with Truncate component when truncation is true and variant is not inline-compact', () => { render({children}); expect(screen.queryByTestId('Truncate-mock')).not.toBeInTheDocument(); }); test('Does not render with Truncate component when truncation is true and variant is expansion', () => { render( {children} ); expect(screen.queryByTestId('Truncate-mock')).not.toBeInTheDocument(); }); test('Does not render with Truncate component when truncation is an object and variant is not inline-compact', () => { render({children}); expect(screen.queryByTestId('Truncate-mock')).not.toBeInTheDocument(); }); test('Does not render with Truncate component when truncation is an object and variant is expansion', () => { render( {children} ); expect(screen.queryByTestId('Truncate-mock')).not.toBeInTheDocument(); }); test('Does not render with Truncate component when variant="inline-compact" and truncation is false', () => { render({children}); expect(screen.queryByTestId('Truncate-mock')).not.toBeInTheDocument(); }); test('Renders with Truncate component when variant="inline-compact" and truncation is true', () => { render( {children} ); expect(screen.getByTestId('Truncate-mock')).toBeInTheDocument(); }); test('Passes children to Truncate content prop when variant="inline-compact" and truncation is true', () => { render( {children} ); expect(screen.getByText(`Truncate content: ${children}`)).toBeInTheDocument(); }); test('Renders with Truncate component when variant="inline-compact" and truncation is an object', () => { render( {children} ); expect(screen.getByTestId('Truncate-mock')).toBeInTheDocument(); }); test('Passes children to Truncate content prop when variant="inline-compact" and truncation is an object', () => { render( {children} ); expect(screen.getByText(`Truncate content: ${children}`)).toBeInTheDocument(); }); test('Passes className prop to Truncate when variant="inline-compact" and truncation is passed', () => { render( {children} ); expect(screen.getByText(`Truncate className: clipboard-truncate`)).toBeInTheDocument(); }); test('Passes trailingNumChars prop to Truncate when variant="inline-compact" and truncation is passed', () => { render( {children} ); expect(screen.getByText(`Truncate trailingNumChars: 5`)).toBeInTheDocument(); }); test('Passes position prop to Truncate when variant="inline-compact" and truncation is passed', () => { render( {children} ); expect(screen.getByText(`Truncate position: start`)).toBeInTheDocument(); }); test('Passes tooltipPosition prop to Truncate when variant="inline-compact" and truncation is passed', () => { render( {children} ); expect(screen.getByText(`Truncate tooltipPosition: bottom`)).toBeInTheDocument(); }); }); test('Matches snapshot', () => { const { asFragment } = render( {children} ); expect(asFragment()).toMatchSnapshot(); });