src/format/index.test.ts
v0.3.0 · 3.1 KB
import { describe, expect, it } from 'vitest';
import * as format from './index.js';
import { HlFormatError, normalizeDecimal } from './index.js';
describe('normalizeDecimal', () => {
it('produces the canonical wire string without rounding', () => {
expect(normalizeDecimal('83.2050')).toBe('83.205');
expect(normalizeDecimal(1e-7)).toBe('0.0000001');
expect(String(1e-7)).toBe('1e-7'); // what the SDK schema would reject
expect(normalizeDecimal(1.5e21)).toBe('1500000000000000000000');
expect(normalizeDecimal('-0.0')).toBe('0');
expect(normalizeDecimal('007.50')).toBe('7.5');
expect(normalizeDecimal('.5')).toBe('0.5');
expect(normalizeDecimal('1e+3')).toBe('1000');
expect(normalizeDecimal(-1.25)).toBe('-1.25');
expect(normalizeDecimal('0.123456789123456789')).toBe('0.123456789123456789');
});
it('throws on non-finite or malformed input', () => {
for (const bad of [Infinity, NaN, 'abc', '1.2.3', '']) {
expect(() => normalizeDecimal(bad)).toThrow(HlFormatError);
}
});
it('HlFormatError is a named Error', () => {
try {
normalizeDecimal('nope');
} catch (e) {
expect(e).toBeInstanceOf(Error);
expect((e as Error).name).toBe('HlFormatError');
}
});
});
describe('public API surface', () => {
it('exports every documented function and constant', () => {
const names = [
'normalizeDecimal',
'assertSzDecimals',
'szStep',
'formatSize',
'sizeFromNotional',
'isValidSize',
'isFullyFilled',
'hasHiddenRemainder',
'pxDecimals',
'formatPrice',
'priceTick',
'isValidPrice',
'shiftPriceTicks',
'samePriceOnGrid',
'notional',
'meetsMinNotional',
'bumpToMinNotional',
'planOrderSize',
'marketLimitPrice',
'exitSlippage',
'escalatingSlippage',
'postOnlyPrice',
'validateOrder',
'triggerPxMatches',
'quoteSizeFromNotional',
'isFlatPosition',
'positionMatchesExpected',
] as const;
for (const name of names) expect(typeof format[name]).toBe('function');
expect(format.MIN_ORDER_NOTIONAL_USD).toBe(10);
expect(format.MAX_SZ_DECIMALS).toBe(8);
expect(format.MAX_PRICE_SIG_FIGS).toBe(5);
expect(typeof format.HlFormatError).toBe('function');
});
it('does not leak private decimal helpers', () => {
expect('parseDec' in format).toBe(false);
expect('roundRatio' in format).toBe(false);
expect('roundPriceDec' in format).toBe(false);
});
});
describe('end-to-end: market IoC entry', () => {
it('limit price, size and validation agree', () => {
const szDecimals = 2;
const p = format.marketLimitPrice({ mid: '34.9', side: 'B', slippage: 0.01, szDecimals });
const plan = format.planOrderSize({ intent: 'open', size: format.sizeFromNotional(12, p, szDecimals), px: p, szDecimals });
expect(p).toBe('35.249');
expect(plan).toMatchObject({ action: 'place', sz: '0.34' });
if (plan.action !== 'place') throw new Error('unreachable');
expect(format.validateOrder({ px: p, sz: plan.sz, szDecimals }).ok).toBe(true);
});
});