import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render, screen } from '@testing-library/react';
import { type ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { BrokerEventsOverview } from './BrokerEventsOverview';
vi.mock('@/entities/broker-event', () => ({
useBrokerEvents: vi.fn(),
}));
import { useBrokerEvents } from '@/entities/broker-event';
vi.mock('@moex-vibe/design-system', () => ({
Heading: ({ children }: { children: ReactNode }) =>
{children}
,
Text: ({ children }: { children: ReactNode }) => {children},
}));
function createWrapper() {
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return function Wrapper({ children }: { children: ReactNode }) {
return (
{children}
);
};
}
const mockItems = [
{
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,
},
];
describe('BrokerEventsOverview', () => {
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('returns null on error', () => {
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: Promise.reject(new Error('fail')),
status: 'error',
fetchStatus: 'idle',
} as unknown as ReturnType);
const { container } = render(, {
wrapper: createWrapper(),
});
expect(container).toBeEmptyDOMElement();
});
it('returns null when items array is empty', () => {
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);
const { container } = render(, {
wrapper: createWrapper(),
});
expect(container).toBeEmptyDOMElement();
});
it('renders event items and link to full page', () => {
vi.mocked(useBrokerEvents).mockReturnValue({
data: {
summary: {
eventCount: 2,
totalEstimatedCashflow: 186.9,
nearestEventDate: '2026-06-25',
currency: 'RUB',
},
items: mockItems,
},
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: 2,
totalEstimatedCashflow: 186.9,
nearestEventDate: '2026-06-25',
currency: 'RUB',
},
items: mockItems,
}),
status: 'success',
fetchStatus: 'idle',
} as unknown as ReturnType);
render(, { wrapper: createWrapper() });
expect(screen.getByText('Ближайшие события')).toBeInTheDocument();
expect(screen.getByText('SBER')).toBeInTheDocument();
expect(screen.getByText('SU26238RMFS5')).toBeInTheDocument();
expect(screen.getByText('Все события')).toBeInTheDocument();
expect(screen.getByRole('link', { name: 'Все события' })).toHaveAttribute(
'href',
'/broker/acc-1/events',
);
});
it('renders at most 5 items', () => {
const manyItems = Array.from({ length: 7 }, (_, i) => ({
id: `ev-${i}`,
type: 'dividend' as const,
ticker: `TICKER${i}`,
name: null as string | null,
eventDate: '2026-06-25',
estimatedAmount: 100,
currency: 'RUB' as const,
}));
vi.mocked(useBrokerEvents).mockReturnValue({
data: {
summary: {
eventCount: 7,
totalEstimatedCashflow: 700,
nearestEventDate: '2026-06-25',
currency: 'RUB',
},
items: manyItems,
},
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: 7,
totalEstimatedCashflow: 700,
nearestEventDate: '2026-06-25',
currency: 'RUB',
},
items: manyItems,
}),
status: 'success',
fetchStatus: 'idle',
} as unknown as ReturnType);
render(, { wrapper: createWrapper() });
expect(screen.getAllByText(/TICKER/)).toHaveLength(5);
});
});