import { Freeze } from '@transferwise/icons';
import { mockMatchMedia, render, screen, userEvent } from '../test-utils';
import Button, { ButtonProps } from './Button.resolver';
import { CommonProps } from './Button.types';
mockMatchMedia();
describe('Button', () => {
const legacyProps: ButtonProps = {
as: 'button',
priority: 'primary',
size: 'md',
type: 'accent',
};
const newProps: ButtonProps = {
as: 'button',
v2: true,
priority: 'primary',
size: 'md',
};
const testId = 'new-button';
it('renders LegacyButton when v2 is false', () => {
render();
const button = screen.getByText('Legacy Button');
expect(button).toBeInTheDocument();
expect(button).toHaveClass('btn btn-md np-btn np-btn-md btn-accent btn-priority-1');
});
it('renders the new Button when v2 is true', () => {
render(
,
);
const button = screen.getByTestId('new-button');
expect(button).toBeInTheDocument();
expect(button).toHaveClass('wds-Button wds-Button--medium wds-Button--primary');
});
describe('render as HTML anchor', () => {
const href = 'https://example.com';
const name = 'Button as link';
describe('v2', () => {
describe('rendered HTMLS element', () => {
it('should render as button by default', () => {
render();
expect(screen.getByRole('button', { name })).toBeInTheDocument();
});
it('should render as link if href is provided', () => {
render(
,
);
expect(screen.getByRole('link', { name })).toHaveAttribute('href', href);
});
it('should render a HTML anchor if `as="a"` is provided', () => {
render(
,
);
expect(screen.getByText(name).closest('a')).toBeInTheDocument();
});
it('should render as a button if `href` is set together with `as="button"`', () => {
render(
,
);
expect(screen.getByRole('button', { name })).toBeInTheDocument();
});
});
describe('HTML attributes', () => {
it('should not set `type` if rendered as HTML anchor', () => {
render(
,
);
expect(screen.getByRole('link')).not.toHaveAttribute('type');
});
it('should not set `href` or `target` if rendered as HTML button', () => {
render(
,
);
const button = screen.getByRole('button');
expect(button).not.toHaveAttribute('href');
expect(button).not.toHaveAttribute('target');
});
});
describe('disabled mode', () => {
describe('button', () => {
it('should not be disabled by default', () => {
render();
const button = screen.getByRole('button');
expect(button).toBeEnabled();
expect(button).not.toHaveAttribute('aria-disabled');
});
it('should respect disabled mode and set it only via the `disabled` attribute', () => {
render(
,
);
const button = screen.getByRole('button');
expect(button).toBeDisabled();
expect(button).not.toHaveAttribute('aria-disabled');
});
});
describe('anchor', () => {
it('should not be disabled by default', () => {
render(
,
);
const button = screen.getByRole('link');
expect(button).toBeEnabled();
expect(button).not.toHaveAttribute('aria-disabled');
});
it('should respect disabled mode', () => {
render(
,
);
const button = screen.getByRole('link');
expect(button).toHaveAttribute('aria-disabled');
expect(button).toBeEnabled();
expect(button).not.toHaveAttribute('href');
});
});
});
describe('loading mode', () => {
describe('button', () => {
it('should not be loading by default', () => {
render();
const button = screen.getByRole('button');
expect(button).toBeEnabled();
expect(button).not.toHaveAttribute('aria-busy');
});
it('should respect loading mode', () => {
render(
,
);
const button = screen.getByRole('button');
expect(button).toHaveAttribute('aria-busy');
// the `disabled` attribute is not set to keep the button
// focusable but aria attribute is defined to make it
// announced properly by the assistive tech
expect(button).toBeEnabled();
expect(button).toHaveAttribute('aria-disabled');
});
});
describe('anchor', () => {
it('should not be loading by default', () => {
render(
,
);
const button = screen.getByRole('link');
expect(button).toBeEnabled();
expect(button).not.toHaveAttribute('aria-busy');
expect(button).not.toHaveAttribute('aria-disabled');
});
it('should respect loading mode', () => {
render(
,
);
const button = screen.getByRole('link');
expect(button).toHaveAttribute('aria-busy');
// the `disabled` attribute is not set to keep the button
// focusable but aria attribute is defined to make it
// announced properly by the assistive tech
expect(button).toBeEnabled();
expect(button).toHaveAttribute('aria-disabled');
expect(button).not.toHaveAttribute('href');
});
});
describe('content id', () => {
it('should not set id for content by default', () => {
const { container } = render();
expect(container.querySelector('[id$="_content"]')).not.toBeInTheDocument();
});
it('should set id for content by default if `id` is passed as a button prop', () => {
const { container } = render(
,
);
expect(container.querySelector('#myId_content')).toBeInTheDocument();
});
});
});
});
});
it('does not set type when type is in LegacyButtonType', () => {
// @ts-expect-error here we intentionally set wrong value to test `type` attr in DOM
const legacyTypeProps: ButtonProps = { ...newProps, type: 'accent' };
render(
,
);
const button = screen.getByTestId('new-button');
expect(button).toBeInTheDocument();
expect(button).not.toHaveAttribute('type');
});
it('sets type when type is not in LegacyButtonType', () => {
const buttonTypeProps: ButtonProps = {
...newProps,
type: 'submit',
};
render(
,
);
const button = screen.getByTestId('new-button');
expect(button).toBeInTheDocument();
expect(button).toHaveAttribute('type', 'submit');
});
describe('addons', () => {
const avatarProp: CommonProps['addonStart'] = {
type: 'avatar',
value: [{ asset: }],
};
const iconProp: CommonProps['addonStart'] = { type: 'icon', value: };
const renderAllPriorities = (props: CommonProps) =>
render(
<>
>,
);
describe('addonsStart', () => {
describe('large', () => {
it('should not support avatars', () => {
renderAllPriorities({
v2: true,
size: 'lg',
addonStart: avatarProp,
});
expect(screen.queryAllByTestId('freeze-icon')).toHaveLength(0);
});
it('should not support icons', () => {
renderAllPriorities({
v2: true,
size: 'lg',
addonStart: iconProp,
});
expect(screen.queryAllByTestId('freeze-icon')).toHaveLength(0);
});
});
describe('medium', () => {
it('should support avatar', () => {
renderAllPriorities({
v2: true,
size: 'md',
addonStart: avatarProp,
});
expect(screen.getAllByTestId('freeze-icon')).toHaveLength(4);
});
it('should support icon', () => {
renderAllPriorities({
v2: true,
size: 'md',
addonStart: iconProp,
});
expect(screen.getAllByTestId('freeze-icon')).toHaveLength(4);
});
});
describe('small', () => {
it('should not support avatar', () => {
renderAllPriorities({
v2: true,
size: 'sm',
addonStart: avatarProp,
});
expect(screen.queryAllByTestId('freeze-icon')).toHaveLength(0);
});
it('should support icon', () => {
renderAllPriorities({
v2: true,
size: 'sm',
addonStart: iconProp,
});
expect(screen.getAllByTestId('freeze-icon')).toHaveLength(4);
});
});
});
describe('addonEnd', () => {
describe('large', () => {
it('should support icon', () => {
renderAllPriorities({
v2: true,
size: 'lg',
addonEnd: iconProp,
});
expect(screen.queryAllByTestId('freeze-icon')).toHaveLength(0);
});
});
describe('medium', () => {
it('should support icon', () => {
renderAllPriorities({
v2: true,
size: 'sm',
addonEnd: iconProp,
});
expect(screen.getAllByTestId('freeze-icon')).toHaveLength(4);
});
});
describe('small', () => {
it('should support icon', () => {
renderAllPriorities({
v2: true,
size: 'md',
addonEnd: iconProp,
});
expect(screen.getAllByTestId('freeze-icon')).toHaveLength(4);
});
});
});
});
describe('onClick', () => {
it('should call the handler when rendered as HTML button', async () => {
const onClick = jest.fn();
render(
,
);
await userEvent.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledTimes(1);
});
it('should call the handler when rendered as HTML anchor', async () => {
const onClick = jest.fn();
render(
,
);
await userEvent.click(screen.getByRole('link'));
expect(onClick).toHaveBeenCalledTimes(1);
});
});
});