feat: add Ops and Watchlists tests (144 total frontend tests)
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import { renderRoute } from './render';
|
||||
|
||||
describe('Pipeline Health page', () => {
|
||||
it('renders page title', async () => {
|
||||
renderRoute('/ops/pipeline');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Pipeline Health' })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders queue depths section', async () => {
|
||||
renderRoute('/ops/pipeline');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Queue Depths')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders document stages section', async () => {
|
||||
renderRoute('/ops/pipeline');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Document Stages')).toBeInTheDocument();
|
||||
});
|
||||
// Mock has { status: 'extracted', doc_count: 5 }
|
||||
expect(screen.getByText('5')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders parsing quality section', async () => {
|
||||
renderRoute('/ops/pipeline');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Parsing Quality')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders extraction validation section', async () => {
|
||||
renderRoute('/ops/pipeline');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Extraction Validation')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders trend generation section', async () => {
|
||||
renderRoute('/ops/pipeline');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Trend Generation')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders pipeline toggle button', async () => {
|
||||
renderRoute('/ops/pipeline');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Pipeline ON')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders queue labels', async () => {
|
||||
renderRoute('/ops/pipeline');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Queue Depths')).toBeInTheDocument();
|
||||
});
|
||||
// Queue labels are rendered inside the Queue Depths card
|
||||
expect(screen.getByText('Aggregation')).toBeInTheDocument();
|
||||
expect(screen.getByText('Recommendation')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ingestion Monitor page', () => {
|
||||
it('renders page title', async () => {
|
||||
renderRoute('/ops/ingestion');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Ingestion Monitor' })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders summary stat cards', async () => {
|
||||
renderRoute('/ops/ingestion');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Total Runs')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('Items Fetched')).toBeInTheDocument();
|
||||
expect(screen.getByText('New Items')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders summary values from mock data', async () => {
|
||||
renderRoute('/ops/ingestion');
|
||||
await waitFor(() => {
|
||||
// mock: total_runs: 10, completed: 8, failed: 2, total_items_fetched: 50, total_items_new: 12
|
||||
expect(screen.getByText('10')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('8')).toBeInTheDocument();
|
||||
expect(screen.getByText('50')).toBeInTheDocument();
|
||||
expect(screen.getByText('12')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders throughput chart section', async () => {
|
||||
renderRoute('/ops/ingestion');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Throughput')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders bucket selector buttons', async () => {
|
||||
renderRoute('/ops/ingestion');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Ingestion Monitor')).toBeInTheDocument();
|
||||
});
|
||||
// Bucket selector has 15m, 1h, 6h, 1d — just verify the group exists
|
||||
expect(screen.getByText('15m')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model Performance page', () => {
|
||||
it('renders page title', async () => {
|
||||
renderRoute('/ops/model');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Model Performance' })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders key metric cards', async () => {
|
||||
renderRoute('/ops/model');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Total Extractions')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('Success Rate')).toBeInTheDocument();
|
||||
expect(screen.getByText('Avg Latency')).toBeInTheDocument();
|
||||
expect(screen.getByText('Retry Rate')).toBeInTheDocument();
|
||||
expect(screen.getByText('Avg Confidence')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders metric values from mock data', async () => {
|
||||
renderRoute('/ops/model');
|
||||
await waitFor(() => {
|
||||
// mock: total_extractions: 20, success_rate: 0.9, avg_duration_ms: 1500, retry_rate: 0.05, avg_confidence: 0.8
|
||||
expect(screen.getByText('20')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('90.0%')).toBeInTheDocument();
|
||||
expect(screen.getByText('1500ms')).toBeInTheDocument();
|
||||
expect(screen.getByText('5.0%')).toBeInTheDocument();
|
||||
expect(screen.getByText('80%')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders recent failures section', async () => {
|
||||
renderRoute('/ops/model');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Recent Failures (0)')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('No recent failures')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Source Coverage page', () => {
|
||||
it('renders page title', async () => {
|
||||
renderRoute('/ops/coverage');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Source Coverage' })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders coverage matrix section', async () => {
|
||||
renderRoute('/ops/coverage');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Company × Source Type Matrix')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
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('Watchlists page', () => {
|
||||
it('renders page title', async () => {
|
||||
renderRoute('/watchlists');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Watchlists' })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders New Watchlist button', async () => {
|
||||
renderRoute('/watchlists');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('New Watchlist')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows create form on button click', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderRoute('/watchlists');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('New Watchlist')).toBeInTheDocument();
|
||||
});
|
||||
await user.click(screen.getByText('New Watchlist'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByLabelText('Watchlist name')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByLabelText('Watchlist description')).toBeInTheDocument();
|
||||
expect(screen.getByText('Create')).toBeInTheDocument();
|
||||
expect(screen.getByText('Cancel')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('cancel closes the create form', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderRoute('/watchlists');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('New Watchlist')).toBeInTheDocument();
|
||||
});
|
||||
await user.click(screen.getByText('New Watchlist'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Cancel')).toBeInTheDocument();
|
||||
});
|
||||
await user.click(screen.getByText('Cancel'));
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByLabelText('Watchlist name')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user