# Test Isolation Fix Plan ## Problem Analysis After analyzing the failing tests, we've identified several issues that cause tests to fail when run together but pass individually: 1. **Singleton TimerController**: The `TimerController` class uses a singleton pattern, which means all tests share the same timer instance. This causes interference between tests. 2. **Static Registry in MemoryTransport**: The `MemoryTransport` class uses a static registry (`_instances`) to track all transport instances, which isn't properly cleaned up between tests. 3. **Time-sensitive Tests**: Several tests rely on actual timing with `setTimeout`, making them flaky. 4. **Date.now() Usage**: Tests using `Date.now()` can be affected by other tests that mock time-related functions. ## Proposed Solutions ### 1. Update TimerController to Support Multiple Instances The current `TimerController` is implemented as a singleton, which prevents proper test isolation. We need to modify it to: - Allow creation of independent instances for each test - Add a method to create a factory that provides isolated instances - Ensure `reset()` is called in `beforeEach` and `afterEach` blocks ### 2. Fix MemoryTransport Static Registry - Add a `resetRegistry()` static method to clear all instances - Ensure this is called in `beforeEach` and `afterEach` hooks in tests - Make sure disconnection properly removes instances from the registry ### 3. Refactor Time-Sensitive Tests For each of the failing tests: #### MemoryTransport Tests - Update `should simulate connection delay` to use TimerController instead of real delays - Update `should simulate latency` to use TimerController #### MessageBatch Tests - Update `should track batch age` to use TimerController instead of real setTimeout #### TransportTester Tests - Update message delivery tests to use TimerController - Update reliability tests to address race conditions #### NetworkNodePhase4 Tests - Ensure proper cleanup and isolation of network components ### 4. Create Test Utility Classes Create test utility classes/functions that: - Provide isolated TimerController instances - Help mock Date.now() consistently - Ensure all static registries are reset between tests ## Implementation Details ### TimerController Changes ```typescript // Modifications needed to TimerController export class TimerController { private _currentTime = 0; private _timers: Map = new Map(); private _nextTimerId = 1; // Remove static singleton instance // private static _instance: TimerController; // Replace getInstance with createInstance public static createInstance(): TimerController { return new TimerController(); } // Other methods remain the same... } // Helper for tests export function createIsolatedTimerController(): TimerController { return TimerController.createInstance(); } ``` ### MemoryTransport Test Setup ```typescript // In memory-transport.spec.ts beforeEach(() => { // Reset static registry MemoryTransport.resetRegistry(); // Create fresh instances with isolated timer controllers const timer1 = createIsolatedTimerController(); const timer2 = createIsolatedTimerController(); // Create transports with these timers transport1 = new MemoryTransport('transport-1', { eventEmitter: eventEmitter1, timerController: timer1 }); transport2 = new MemoryTransport('transport-2', { eventEmitter: eventEmitter2, timerController: timer2 }); }); afterEach(() => { // Clean up MemoryTransport.resetRegistry(); }); ``` ### TransportTester Tests The TransportTester tests require special attention to ensure proper timing control. The issue is that these tests verify asynchronous behaviors like message delivery and reliability. ```typescript // In transport-testing.spec.ts beforeEach(() => { // Reset static registries and create isolated timer controllers MemoryTransport.resetRegistry(); const senderTimer = createIsolatedTimerController(); const receiverTimer = createIsolatedTimerController(); // Configure transports with isolated timers sender = new MockTransport('sender', undefined, senderTimer); receiver = new MockTransport('receiver', undefined, receiverTimer); }); afterEach(() => { // Clean up MemoryTransport.resetRegistry(); // Additional cleanup as needed }); ``` ## Next Steps After implementing these changes: 1. Run individual test suites to verify they still pass 2. Run the full test suite to verify the fixes resolved the isolation issues 3. Add documentation about the importance of test isolation 4. Consider adding a linting rule to prevent direct usage of setTimeout/setInterval in tests ## Implementation Recommendation To implement these changes, we should switch to Code mode and systematically update each test file, ensuring that each component of the system is properly isolated from others during testing.