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();
});