import { describe, expect, it, vi } from 'vitest'; import { OrderRouter } from '../packages/execution/src/orderRouter'; import type { Order, OrderBook } from '../packages/domain/src/types'; const sampleBook: OrderBook = { bids: [{ px: 100, sz: 1 }], asks: [{ px: 100.5, sz: 1 }], ts: Date.now() }; describe('OrderRouter', () => { const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; it('sends limit order within slip guard', async () => { const send = vi.fn(async (order: Order) => ({ id: order.clientId })); const router = new OrderRouter(send, () => sampleBook, { maxBps: 100 }); const order: Order = { clientId: 'o-1', symbol: 'BTC', side: 'buy', px: 100.55, sz: 0.1, tif: 'GTC' }; const id = await router.sendLimit(order); expect(id).toMatch(uuidRegex); expect(send).toHaveBeenCalledWith(expect.objectContaining({ clientId: id })); expect(send).toHaveBeenCalledTimes(1); }); it('rejects orders exceeding slip guard', async () => { const send = vi.fn(async (order: Order) => ({ id: order.clientId })); const router = new OrderRouter(send, () => sampleBook, { maxBps: 10 }); const order: Order = { clientId: 'o-2', symbol: 'BTC', side: 'buy', px: 102, sz: 0.1, tif: 'GTC' }; await expect(router.sendLimit(order)).rejects.toThrow(/slippage/); expect(send).not.toHaveBeenCalled(); }); it('rejects post-only orders that would cross', async () => { const send = vi.fn(async (order: Order) => ({ id: order.clientId })); const router = new OrderRouter(send, () => sampleBook, { maxBps: 100 }); const order: Order = { clientId: 'o-3', symbol: 'BTC', side: 'buy', px: 100.5, sz: 0.1, tif: 'GTC', postOnly: true }; await expect(router.sendLimit(order)).rejects.toThrow(/post-only/); expect(send).not.toHaveBeenCalled(); }); it('throttles orders based on min interval and enforces unique client ids', async () => { const send = vi.fn(async (order: Order) => ({ id: order.clientId })); const router = new OrderRouter(send, () => sampleBook, { maxBps: 100, minIntervalMs: 10 }); const orderA: Order = { clientId: 'o-4', symbol: 'BTC', side: 'buy', px: 100.4, sz: 0.1, tif: 'GTC' }; const orderB: Order = { ...orderA, clientId: 'o-5', px: 100.45 }; await router.sendLimit(orderA); expect(send).toHaveBeenCalledTimes(1); const start = Date.now(); await router.sendLimit(orderB); const elapsed = Date.now() - start; expect(send).toHaveBeenCalledTimes(2); expect(elapsed).toBeGreaterThanOrEqual(8); await expect(router.sendLimit(orderB)).rejects.toThrow(/duplicate clientId/); }); });