feat: add detail page tests for Documents, Recommendations, Trends, Events, Companies (176 total)

This commit is contained in:
Celes Renata
2026-04-21 07:39:19 +00:00
parent 58a63408c7
commit a023050223
+268
View File
@@ -0,0 +1,268 @@
import { describe, it, expect } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import { renderRoute } from './render';
describe('Document Detail page', () => {
it('renders document title', async () => {
renderRoute('/documents/d1');
await waitFor(() => {
expect(screen.getByText('Apple Q4 Earnings Beat')).toBeInTheDocument();
});
});
it('shows document type and source type', async () => {
renderRoute('/documents/d1');
await waitFor(() => {
expect(screen.getByText('news')).toBeInTheDocument();
});
expect(screen.getByText('news_api')).toBeInTheDocument();
});
it('shows publisher', async () => {
renderRoute('/documents/d1');
await waitFor(() => {
expect(screen.getByText('Reuters')).toBeInTheDocument();
});
});
it('renders metadata section', async () => {
renderRoute('/documents/d1');
await waitFor(() => {
expect(screen.getByText('Metadata')).toBeInTheDocument();
});
expect(screen.getByText('Language')).toBeInTheDocument();
expect(screen.getByText('en')).toBeInTheDocument();
expect(screen.getByText('Content Hash')).toBeInTheDocument();
});
it('renders parse quality score', async () => {
renderRoute('/documents/d1');
await waitFor(() => {
expect(screen.getByText('Parse Quality')).toBeInTheDocument();
});
expect(screen.getByText('0.92')).toBeInTheDocument();
});
it('shows no intelligence message when null', async () => {
renderRoute('/documents/d1');
await waitFor(() => {
expect(screen.getByText('No intelligence extraction available')).toBeInTheDocument();
});
});
it('renders storage references section', async () => {
renderRoute('/documents/d1');
await waitFor(() => {
expect(screen.getByText('Storage References')).toBeInTheDocument();
});
});
});
describe('Recommendation Detail page', () => {
it('renders ticker as heading', async () => {
renderRoute('/recommendations/r1');
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'AAPL' })).toBeInTheDocument();
});
});
it('shows action and mode badges', async () => {
renderRoute('/recommendations/r1');
await waitFor(() => {
expect(screen.getByText('buy')).toBeInTheDocument();
});
expect(screen.getByText('paper')).toBeInTheDocument();
});
it('shows time horizon', async () => {
renderRoute('/recommendations/r1');
await waitFor(() => {
expect(screen.getByText('Horizon')).toBeInTheDocument();
});
expect(screen.getByText('7d')).toBeInTheDocument();
});
it('shows risk classification', async () => {
renderRoute('/recommendations/r1');
await waitFor(() => {
expect(screen.getByText('Risk')).toBeInTheDocument();
});
expect(screen.getByText('moderate')).toBeInTheDocument();
});
it('shows portfolio and max loss percentages', async () => {
renderRoute('/recommendations/r1');
await waitFor(() => {
expect(screen.getByText('Portfolio %')).toBeInTheDocument();
});
expect(screen.getByText('5.0%')).toBeInTheDocument();
expect(screen.getByText('2.00%')).toBeInTheDocument();
});
it('shows thesis', async () => {
renderRoute('/recommendations/r1');
await waitFor(() => {
expect(screen.getByText('Thesis')).toBeInTheDocument();
});
expect(screen.getByText('Strong earnings momentum')).toBeInTheDocument();
});
it('shows evidence section with zero count', async () => {
renderRoute('/recommendations/r1');
await waitFor(() => {
expect(screen.getByText('Evidence (0)')).toBeInTheDocument();
});
expect(screen.getByText('No evidence linked')).toBeInTheDocument();
});
});
describe('Trend Detail page', () => {
it('renders entity ID as heading', async () => {
renderRoute('/trends/t1');
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'AAPL' })).toBeInTheDocument();
});
});
it('shows trend direction', async () => {
renderRoute('/trends/t1');
await waitFor(() => {
expect(screen.getByText('bullish')).toBeInTheDocument();
});
});
it('shows window badge', async () => {
renderRoute('/trends/t1');
await waitFor(() => {
expect(screen.getByText('AAPL')).toBeInTheDocument();
});
expect(screen.getAllByText('7d').length).toBeGreaterThanOrEqual(1);
});
it('shows contradiction score', async () => {
renderRoute('/trends/t1');
await waitFor(() => {
expect(screen.getByText('Contradiction')).toBeInTheDocument();
});
expect(screen.getByText('10%')).toBeInTheDocument();
});
it('shows dominant catalysts', async () => {
renderRoute('/trends/t1');
await waitFor(() => {
expect(screen.getByText('Dominant Catalysts')).toBeInTheDocument();
});
expect(screen.getByText('earnings')).toBeInTheDocument();
});
it('shows contributing evidence section', async () => {
renderRoute('/trends/t1');
await waitFor(() => {
expect(screen.getByText('Contributing Evidence (0)')).toBeInTheDocument();
});
expect(screen.getByText('No evidence records')).toBeInTheDocument();
});
it('shows trend projection panel', async () => {
renderRoute('/trends/t1');
await waitFor(() => {
expect(screen.getByText('Trend Projection')).toBeInTheDocument();
});
// Mock projection: projected_direction: 'bearish', diverges_from_current: true
expect(screen.getByText('DIVERGENCE')).toBeInTheDocument();
expect(screen.getByText('bearish')).toBeInTheDocument();
});
it('shows macro contribution percentage', async () => {
renderRoute('/trends/t1');
await waitFor(() => {
expect(screen.getByText('Macro Contribution')).toBeInTheDocument();
});
// macro_contribution_pct: 0.3 → 30%
expect(screen.getByText('30%')).toBeInTheDocument();
});
});
describe('Global Event Detail page', () => {
it('renders page heading', async () => {
renderRoute('/macro/events/me1');
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'Global Event' })).toBeInTheDocument();
});
});
it('shows severity badge', async () => {
renderRoute('/macro/events/me1');
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'Global Event' })).toBeInTheDocument();
});
// severity: 'high'
expect(screen.getByText('high')).toBeInTheDocument();
});
it('shows event summary', async () => {
renderRoute('/macro/events/me1');
await waitFor(() => {
expect(screen.getByText('Summary')).toBeInTheDocument();
});
expect(screen.getByText('US tariffs on Chinese semiconductors')).toBeInTheDocument();
});
it('shows key facts', async () => {
renderRoute('/macro/events/me1');
await waitFor(() => {
expect(screen.getByText('Key Facts')).toBeInTheDocument();
});
expect(screen.getByText('25% tariff')).toBeInTheDocument();
expect(screen.getByText('Effective in 30 days')).toBeInTheDocument();
});
it('shows affected regions', async () => {
renderRoute('/macro/events/me1');
await waitFor(() => {
expect(screen.getByText('Regions')).toBeInTheDocument();
});
expect(screen.getByText('US')).toBeInTheDocument();
expect(screen.getByText('CN')).toBeInTheDocument();
});
it('shows affected companies table', async () => {
renderRoute('/macro/events/me1');
await waitFor(() => {
expect(screen.getByText(/Affected Companies/)).toBeInTheDocument();
});
// Mock has 1 impact: AAPL with negative direction
expect(screen.getByText('AAPL')).toBeInTheDocument();
expect(screen.getByText('negative')).toBeInTheDocument();
});
it('shows estimated duration', async () => {
renderRoute('/macro/events/me1');
await waitFor(() => {
expect(screen.getByText('medium term')).toBeInTheDocument();
});
});
});
describe('Company Detail page', () => {
it('renders company ticker as heading', async () => {
renderRoute('/companies/1');
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'AAPL' })).toBeInTheDocument();
});
});
it('shows company name', async () => {
renderRoute('/companies/1');
await waitFor(() => {
expect(screen.getByText('Apple Inc.')).toBeInTheDocument();
});
});
it('shows sector and exchange', async () => {
renderRoute('/companies/1');
await waitFor(() => {
expect(screen.getByText('NASDAQ')).toBeInTheDocument();
});
});
});