feat: add 25 tests for Trading Controls and Global Events pages (100 total)

This commit is contained in:
Celes Renata
2026-04-21 07:10:30 +00:00
parent 680e7ab1b8
commit 34d353bf3f
2 changed files with 332 additions and 0 deletions
+135
View File
@@ -0,0 +1,135 @@
import { describe, it, expect } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { HttpResponse, http } from 'msw';
import { renderRoute } from './render';
import { server } from './mocks/server';
describe('Global Events page', () => {
// -------------------------------------------------------------------------
// 1. Renders event list with summary
// -------------------------------------------------------------------------
it('renders event list with summary', async () => {
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByText(/US tariffs on Chinese semiconductors/)).toBeInTheDocument();
});
});
// -------------------------------------------------------------------------
// 2. Shows severity badge
// -------------------------------------------------------------------------
it('shows severity badge', async () => {
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByText(/US tariffs/)).toBeInTheDocument();
});
const row = screen.getByText(/US tariffs/).closest('tr')!;
expect(row).toHaveTextContent('high');
});
// -------------------------------------------------------------------------
// 3. Shows event type tags
// -------------------------------------------------------------------------
it('shows event type tags', async () => {
renderRoute('/macro/events');
await waitFor(() => {
// event_types: ['trade_barrier', 'cost_increase'] — underscores replaced with spaces
expect(screen.getByText('trade barrier')).toBeInTheDocument();
});
expect(screen.getByText('cost increase')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 4. Shows affected regions
// -------------------------------------------------------------------------
it('shows affected regions', async () => {
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByText('US')).toBeInTheDocument();
});
expect(screen.getByText('CN')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 5. Shows affected sectors
// -------------------------------------------------------------------------
it('shows affected sectors', async () => {
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByText('Technology')).toBeInTheDocument();
});
});
// -------------------------------------------------------------------------
// 6. Severity filter buttons render
// -------------------------------------------------------------------------
it('renders severity filter buttons', async () => {
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByRole('group', { name: 'Severity filter' })).toBeInTheDocument();
});
const group = screen.getByRole('group', { name: 'Severity filter' });
expect(group).toHaveTextContent('All');
expect(group).toHaveTextContent('low');
expect(group).toHaveTextContent('moderate');
expect(group).toHaveTextContent('high');
expect(group).toHaveTextContent('critical');
});
// -------------------------------------------------------------------------
// 7. Empty state
// -------------------------------------------------------------------------
it('shows empty state when no events', async () => {
server.use(
http.get('/api/macro/events', () => HttpResponse.json([])),
);
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByText('No data')).toBeInTheDocument();
});
});
// -------------------------------------------------------------------------
// 8. Page title renders
// -------------------------------------------------------------------------
it('renders page title', async () => {
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'Global Events' })).toBeInTheDocument();
});
});
// -------------------------------------------------------------------------
// 9. Severity filter is clickable
// -------------------------------------------------------------------------
it('severity filter buttons are clickable', async () => {
const user = userEvent.setup();
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByRole('group', { name: 'Severity filter' })).toBeInTheDocument();
});
// Click "critical" filter — should not crash
await user.click(screen.getByRole('button', { name: 'critical' }));
// Page should still be rendered
expect(screen.getByRole('heading', { name: 'Global Events' })).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 10. Multiple events render
// -------------------------------------------------------------------------
it('renders multiple events', async () => {
server.use(
http.get('/api/macro/events', () => HttpResponse.json([
{ id: 'me1', event_types: ['trade_barrier'], severity: 'high', affected_regions: ['US'], affected_sectors: ['Technology'], affected_commodities: [], summary: 'Tariff event', key_facts: [], estimated_duration: 'short_term', confidence: 0.85, source_document_id: 'd1', created_at: '2026-05-15T14:00:00Z' },
{ id: 'me2', event_types: ['monetary_policy'], severity: 'moderate', affected_regions: ['EU'], affected_sectors: ['Financial Services'], affected_commodities: [], summary: 'ECB rate decision', key_facts: [], estimated_duration: 'medium_term', confidence: 0.70, source_document_id: 'd2', created_at: '2026-05-16T10:00:00Z' },
])),
);
renderRoute('/macro/events');
await waitFor(() => {
expect(screen.getByText('Tariff event')).toBeInTheDocument();
});
expect(screen.getByText('ECB rate decision')).toBeInTheDocument();
expect(screen.getByText('EU')).toBeInTheDocument();
});
});
+197
View File
@@ -0,0 +1,197 @@
import { describe, it, expect } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderRoute } from './render';
describe('Trading Controls page', () => {
// -------------------------------------------------------------------------
// 1. Page title renders
// -------------------------------------------------------------------------
it('renders page title', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'Trading Controls' })).toBeInTheDocument();
});
});
// -------------------------------------------------------------------------
// 2. Trading mode buttons render with paper active
// -------------------------------------------------------------------------
it('renders trading mode buttons with paper active', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByRole('button', { name: 'paper', pressed: true })).toBeInTheDocument();
});
expect(screen.getByRole('button', { name: 'live', pressed: false })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'disabled', pressed: false })).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 3. Live mode shows confirmation dialog
// -------------------------------------------------------------------------
it('shows confirmation dialog when clicking live mode', async () => {
const user = userEvent.setup();
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByRole('button', { name: 'live' })).toBeInTheDocument();
});
await user.click(screen.getByRole('button', { name: 'live' }));
await waitFor(() => {
expect(screen.getByText(/Are you sure you want to switch to/)).toBeInTheDocument();
});
expect(screen.getByText('Confirm')).toBeInTheDocument();
expect(screen.getByText('Cancel')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 4. Cancel dismisses live mode confirmation
// -------------------------------------------------------------------------
it('dismisses live mode confirmation on cancel', async () => {
const user = userEvent.setup();
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByRole('button', { name: 'live' })).toBeInTheDocument();
});
await user.click(screen.getByRole('button', { name: 'live' }));
await waitFor(() => {
expect(screen.getByText('Cancel')).toBeInTheDocument();
});
await user.click(screen.getByText('Cancel'));
await waitFor(() => {
expect(screen.queryByText(/Are you sure you want to switch to/)).not.toBeInTheDocument();
});
});
// -------------------------------------------------------------------------
// 5. Reset card renders with button
// -------------------------------------------------------------------------
it('renders paper trading reset card', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByText('Paper Trading Account')).toBeInTheDocument();
});
expect(screen.getByText('Reset Everything')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 6. Reset shows confirmation dialog
// -------------------------------------------------------------------------
it('shows reset confirmation dialog', async () => {
const user = userEvent.setup();
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByText('Reset Everything')).toBeInTheDocument();
});
await user.click(screen.getByText('Reset Everything'));
await waitFor(() => {
expect(screen.getByText(/permanently delete/)).toBeInTheDocument();
});
expect(screen.getByText('Yes, Reset Everything')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 7. Macro signal layer toggle renders
// -------------------------------------------------------------------------
it('renders macro signal layer toggle', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByText('Macro Signal Layer')).toBeInTheDocument();
});
expect(screen.getByLabelText('Toggle macro signal layer')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 8. Competitive signal layer toggle renders
// -------------------------------------------------------------------------
it('renders competitive signal layer toggle', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByText('Competitive Signal Layer')).toBeInTheDocument();
});
expect(screen.getByLabelText('Toggle competitive signal layer')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 9. Macro toggle shows confirmation
// -------------------------------------------------------------------------
it('shows confirmation when toggling macro layer', async () => {
const user = userEvent.setup();
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByLabelText('Toggle macro signal layer')).toBeInTheDocument();
});
await user.click(screen.getByLabelText('Toggle macro signal layer'));
await waitFor(() => {
expect(screen.getByText(/Are you sure you want to/)).toBeInTheDocument();
});
});
// -------------------------------------------------------------------------
// 10. Pending approvals section renders
// -------------------------------------------------------------------------
it('renders pending approvals section with zero count', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByText('Pending Approvals (0)')).toBeInTheDocument();
});
expect(screen.getByText('No pending approvals')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 11. Active lockouts section renders
// -------------------------------------------------------------------------
it('renders active lockouts section with zero count', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByText('Active Lockouts (0)')).toBeInTheDocument();
});
expect(screen.getByText('No active lockouts')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 12. Lockout form renders with fields
// -------------------------------------------------------------------------
it('renders lockout creation form', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByLabelText('Ticker')).toBeInTheDocument();
});
expect(screen.getByLabelText('Reason')).toBeInTheDocument();
expect(screen.getByLabelText('Minutes')).toBeInTheDocument();
expect(screen.getByText('Add Lockout')).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 13. Risk tier buttons render
// -------------------------------------------------------------------------
it('renders risk tier buttons', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByText('Risk Tier')).toBeInTheDocument();
});
expect(screen.getByRole('button', { name: 'conservative' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'moderate' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'aggressive' })).toBeInTheDocument();
});
// -------------------------------------------------------------------------
// 14. Override Trade button links to engine
// -------------------------------------------------------------------------
it('renders Override Trade button', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByTestId('override-trade-button')).toBeInTheDocument();
});
});
// -------------------------------------------------------------------------
// 15. Paper order approval toggle renders
// -------------------------------------------------------------------------
it('renders paper order approval toggle', async () => {
renderRoute('/trading');
await waitFor(() => {
expect(screen.getByText('Paper Order Approval')).toBeInTheDocument();
});
expect(screen.getByLabelText('Toggle paper order approval requirement')).toBeInTheDocument();
});
});