import { describe, expect, it } from 'vitest'; import { extract, renderResult, shrink } from '../src/format.js'; import { rateFromHeaders } from '../src/client.js'; import { bars } from './helpers.js'; const rate = rateFromHeaders(new Headers({ 'x-ratelimit-remaining-requests': '7', 'x-ratelimit-limit-requests': '30' })); describe('extract', () => { it('understands the v1 envelope', () => { const e = extract({ count: 2, data: [{ a: 1 }, { a: 2 }] }); expect(e.rows).toHaveLength(2); expect(e.meta.count).toBe(2); }); it('understands the v2 envelope and keeps meta', () => { const e = extract({ data: [{ a: 1 }], meta: { count: 1, next_cursor: 'abc', roll_dates: ['2025-03-14'] } }); expect(e.rows).toHaveLength(1); expect(e.meta.next_cursor).toBe('abc'); }); it('keeps non-tabular payloads in rest', () => { const e = extract({ asset: 'stock', count: 3, tickers: ['A', 'B', 'C'] }); expect(e.rows).toBeNull(); expect(e.rest.tickers).toEqual(['A', 'B', 'C']); }); }); describe('renderResult', () => { it('renders small tables in full as columns/rows', () => { const text = renderResult({ status: 200, url: 'u', body: { count: 3, data: bars(3) }, rate, ms: 1 }, { title: 'T' }); expect(text.startsWith('T\n')).toBe(true); const json = JSON.parse(text.split('\n')[1]); expect(json.row_count).toBe(3); expect(json.columns).toEqual(['ticker', 'datetime', 'open', 'high', 'low', 'close', 'volume']); expect(json.rows).toHaveLength(3); expect(json.truncated).toBeUndefined(); expect(text).toContain('Rate limit: requests 7/30 left'); }); it('summarises large tables with head/tail, numeric ranges and a hint', () => { const text = renderResult({ status: 200, url: 'u', body: { data: bars(600), meta: { count: 600, next_cursor: 'n' } }, rate, ms: 1 }); const json = JSON.parse(text.split('\n')[0]); expect(json.truncated).toBe(true); expect(json.row_count).toBe(600); expect(json.first_rows).toHaveLength(15); expect(json.last_rows).toHaveLength(15); expect(json.numeric_summary.close.min).toBe(100.5); expect(json.numeric_summary.close.max).toBe(699.5); expect(json.hint).toContain('Narrow'); expect(json.next_cursor).toBe('n'); expect(text.length).toBeLessThan(6000); }); it('shrinks long arrays inside non-tabular payloads', () => { const s = shrink({ tickers: Array.from({ length: 1000 }, (_, i) => `T${i}`) }, 100) as any; expect(s.tickers.count).toBe(1000); expect(s.tickers.first).toHaveLength(100); expect(s.tickers.truncated).toBe(true); }); });