Загрузка данных


import { fireEvent, render, screen } from '@testing-library/react';
import { ReactNode } from 'react';

import SplitDropdown from './index';

interface MockDropdownProps {
  position?: string;
  buttonClassName?: string;
  renderTrigger: (params: {
    isOpen: boolean;
    onToggle: () => void;
  }) => ReactNode;
  children?: ReactNode;
}

interface MockButtonProps {
  className?: string;
  pressed?: boolean;
  onClick?: () => void;
  label?: ReactNode;
}

interface MockTooltipProps {
  children?: ReactNode;
  tooltipClassName?: string;
  showMessageOnFocus?: boolean;
  label?: string;
}

jest.mock('../Dropdown', () => {
  const { useState } = jest.requireActual<typeof import('react')>('react');

  return {
    Dropdown: ({
      position,
      buttonClassName,
      renderTrigger,
      children,
    }: MockDropdownProps) => {
      const [isOpen, setIsOpen] = useState(false);

      return (
        <div
          data-testid="dropdown"
          data-position={position}
          data-button-class-name={buttonClassName}
        >
          {renderTrigger({
            isOpen,
            onToggle: () => setIsOpen((value) => !value),
          })}

          {isOpen && <div data-testid="dropdown-content">{children}</div>}
        </div>
      );
    },
  };
});

jest.mock('@src/components/Button', () => ({
  Button: ({
    className,
    pressed,
    onClick,
    label,
  }: MockButtonProps) => (
    <button
      type="button"
      className={className}
      data-pressed={String(Boolean(pressed))}
      onClick={onClick}
    >
      {label}
    </button>
  ),
}));

jest.mock('@src/components/Tooltip', () => ({
  Tooltip: ({
    children,
    tooltipClassName,
    showMessageOnFocus,
    label,
  }: MockTooltipProps) => (
    <div
      data-testid="tooltip"
      data-tooltip-class-name={tooltipClassName}
      data-show-message-on-focus={String(showMessageOnFocus)}
      data-label={label}
    >
      {children}
    </div>
  ),
}));

jest.mock('@src/components/Icon/SmallChevronLeft', () => ({
  __esModule: true,
  default: () => <span data-testid="default-menu-content">Chevron</span>,
}));

describe('SplitDropdown', () => {
  it('должен использовать значения по умолчанию в закрытом состоянии', () => {
    render(
      <SplitDropdown mainContent={<span>Основная кнопка</span>}>
        <div>Содержимое меню</div>
      </SplitDropdown>,
    );

    const dropdown = screen.getByTestId('dropdown');
    const buttons = screen.getAllByRole('button');
    const tooltips = screen.getAllByTestId('tooltip');

    expect(dropdown).toHaveAttribute('data-position', 'right');

    expect(buttons[0]).toHaveAttribute('data-pressed', 'false');
    expect(buttons[1]).toHaveAttribute('data-pressed', 'false');

    expect(tooltips[0]).toHaveAttribute(
      'data-show-message-on-focus',
      'true',
    );
    expect(tooltips[1]).toHaveAttribute(
      'data-show-message-on-focus',
      'true',
    );

    expect(screen.getByTestId('default-menu-content')).toBeInTheDocument();
    expect(screen.queryByTestId('dropdown-content')).not.toBeInTheDocument();
  });

  it('должен устанавливать pressed для основной кнопки через mainButtonPressed', () => {
    render(
      <SplitDropdown
        mainButtonPressed
        mainContent={<span>Основная кнопка</span>}
      >
        <div>Содержимое меню</div>
      </SplitDropdown>,
    );

    const buttons = screen.getAllByRole('button');

    expect(buttons[0]).toHaveAttribute('data-pressed', 'true');
    expect(buttons[1]).toHaveAttribute('data-pressed', 'false');
  });

  it('должен переводить обе кнопки в pressed состояние при открытии меню', () => {
    render(
      <SplitDropdown mainContent={<span>Основная кнопка</span>}>
        <div>Содержимое меню</div>
      </SplitDropdown>,
    );

    fireEvent.click(screen.getAllByRole('button')[1]);

    const buttons = screen.getAllByRole('button');
    const tooltips = screen.getAllByTestId('tooltip');

    expect(buttons[0]).toHaveAttribute('data-pressed', 'true');
    expect(buttons[1]).toHaveAttribute('data-pressed', 'true');

    expect(
      screen.getByText('Основная кнопка').closest('.dropdown'),
    ).toHaveClass('open');

    expect(tooltips[0]).toHaveAttribute(
      'data-show-message-on-focus',
      'false',
    );
    expect(tooltips[1]).toHaveAttribute(
      'data-show-message-on-focus',
      'false',
    );

    expect(screen.getByTestId('dropdown-content')).toHaveTextContent(
      'Содержимое меню',
    );
  });

  it('должен вызывать обработчик основной кнопки', () => {
    const onMainClick = jest.fn();

    render(
      <SplitDropdown
        mainContent={<span>Основная кнопка</span>}
        onMainClick={onMainClick}
      >
        <div>Содержимое меню</div>
      </SplitDropdown>,
    );

    fireEvent.click(screen.getAllByRole('button')[0]);

    expect(onMainClick).toHaveBeenCalledTimes(1);
  });

  it('должен передавать классы основной кнопке и тултипам', () => {
    render(
      <SplitDropdown
        mainContent={<span>Основная кнопка</span>}
        mainButtonClassName="main-button-class"
        tooltipClassName="tooltip-class"
      >
        <div>Содержимое меню</div>
      </SplitDropdown>,
    );

    const buttons = screen.getAllByRole('button');
    const tooltips = screen.getAllByTestId('tooltip');

    expect(buttons[0]).toHaveClass('main-button-class');
    expect(buttons[1]).toHaveClass('menu_button');

    expect(tooltips[0]).toHaveAttribute(
      'data-tooltip-class-name',
      'tooltip__main tooltip-class',
    );
    expect(tooltips[1]).toHaveAttribute(
      'data-tooltip-class-name',
      'tooltip-class',
    );
  });
});