274 lines
7.9 KiB
TypeScript
274 lines
7.9 KiB
TypeScript
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 }) => <h2>{children}</h2>,
|
||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||
TextField: ({ label, value, onChange, ...props }: any) => (
|
||
<input
|
||
aria-label={label || ''}
|
||
value={value || ''}
|
||
onChange={onChange || (() => {})}
|
||
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 <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
||
};
|
||
}
|
||
|
||
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<never>(() => {}),
|
||
status: 'pending',
|
||
fetchStatus: 'fetching',
|
||
} as unknown as ReturnType<typeof useBrokerEvents>);
|
||
|
||
render(<BrokerEventsPage />, { 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<never>(() => {}),
|
||
status: 'error',
|
||
fetchStatus: 'idle',
|
||
} as unknown as ReturnType<typeof useBrokerEvents>);
|
||
|
||
render(<BrokerEventsPage />, { 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<typeof useBrokerEvents>);
|
||
|
||
render(<BrokerEventsPage />, { 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<typeof useBrokerEvents>);
|
||
|
||
render(<BrokerEventsPage />, { 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<typeof useBrokerEvents>);
|
||
|
||
render(<BrokerEventsPage />, { 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();
|
||
});
|
||
});
|