import { describe, expect, it } from 'bun:test'; import { DEFAULT_GRAPH_TICKERS, buildGraphingHref, metricsForSurfaceAndCadence, normalizeGraphTickers, parseGraphingParams } from '@/lib/graphing/catalog'; describe('graphing catalog', () => { it('normalizes compare set tickers with dedupe and max five', () => { expect(normalizeGraphTickers(' msft, aapl, msft, nvda, amd, goog, meta ')).toEqual([ 'MSFT', 'AAPL', 'NVDA', 'AMD', 'GOOG' ]); }); it('falls back to defaults when params are missing or invalid', () => { const state = parseGraphingParams(new URLSearchParams('surface=invalid&metric=made_up&chart=nope')); expect(state.tickers).toEqual([...DEFAULT_GRAPH_TICKERS]); expect(state.surface).toBe('income_statement'); expect(state.metric).toBe('revenue'); expect(state.chart).toBe('line'); expect(state.scale).toBe('millions'); }); it('filters annual-only ratio metrics for non-annual views', () => { const quarterlyMetricKeys = metricsForSurfaceAndCadence('ratios', 'quarterly').map((metric) => metric.key); expect(quarterlyMetricKeys).not.toContain('3y_revenue_cagr'); expect(quarterlyMetricKeys).not.toContain('5y_eps_cagr'); expect(quarterlyMetricKeys).toContain('gross_margin'); }); it('includes other operating expense in the income statement metric catalog', () => { const metricKeys = metricsForSurfaceAndCadence('income_statement', 'annual').map((metric) => metric.key); expect(metricKeys).toContain('operating_expenses'); expect(metricKeys).toContain('selling_general_and_administrative'); expect(metricKeys).toContain('research_and_development'); expect(metricKeys).toContain('other_operating_expense'); }); it('replaces invalid metrics after surface and cadence normalization', () => { const state = parseGraphingParams(new URLSearchParams('surface=ratios&cadence=quarterly&metric=5y_revenue_cagr&tickers=msft,aapl')); expect(state.surface).toBe('ratios'); expect(state.cadence).toBe('quarterly'); expect(state.metric).toBe('gross_margin'); expect(state.tickers).toEqual(['MSFT', 'AAPL']); }); it('builds graphing hrefs with the primary ticker leading the compare set', () => { expect(buildGraphingHref('amd')).toContain('tickers=AMD%2CMSFT%2CAAPL%2CNVDA'); }); });