Загрузка данных
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]);
});
});