spb/hfmarketdata
Public
Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)
JavaScript 53.7%
Python 38.3%
CSS 4.6%
TypeScript 3.1%
1import { describe, expect, it } from 'vitest';2import { extract, renderResult, shrink } from '../src/format.js';3import { rateFromHeaders } from '../src/client.js';4import { bars } from './helpers.js';56const rate = rateFromHeaders(new Headers({ 'x-ratelimit-remaining-requests': '7', 'x-ratelimit-limit-requests': '30' }));78describe('extract', () => {9 it('understands the v1 envelope', () => {10 const e = extract({ count: 2, data: [{ a: 1 }, { a: 2 }] });11 expect(e.rows).toHaveLength(2);12 expect(e.meta.count).toBe(2);13 });14 it('understands the v2 envelope and keeps meta', () => {15 const e = extract({ data: [{ a: 1 }], meta: { count: 1, next_cursor: 'abc', roll_dates: ['2025-03-14'] } });16 expect(e.rows).toHaveLength(1);17 expect(e.meta.next_cursor).toBe('abc');18 });19 it('keeps non-tabular payloads in rest', () => {20 const e = extract({ asset: 'stock', count: 3, tickers: ['A', 'B', 'C'] });21 expect(e.rows).toBeNull();22 expect(e.rest.tickers).toEqual(['A', 'B', 'C']);23 });24});2526describe('renderResult', () => {27 it('renders small tables in full as columns/rows', () => {28 const text = renderResult({ status: 200, url: 'u', body: { count: 3, data: bars(3) }, rate, ms: 1 }, { title: 'T' });29 expect(text.startsWith('T\n')).toBe(true);30 const json = JSON.parse(text.split('\n')[1]);31 expect(json.row_count).toBe(3);32 expect(json.columns).toEqual(['ticker', 'datetime', 'open', 'high', 'low', 'close', 'volume']);33 expect(json.rows).toHaveLength(3);34 expect(json.truncated).toBeUndefined();35 expect(text).toContain('Rate limit: requests 7/30 left');36 });3738 it('summarises large tables with head/tail, numeric ranges and a hint', () => {39 const text = renderResult({ status: 200, url: 'u', body: { data: bars(600), meta: { count: 600, next_cursor: 'n' } }, rate, ms: 1 });40 const json = JSON.parse(text.split('\n')[0]);41 expect(json.truncated).toBe(true);42 expect(json.row_count).toBe(600);43 expect(json.first_rows).toHaveLength(15);44 expect(json.last_rows).toHaveLength(15);45 expect(json.numeric_summary.close.min).toBe(100.5);46 expect(json.numeric_summary.close.max).toBe(699.5);47 expect(json.hint).toContain('Narrow');48 expect(json.next_cursor).toBe('n');49 expect(text.length).toBeLessThan(6000);50 });5152 it('shrinks long arrays inside non-tabular payloads', () => {53 const s = shrink({ tickers: Array.from({ length: 1000 }, (_, i) => `T${i}`) }, 100) as any;54 expect(s.tickers.count).toBe(1000);55 expect(s.tickers.first).toHaveLength(100);56 expect(s.tickers.truncated).toBe(true);57 });58});59