Created
December 16, 2025 12:54
-
-
Save edmulraney/a961208a6af5c2234daaed8d0e4832bc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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