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


import { act, render } from '@testing-library/react';

import React from 'react';

import { CompareModal } from '../components/MoexChart/components/CompareModal';
import { SymbolSearchModal } from '../components/MoexChart/components/SymbolSearchModal';
import { useMoexChart } from '../components/MoexChart/hooks';
import MoexChartComponent from '../components/MoexChart/MoexChart';

import type { Contract } from '@modules/contracts';
import type { __CompareManager__ } from 'moex-chart';
import type { MutableRefObject } from 'react';

jest.mock('../components/MoexChart/hooks', () => ({
  useMoexChart: jest.fn(),
}));

jest.mock('../components/MoexChart/components/CompareModal', () => ({
  CompareModal: jest.fn(() => null),
}));

jest.mock('../components/MoexChart/components/SymbolSearchModal', () => ({
  SymbolSearchModal: jest.fn(() => null),
}));

interface CompareModalMockProps {
  widgetId: number;
  isOpen: boolean;
  setOpen: (isOpen: boolean) => void;
  onClose: () => void;
  compareManager: MutableRefObject<__CompareManager__ | null>;
}

interface SymbolSearchModalMockProps {
  widgetId: number;
  isOpen: boolean;
  setOpen: (isOpen: boolean) => void;
  onSymbolChange: (instrument: Contract) => void;
}

describe('MoexChart', () => {
  const mockUseMoexChart = useMoexChart as jest.Mock;
  const mockCompareModal = CompareModal as jest.Mock;
  const mockSymbolSearchModal = SymbolSearchModal as jest.Mock;

  const mockSetIsCompareOpen = jest.fn();
  const mockSetIsSymbolSearchOpen = jest.fn();
  const mockAddInstrumentFromModal = jest.fn();

  let containerRef: MutableRefObject<HTMLDivElement | null>;
  let compareManagerRef: MutableRefObject<__CompareManager__ | null>;

  const renderComponent = () =>
    render(
      <MoexChartComponent
        symbol="MXSE:TQBR:SBER"
        instrumentName="Сбербанк"
        instrumentTicker="SBER"
        widgetId={42}
        addInstrumentFromModal={mockAddInstrumentFromModal}
      />,
    );

  beforeEach(() => {
    jest.clearAllMocks();

    containerRef = {
      current: null,
    };

    compareManagerRef = {
      current: null,
    };

    mockUseMoexChart.mockReturnValue({
      containerRef,
      isCompareOpen: false,
      isSymbolSearchOpen: false,
      compareManagerRef,
      setIsCompareOpen: mockSetIsCompareOpen,
      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
      saveSnapshot: jest.fn(),
      applySnapshot: jest.fn(),
      hasSavedSnapshot: false,
    });
  });

  it('should initialize chart hook with symbol, name and ticker', () => {
    // Arrange & Act
    renderComponent();

    // Assert
    expect(mockUseMoexChart).toHaveBeenCalledTimes(1);
    expect(mockUseMoexChart).toHaveBeenCalledWith({
      symbol: 'MXSE:TQBR:SBER',
      instrumentName: 'Сбербанк',
      instrumentTicker: 'SBER',
      indicativeData: undefined,
    });
  });

  it('should attach chart container ref', () => {
    // Arrange & Act
    renderComponent();

    // Assert
    expect(containerRef.current).toBeInstanceOf(HTMLDivElement);
  });

  it('should not render modals when they are closed', () => {
    // Arrange & Act
    renderComponent();

    // Assert
    expect(mockCompareModal).not.toHaveBeenCalled();
    expect(mockSymbolSearchModal).not.toHaveBeenCalled();
  });

  it('should render compare modal with chart manager', () => {
    // Arrange
    mockUseMoexChart.mockReturnValue({
      containerRef,
      isCompareOpen: true,
      isSymbolSearchOpen: false,
      compareManagerRef,
      setIsCompareOpen: mockSetIsCompareOpen,
      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
      saveSnapshot: jest.fn(),
      applySnapshot: jest.fn(),
      hasSavedSnapshot: false,
    });

    // Act
    renderComponent();

    const compareModalProps = mockCompareModal.mock.calls[0]?.[0] as CompareModalMockProps;

    // Assert
    expect(compareModalProps.widgetId).toBe(42);
    expect(compareModalProps.isOpen).toBe(true);
    expect(compareModalProps.setOpen).toBe(mockSetIsCompareOpen);
    expect(compareModalProps.compareManager).toBe(compareManagerRef);
  });

  it('should close compare modal through onClose callback', () => {
    // Arrange
    mockUseMoexChart.mockReturnValue({
      containerRef,
      isCompareOpen: true,
      isSymbolSearchOpen: false,
      compareManagerRef,
      setIsCompareOpen: mockSetIsCompareOpen,
      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
      saveSnapshot: jest.fn(),
      applySnapshot: jest.fn(),
      hasSavedSnapshot: false,
    });

    renderComponent();

    const compareModalProps = mockCompareModal.mock.calls[0]?.[0] as CompareModalMockProps;

    // Act
    act(() => {
      compareModalProps.onClose();
    });

    // Assert
    expect(mockSetIsCompareOpen).toHaveBeenCalledWith(false);
  });

  it('should render symbol search modal', () => {
    // Arrange
    mockUseMoexChart.mockReturnValue({
      containerRef,
      isCompareOpen: false,
      isSymbolSearchOpen: true,
      compareManagerRef,
      setIsCompareOpen: mockSetIsCompareOpen,
      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
      saveSnapshot: jest.fn(),
      applySnapshot: jest.fn(),
      hasSavedSnapshot: false,
    });

    // Act
    renderComponent();

    const symbolSearchModalProps = mockSymbolSearchModal.mock.calls[0]?.[0] as SymbolSearchModalMockProps;

    // Assert
    expect(symbolSearchModalProps.widgetId).toBe(42);
    expect(symbolSearchModalProps.isOpen).toBe(true);
    expect(symbolSearchModalProps.setOpen).toBe(mockSetIsSymbolSearchOpen);
  });

  it('should pass selected instrument from symbol search modal', () => {
    // Arrange
    mockUseMoexChart.mockReturnValue({
      containerRef,
      isCompareOpen: false,
      isSymbolSearchOpen: true,
      compareManagerRef,
      setIsCompareOpen: mockSetIsCompareOpen,
      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
      saveSnapshot: jest.fn(),
      applySnapshot: jest.fn(),
      hasSavedSnapshot: false,
    });

    renderComponent();

    const symbolSearchModalProps = mockSymbolSearchModal.mock.calls[0]?.[0] as SymbolSearchModalMockProps;

    const instrument = {
      issKey: 'MXSE:TQBR:GAZP',
      displayName: 'Газпром',
      symbol: 'GAZP',
    } as Contract;

    // Act
    act(() => {
      symbolSearchModalProps.onSymbolChange(instrument);
    });

    // Assert
    expect(mockAddInstrumentFromModal).toHaveBeenCalledTimes(1);
    expect(mockAddInstrumentFromModal).toHaveBeenCalledWith([instrument]);
  });
});