Skip to content

Instantly share code, notes, and snippets.

@edmulraney
Created December 16, 2025 12:54
Show Gist options
  • Select an option

  • Save edmulraney/a961208a6af5c2234daaed8d0e4832bc to your computer and use it in GitHub Desktop.

Select an option

Save edmulraney/a961208a6af5c2234daaed8d0e4832bc to your computer and use it in GitHub Desktop.
import type { Address } from 'viem'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { FundingRateArbParams } from './open'
// Only mock external deps - logger and storage
vi.mock('@/lib/logger', () => ({
logger: { getChild: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }) },
}))
vi.mock('@/lib/storage/env-storage', () => ({
envStorage: () => ({
getItem: vi.fn().mockResolvedValue(null),
setItem: vi.fn().mockResolvedValue(undefined),
removeItem: vi.fn(),
}),
}))
vi.mock('@/services/orders/order-store', () => ({
orderStore: {
getState: () => ({
getStrategyOrders: () => ({ longOrders: [], shortOrders: [] }),
getExecutionOrders: () => ({ longOrders: [], shortOrders: [] }),
cancelOrder: vi.fn(),
getOrderById: vi.fn(),
}),
},
}))
const mockParams: FundingRateArbParams = {
userId: 'user-1' as FundingRateArbParams['userId'],
executionId: 'exec-1',
strategyId: 'test-strat',
type: 'funding_arb',
asset: 'BTC',
size: 1,
leverage: 5,
long: {
exchange: 'LIGHTER',
user: '0x123' as Address,
orderType: 'CHASE',
},
short: {
exchange: 'HYPERLIQUID',
user: '0x456' as Address,
orderType: 'MARKET',
slippage: 0.01,
},
}
const mockResult = {
longOrder: { id: 'long-1' },
shortOrder: { id: 'short-1' },
}
describe('StrategyMonitor integration', () => {
beforeEach(() => {
vi.clearAllMocks()
vi.resetModules()
})
describe('strategy.open.done handler', () => {
it('does not regress opened phase to validating', async () => {
// Dynamic imports to get fresh instances
const { bus } = await import('@/lib/events/bus')
const { strategyStore } = await import('./strategy-store')
const { strategyMonitor } = await import('./strategy-monitor')
await strategyMonitor.start()
// Create a strategy and transition to 'opened' (simulating order.updated already transitioned it)
await strategyStore.getState().trackStrategy({
strategyId: 'test-strat',
phase: 'opening',
params: mockParams,
})
await strategyStore.getState().updateStrategy('test-strat', { phase: 'opened' })
expect(strategyStore.getState().getStrategy('test-strat')?.phase).toBe('opened')
// Fire strategy.open.done - should NOT regress to validating
await bus.emit('strategy.open.done', {
strategyId: 'test-strat',
executionId: 'exec-1',
params: mockParams,
result: mockResult as never,
})
// Phase should still be 'opened'
expect(strategyStore.getState().getStrategy('test-strat')?.phase).toBe('opened')
strategyMonitor.stop()
})
it('does not regress balanced phase to validating', async () => {
const { bus } = await import('@/lib/events/bus')
const { strategyStore } = await import('./strategy-store')
const { strategyMonitor } = await import('./strategy-monitor')
await strategyMonitor.start()
await strategyStore.getState().trackStrategy({
strategyId: 'test-strat',
phase: 'opening',
params: mockParams,
})
// Transition through valid path: opening -> validating -> balanced
await strategyStore.getState().updateStrategy('test-strat', { phase: 'validating' })
await strategyStore.getState().updateStrategy('test-strat', { phase: 'balanced' })
expect(strategyStore.getState().getStrategy('test-strat')?.phase).toBe('balanced')
await bus.emit('strategy.open.done', {
strategyId: 'test-strat',
executionId: 'exec-1',
params: mockParams,
result: mockResult as never,
})
expect(strategyStore.getState().getStrategy('test-strat')?.phase).toBe('balanced')
strategyMonitor.stop()
})
it('does not regress imbalanced phase to validating', async () => {
const { bus } = await import('@/lib/events/bus')
const { strategyStore } = await import('./strategy-store')
const { strategyMonitor } = await import('./strategy-monitor')
await strategyMonitor.start()
await strategyStore.getState().trackStrategy({
strategyId: 'test-strat',
phase: 'opening',
params: mockParams,
})
// opening -> imbalanced is valid
await strategyStore.getState().updateStrategy('test-strat', { phase: 'imbalanced' })
expect(strategyStore.getState().getStrategy('test-strat')?.phase).toBe('imbalanced')
await bus.emit('strategy.open.done', {
strategyId: 'test-strat',
executionId: 'exec-1',
params: mockParams,
result: mockResult as never,
})
expect(strategyStore.getState().getStrategy('test-strat')?.phase).toBe('imbalanced')
strategyMonitor.stop()
})
it('transitions opening to validating', async () => {
const { bus } = await import('@/lib/events/bus')
const { strategyStore } = await import('./strategy-store')
const { strategyMonitor } = await import('./strategy-monitor')
await strategyMonitor.start()
await strategyStore.getState().trackStrategy({
strategyId: 'test-strat',
phase: 'opening',
params: mockParams,
})
expect(strategyStore.getState().getStrategy('test-strat')?.phase).toBe('opening')
await bus.emit('strategy.open.done', {
strategyId: 'test-strat',
executionId: 'exec-1',
params: mockParams,
result: mockResult as never,
})
expect(strategyStore.getState().getStrategy('test-strat')?.phase).toBe('validating')
strategyMonitor.stop()
})
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment