import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render, screen } from '@testing-library/react';
import React, { type ReactNode } from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { BrokerEventsPage } from './BrokerEventsPage';
vi.mock('@/entities/broker-event', () => ({
useBrokerEvents: vi.fn(),
}));
vi.mock('@/widgets/broker-account-layout', () => ({
useBrokerAccountContext: () => ({ accountId: 'acc-1', portfolio: null }),
}));
const mockSetSearchParams = vi.fn();
vi.mock('react-router-dom', () => ({
useSearchParams: () => [new URLSearchParams(), mockSetSearchParams],
}));
vi.mock('@moex-vibe/design-system', () => ({
Heading: ({ children }: { children: ReactNode }) =>
{children}
,
Text: ({ children }: { children: ReactNode }) => {children},
TextField: ({ label, value, onChange, ...props }: any) => (
{})}
type={props.type || 'text'}
/>
),
}));
import { useBrokerEvents } from '@/entities/broker-event';
function createWrapper() {
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return function Wrapper({ children }: { children: ReactNode }) {
return {children};
};
}
const mockData = {
summary: {
eventCount: 3,
totalEstimatedCashflow: 450,
nearestEventDate: '2026-06-25',
currency: 'RUB',
},
items: [
{
id: 'ev-1',
type: 'dividend',
ticker: 'SBER',
name: 'Сбер Банк',
eventDate: '2026-06-25',
estimatedAmount: 150,
currency: 'RUB' as const,
},
{
id: 'ev-2',
type: 'coupon',
ticker: 'SU26238RMFS5',
name: 'ОФЗ 26238',
eventDate: '2026-06-27',
estimatedAmount: 36.9,
currency: 'RUB' as const,
},
{
id: 'ev-3',
type: 'maturity',
ticker: 'VTBR',
name: 'ВТБ',
eventDate: '2026-06-30',
estimatedAmount: 1000,
currency: 'RUB' as const,
},
],
};
describe('BrokerEventsPage', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('renders loading state', () => {
vi.mocked(useBrokerEvents).mockReturnValue({
data: undefined,
isLoading: true,
isError: false,
error: null,
isSuccess: false,
isPending: true,
dataUpdatedAt: 0,
errorUpdatedAt: 0,
failureCount: 0,
failureReason: null,
errorUpdateCount: 0,
isFetched: false,
isFetchedAfterMount: false,
isFetching: true,
isInitialLoading: true,
isPaused: false,
isLoadingError: false,
isRefetchError: false,
isPlaceholderData: false,
isStale: false,
refetch: vi.fn(),
promise: new Promise(() => {}),
status: 'pending',
fetchStatus: 'fetching',
} as unknown as ReturnType);
render(, { wrapper: createWrapper() });
expect(screen.getByText('Загрузка событий…')).toBeInTheDocument();
});
it('renders error state', () => {
vi.mocked(useBrokerEvents).mockReturnValue({
data: undefined,
isLoading: false,
isError: true,
error: new Error('fail'),
isSuccess: false,
isPending: false,
dataUpdatedAt: 0,
errorUpdatedAt: 0,
failureCount: 1,
failureReason: null,
errorUpdateCount: 1,
isFetched: true,
isFetchedAfterMount: true,
isFetching: false,
isInitialLoading: false,
isPaused: false,
isLoadingError: true,
isRefetchError: false,
isPlaceholderData: false,
isStale: false,
refetch: vi.fn(),
promise: new Promise(() => {}),
status: 'error',
fetchStatus: 'idle',
} as unknown as ReturnType);
render(, { wrapper: createWrapper() });
expect(screen.getByText('Не удалось загрузить календарь событий')).toBeInTheDocument();
});
it('renders empty state', () => {
vi.mocked(useBrokerEvents).mockReturnValue({
data: {
summary: {
eventCount: 0,
totalEstimatedCashflow: 0,
nearestEventDate: null,
currency: 'RUB',
},
items: [],
},
isLoading: false,
isError: false,
error: null,
isSuccess: true,
isPending: false,
dataUpdatedAt: Date.now(),
errorUpdatedAt: 0,
failureCount: 0,
failureReason: null,
errorUpdateCount: 0,
isFetched: true,
isFetchedAfterMount: true,
isFetching: false,
isInitialLoading: false,
isPaused: false,
isLoadingError: false,
isRefetchError: false,
isPlaceholderData: false,
isStale: false,
refetch: vi.fn(),
promise: Promise.resolve({
summary: {
eventCount: 0,
totalEstimatedCashflow: 0,
nearestEventDate: null,
currency: 'RUB',
},
items: [],
}),
status: 'success',
fetchStatus: 'idle',
} as unknown as ReturnType);
render(, { wrapper: createWrapper() });
expect(screen.getByText('В выбранном диапазоне событий нет')).toBeInTheDocument();
});
it('renders date range inputs', () => {
vi.mocked(useBrokerEvents).mockReturnValue({
data: mockData,
isLoading: false,
isError: false,
error: null,
isSuccess: true,
isPending: false,
dataUpdatedAt: Date.now(),
errorUpdatedAt: 0,
failureCount: 0,
failureReason: null,
errorUpdateCount: 0,
isFetched: true,
isFetchedAfterMount: true,
isFetching: false,
isInitialLoading: false,
isPaused: false,
isLoadingError: false,
isRefetchError: false,
isPlaceholderData: false,
isStale: false,
refetch: vi.fn(),
promise: Promise.resolve(mockData),
status: 'success',
fetchStatus: 'idle',
} as unknown as ReturnType);
render(, { wrapper: createWrapper() });
expect(screen.getByLabelText('С')).toBeInTheDocument();
expect(screen.getByLabelText('По')).toBeInTheDocument();
});
it('renders events heading, summary and table', () => {
vi.mocked(useBrokerEvents).mockReturnValue({
data: mockData,
isLoading: false,
isError: false,
error: null,
isSuccess: true,
isPending: false,
dataUpdatedAt: Date.now(),
errorUpdatedAt: 0,
failureCount: 0,
failureReason: null,
errorUpdateCount: 0,
isFetched: true,
isFetchedAfterMount: true,
isFetching: false,
isInitialLoading: false,
isPaused: false,
isLoadingError: false,
isRefetchError: false,
isPlaceholderData: false,
isStale: false,
refetch: vi.fn(),
promise: Promise.resolve(mockData),
status: 'success',
fetchStatus: 'idle',
} as unknown as ReturnType);
render(, { wrapper: createWrapper() });
expect(screen.getByText('События')).toBeInTheDocument();
expect(screen.getByText('Событий')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
expect(screen.getByText('Ближайшее')).toBeInTheDocument();
expect(screen.getByText('Денежный поток')).toBeInTheDocument();
expect(screen.getByText('Дивиденд')).toBeInTheDocument();
expect(screen.getByText('Купон')).toBeInTheDocument();
expect(screen.getByText('Погашение')).toBeInTheDocument();
expect(screen.getByText('SBER')).toBeInTheDocument();
expect(screen.getByText('SU26238RMFS5')).toBeInTheDocument();
expect(screen.getByText('VTBR')).toBeInTheDocument();
});
});