import { Sentiment } from '../../common';
import { mockMatchMedia, render, screen } from '../../test-utils';
import { ActionPrompt, ActionPromptProps } from './ActionPrompt';
import { userEvent } from '@testing-library/user-event';
mockMatchMedia();
describe('ActionPrompt', () => {
const defaultProps: ActionPromptProps = {
title: 'Test Title',
action: {
label: 'Primary Action',
onClick: jest.fn(),
},
};
beforeEach(() => {
jest.clearAllMocks();
});
describe('Basic rendering', () => {
it('renders title', () => {
render();
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
it('renders description when provided', () => {
render();
expect(screen.getByText('Test description')).toBeInTheDocument();
});
});
[
{ sentiment: 'negative' as const, statusIconLabel: 'Error:' },
{ sentiment: 'warning' as const, statusIconLabel: 'Warning:' },
{ sentiment: 'neutral' as const, statusIconLabel: 'Information:' },
{ sentiment: 'success' as const, statusIconLabel: 'Success:' },
{ sentiment: 'proposition' as const, statusIconLabel: '' },
].forEach(({ sentiment, statusIconLabel }) => {
describe(sentiment, () => {
if (statusIconLabel) {
it('should render StatusIcon', () => {
render();
expect(screen.getByLabelText(statusIconLabel)).toBeInTheDocument();
});
}
});
});
describe('Actions', () => {
it('renders primary action button with correct label', () => {
render();
expect(screen.getByText('Primary Action')).toBeInTheDocument();
});
it('calls primary action onClick when clicked', async () => {
const onClick = jest.fn();
const user = userEvent.setup();
render();
const button = screen.getByRole('button', { name: 'Primary Action' });
await user.click(button);
expect(onClick).toHaveBeenCalledTimes(1);
});
it('renders primary action as link when href is provided', () => {
render(
,
);
const link = screen.getByRole('link', { name: 'Primary Action' });
expect(link).toHaveAttribute('href', '/test-url');
});
it('renders secondary action when provided', () => {
render(
,
);
expect(screen.getByText('Secondary Action')).toBeInTheDocument();
});
it('calls secondary action onClick when clicked', async () => {
const onClick = jest.fn();
const user = userEvent.setup();
render(
,
);
const button = screen.getByRole('button', { name: 'Secondary Action' });
await user.click(button);
expect(onClick).toHaveBeenCalledTimes(1);
});
it('renders secondary action as link when href is provided', () => {
render(
,
);
const link = screen.getByRole('link', { name: 'Secondary Action' });
expect(link).toHaveAttribute('href', '/secondary-url');
});
});
describe('Media', () => {
describe('Image media', () => {
it('renders custom image when imgSrc is provided', () => {
render(
,
);
const img = screen.getByRole('img', { name: 'Test image' });
expect(img).toBeInTheDocument();
expect(img).toHaveAttribute('src', '/test-image.jpg');
});
it('renders image with empty alt when aria-label is not provided', () => {
const { container } = render(
,
);
const img = container.querySelector('img[src="/test-image.jpg"]');
expect(img).toHaveAttribute('alt', '');
});
});
describe('Avatar media', () => {
it('renders avatar with image', () => {
const { container } = render(
,
);
const img = container.querySelector('img[src="/avatar.jpg"]');
expect(img).toBeInTheDocument();
expect(img).toHaveAttribute('src', '/avatar.jpg');
});
it('renders avatar with profile name', () => {
render();
expect(screen.getByText('JD')).toBeInTheDocument();
});
it('renders avatar with custom asset', () => {
render(
Icon } }}
/>,
);
expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
});
it('renders avatar with badge', () => {
render(
,
);
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
it('applies status badge for non-proposition sentiment when no badge is provided', () => {
render(
,
);
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
it('renders avatar for proposition sentiment when no badge is provided', () => {
render(
,
);
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
});
describe('Default media', () => {
it('renders GiftBox for proposition sentiment with no media', () => {
render();
expect(screen.getByTestId('gift-box-icon')).toBeInTheDocument();
});
it('renders StatusIcon for non-proposition sentiment with no media', () => {
render();
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
});
});
describe('Two actions styling', () => {
it('applies two actions class when secondary action is provided', () => {
render(
,
);
expect(screen.getByTestId('prompt')).toHaveClass('wds-action-prompt--with-two-actions');
});
it('does not apply two actions class when only primary action is provided', () => {
render();
expect(screen.getByTestId('prompt')).not.toHaveClass('wds-action-prompt--with-two-actions');
});
});
describe('Responsive behavior', () => {
it('renders buttons as block on mobile', () => {
// Mock mobile viewport
const mockMatchMediaFn = window.matchMedia as jest.Mock;
mockMatchMediaFn.mockImplementation((query: string) => ({
matches: query === '(max-width: 768px)',
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
}));
render(
,
);
expect(screen.getByText('Primary Action')).toBeInTheDocument();
expect(screen.getByText('Secondary')).toBeInTheDocument();
});
});
});