# Position Manager Tests ## Overview Comprehensive integration test suite for the Position Manager (`lib/trading/position-manager.ts`), which manages ~1,938 lines of critical trading logic handling real capital. ## Quick Start ```bash # Run all tests npm test # Run tests in watch mode (development) npm run test:watch # Run tests with coverage report npm run test:coverage # Run tests for CI (with JUnit reporter) npm run test:ci ``` ## Test Structure ``` tests/ ├── setup.ts # Global test configuration and mocks ├── helpers/ │ └── trade-factory.ts # Factory functions for creating mock trades ├── integration/ │ └── position-manager/ │ ├── tp1-detection.test.ts # Take Profit 1 detection tests │ ├── breakeven-sl.test.ts # Breakeven SL after TP1 tests │ ├── adx-runner-sl.test.ts # ADX-based runner SL tests │ ├── trailing-stop.test.ts # Trailing stop functionality tests │ ├── edge-cases.test.ts # Edge cases and common pitfalls │ ├── price-verification.test.ts # Price verification before TP flags │ └── decision-helpers.test.ts # Decision helper function tests └── README.md # This file ``` ## Test Coverage These tests verify the **logic** of Position Manager functions in isolation: - Decision helper functions (shouldStopLoss, shouldTakeProfit1, etc.) - Price calculation functions (calculatePrice, calculateProfitPercent) - ADX-based SL positioning logic - Trailing stop mechanics - Token vs USD conversion requirements - Price verification requirements The tests extract and validate the pure calculation logic without importing the actual Position Manager, avoiding complex mocking of: - Drift blockchain connections - Pyth price feeds - Database operations - WebSocket subscriptions This approach: 1. Validates critical trading logic is correct 2. Prevents regression of known bugs (Common Pitfalls) 3. Enables safe refactoring of calculation functions 4. Runs quickly without external dependencies ## Test Data Standards All tests use standardized test data based on actual trading conditions: ```typescript TEST_DEFAULTS = { entry: 140.00, // Entry price atr: 0.43, // ATR value adx: 26.9, // ADX (strong trend) qualityScore: 95, // Signal quality positionSize: 8000, // Position size USD leverage: 15, // Leverage multiplier // LONG targets long: { tp1: 141.20, // +0.86% tp2: 142.41, // +1.72% sl: 138.71, // -0.92% emergencySl: 137.20, // -2% }, // SHORT targets short: { tp1: 138.80, // -0.86% tp2: 137.59, // -1.72% sl: 141.29, // +0.92% emergencySl: 142.80, // +2% }, } ``` ## Common Pitfalls Covered These tests specifically prevent known bugs documented in the codebase: | Pitfall # | Issue | Test File | |-----------|--------------------------------------------|-----------------------------| | #24 | Position.size as tokens, not USD | edge-cases.test.ts | | #43 | TP1 false detection without price check | price-verification.test.ts | | #45 | Wrong entry price for breakeven SL | breakeven-sl.test.ts | | #52 | ADX-based runner SL positioning | adx-runner-sl.test.ts | | #54 | MAE/MFE as percentages, not dollars | edge-cases.test.ts | | #67 | Duplicate closures (atomic deduplication) | Covered by mock structure | ## Test Helpers ### Trade Factory (`tests/helpers/trade-factory.ts`) ```typescript import { createLongTrade, createShortTrade, createTradeAfterTP1, createTradeAfterTP2 } from '../helpers/trade-factory' // Create a basic LONG trade const longTrade = createLongTrade() // Create a SHORT trade with custom entry const shortTrade = createShortTrade({ entryPrice: 150 }) // Create a trade after TP1 hit (40% runner remaining) const runnerTrade = createTradeAfterTP1('long') // Create a trade with trailing stop active const trailingTrade = createTradeAfterTP2('short') ``` ### Custom Matchers ```typescript // Check if value is within a range expect(0.86).toBeWithinRange(0.8, 0.9) // passes ``` ## Why These Tests Matter 1. **Financial Protection**: Position Manager handles real money ($540+ capital). Bugs cost real dollars. 2. **Regression Prevention**: 71+ documented bugs in the codebase. Tests prevent reintroduction. 3. **Safe Refactoring**: With test coverage, code can be improved without fear of breaking existing functionality. 4. **Documentation**: Tests serve as executable documentation of expected behavior. 5. **CI/CD Pipeline**: Automated testing ensures changes don't break critical trading logic. ## Writing New Tests ### Guidelines 1. **Use Factories**: Always use `createLongTrade()` or `createShortTrade()` instead of manual object creation 2. **Test Both Directions**: Every price-based test should cover both LONG and SHORT positions 3. **Test Edge Cases**: Include boundary conditions and error scenarios 4. **Clear Names**: Test names should describe the exact behavior being tested 5. **Reference Pitfalls**: When testing a known bug, reference the pitfall number in comments ### Example Test ```typescript import { createLongTrade, createShortTrade, TEST_DEFAULTS } from '../../helpers/trade-factory' describe('New Feature', () => { it('should handle LONG position correctly', () => { const trade = createLongTrade() // ... test logic expect(result).toBe(expected) }) it('should handle SHORT position correctly', () => { const trade = createShortTrade() // ... test logic expect(result).toBe(expected) }) // Reference known bugs it('should NOT trigger false positive (Pitfall #XX)', () => { // ... regression test }) }) ``` ## Mocked Dependencies The test setup mocks external dependencies to isolate tests: - **Drift Service**: No actual blockchain calls - **Pyth Price Monitor**: No WebSocket connections - **Database Operations**: No actual DB queries - **Telegram Notifications**: No actual messages sent - **Drift Orders**: No actual order placement ## Running Specific Tests ```bash # Run a specific test file npm test -- tests/integration/position-manager/tp1-detection.test.ts # Run tests matching a pattern npm test -- --testNamePattern="LONG" # Run tests in a specific directory npm test -- tests/integration/position-manager/ ``` ## CI Integration Tests run automatically in CI with: - JUnit XML reports for test results - Coverage reports in HTML and text formats - Failure threshold of 60% coverage Configure in `jest.config.js`: ```javascript coverageThreshold: { global: { branches: 60, functions: 60, lines: 60, statements: 60, }, }, ```