learning_ai_invt_trdg/web/src/tabs/EntriesTab.dom.test.tsx

130 lines
5.0 KiB
TypeScript

// @vitest-environment jsdom
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen, waitFor, fireEvent, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { EntriesTab } from './EntriesTab';
const {
authState,
confirmMock,
fetchManualEntriesMock,
deleteManualEntryMock,
createManualEntryMock
} = vi.hoisted(() => ({
authState: {
user: { id: 'user-1', email: 'test@demo.test' } as any,
profile: { role: 'user' } as any
},
confirmMock: vi.fn(),
fetchManualEntriesMock: vi.fn(),
deleteManualEntryMock: vi.fn(),
createManualEntryMock: vi.fn()
}));
vi.mock('../components/AuthContext', () => ({
useAuth: () => authState
}));
vi.mock('../lib/manualEntriesApi', () => ({
fetchManualEntries: fetchManualEntriesMock,
deleteManualEntry: deleteManualEntryMock,
createManualEntry: createManualEntryMock
}));
vi.mock('../components/EntryForm', () => ({
EntryForm: ({ onSuccess, initialData }: any) => (
<div>
<span data-testid="initial-data">{initialData ? initialData.symbol : 'none'}</span>
<button onClick={onSuccess}>SubmitEntry</button>
</div>
)
}));
describe('EntriesTab master suite', () => {
const mockEntry = {
stock_instance_id: 'entry-1',
symbol: 'BTC/USDT',
active: true,
user_id: 'user-1',
buy_price: '50000',
sell_price: '55000',
quantity: '1',
status: 'active',
is_crypto: true,
is_real_trade: false,
label: 'Test Entry'
};
const mockBotState: any = {
orders: [],
symbols: {},
alerts: [],
positions: [],
history: [],
settings: { executionMode: 'Paper' }
};
beforeEach(() => {
vi.clearAllMocks();
authState.user = { id: 'user-1', email: 'test@demo.test' };
authState.profile = { role: 'user' };
vi.stubGlobal('confirm', confirmMock);
vi.stubGlobal('crypto', { randomUUID: () => 'uuid-123' });
fetchManualEntriesMock.mockResolvedValue([mockEntry]);
deleteManualEntryMock.mockResolvedValue(undefined);
createManualEntryMock.mockResolvedValue({});
});
it('handles entry drawer interactions', async () => {
const user = userEvent.setup();
render(<EntriesTab botState={mockBotState} />);
await waitFor(() => expect(screen.getByText('BTC/USDT')).toBeInTheDocument());
await user.click(screen.getByText(/Manual Entry Injection/i));
expect(screen.getByText(/New Opportunity Initialization/i)).toBeInTheDocument();
await user.click(screen.getByText('SubmitEntry'));
expect(screen.queryByText(/New Opportunity Initialization/i)).not.toBeInTheDocument();
});
it('derives diverse entry states (LOCKED, BLOCKED, SUBMITTED, CONFIRMED, ORPHAN)', async () => {
const user = userEvent.setup();
const entries = [
{ stock_instance_id: 's1', symbol: 'S1', active: true, status: 'active', is_real_trade: false },
{ stock_instance_id: 's2', symbol: 'S2', active: false, status: 'cooldown', is_real_trade: false }, // Use 'cooldown' instead of 'blocked' because 'blocked' contains 'lock'
{ stock_instance_id: 's3', symbol: 'S3', active: false, status: 'submitted', is_real_trade: false },
{ stock_instance_id: 's4', symbol: 'S4', active: false, status: 'confirmed', is_real_trade: false },
{ stock_instance_id: 's5', symbol: 'S5', active: false, status: 'orphan', is_real_trade: false },
];
fetchManualEntriesMock.mockResolvedValue(entries);
render(<EntriesTab botState={mockBotState} />);
await waitFor(() => expect(screen.getByText('S1')).toBeInTheDocument());
expect(screen.getByText('LOCKED')).toBeInTheDocument();
const suspendedTab = screen.getByRole('button', { name: /Suspended/i });
await user.click(suspendedTab);
await waitFor(() => expect(screen.getByText('S2')).toBeInTheDocument(), { timeout: 3000 });
expect(screen.getByText('BLOCKED')).toBeInTheDocument();
expect(screen.getByText('SUBMITTED')).toBeInTheDocument();
expect(screen.getByText('CONFIRMED')).toBeInTheDocument();
expect(screen.getByText('ORPHAN')).toBeInTheDocument();
});
it('covers clone and delete triggers', async () => {
render(<EntriesTab botState={mockBotState} />);
await waitFor(() => expect(screen.getByText('BTC/USDT')).toBeInTheDocument());
const card = screen.getByText('BTC/USDT').closest('.group');
const buttons = within(card as HTMLElement).getAllByRole('button');
await fireEvent.click(buttons[1]);
expect(createManualEntryMock).toHaveBeenCalled();
confirmMock.mockReturnValue(true);
await fireEvent.click(buttons[2]);
expect(deleteManualEntryMock).toHaveBeenCalledWith('entry-1');
});
});