From bbcf26477112b0b3386ea30b6cb41cbb682644e1 Mon Sep 17 00:00:00 2001 From: jedarden Date: Sat, 2 May 2026 17:07:24 -0400 Subject: [PATCH] fix: resolve vitest mock hoisting errors in test files Fix CrossReferencePanel.test.ts and WorkerAnalyticsPanel.test.ts which failed to load due to vi.mock() hoisting issues. The vi.mock() factory functions referenced variables declared after the mock call. When vitest hoists these mocks to the top of the file, those variables weren't initialized yet, causing "Cannot access before initialization" errors. Solution: Use vi.hoisted() to declare mock variables before the factory runs, ensuring they're available when the mock is evaluated. Co-Authored-By: Claude Opus 4.7 --- .../components/CrossReferencePanel.test.ts | 45 ++++++++++++------- .../components/WorkerAnalyticsPanel.test.ts | 18 ++++---- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/tui/components/CrossReferencePanel.test.ts b/src/tui/components/CrossReferencePanel.test.ts index 0e54a53..531ebd3 100644 --- a/src/tui/components/CrossReferencePanel.test.ts +++ b/src/tui/components/CrossReferencePanel.test.ts @@ -63,21 +63,26 @@ vi.mock('../utils/colors.js', () => ({ }, })); -// Module-level variables to track mock instance and functions -let mockManagerInstance: any = null; -export const mockGetEntity = vi.fn(function() { return null; }); -export const mockGetLinksForEntity = vi.fn(function() { return []; }); -export const mockGetStats = vi.fn(function() { return ({ - totalLinks: 0, - totalEntities: 0, - byRelationship: {}, - byEntityType: {}, - mostLinked: [], - recentLinks: [], -});}); -export const mockFindPath = vi.fn(function() { return null; }); +// Mock crossReferenceManager module - use vi.hoisted to declare variables before factory runs +const { mockGetEntity, mockGetLinksForEntity, mockGetStats, mockFindPath, getMockManagerInstance, setMockManagerInstance } = vi.hoisted(() => { + let instance: any = null; + return { + getMockManagerInstance: () => instance, + setMockManagerInstance: (val: any) => { instance = val; }, + mockGetEntity: vi.fn(function() { return null; }), + mockGetLinksForEntity: vi.fn(function() { return []; }), + mockGetStats: vi.fn(function() { return ({ + totalLinks: 0, + totalEntities: 0, + byRelationship: {}, + byEntityType: {}, + mostLinked: [], + recentLinks: [], + });}), + mockFindPath: vi.fn(function() { return null; }), + }; +}); -// Mock crossReferenceManager module - define the class inside the factory vi.mock('../../crossReferenceManager.js', () => { class MockCrossReferenceManager { getEntity = mockGetEntity; @@ -87,10 +92,13 @@ vi.mock('../../crossReferenceManager.js', () => { } const MockConstructor = vi.fn(function() { - if (!mockManagerInstance) { - mockManagerInstance = new MockCrossReferenceManager(); + const current = getMockManagerInstance(); + if (!current) { + const newInstance = new MockCrossReferenceManager(); + setMockManagerInstance(newInstance); + return newInstance; } - return mockManagerInstance; + return current; }); return { @@ -99,6 +107,9 @@ vi.mock('../../crossReferenceManager.js', () => { }; }); +// Export the hoisted mock functions for test access +export { mockGetEntity, mockGetLinksForEntity, mockGetStats, mockFindPath }; + // Import after mocking import { CrossReferencePanel, createCrossReferencePanel } from './CrossReferencePanel.js'; import { CrossReferenceManager } from '../../crossReferenceManager.js'; diff --git a/src/tui/components/WorkerAnalyticsPanel.test.ts b/src/tui/components/WorkerAnalyticsPanel.test.ts index 4406615..f4025c7 100644 --- a/src/tui/components/WorkerAnalyticsPanel.test.ts +++ b/src/tui/components/WorkerAnalyticsPanel.test.ts @@ -71,10 +71,10 @@ vi.mock('../utils/colors.js', () => ({ }, })); -// Mock workerAnalytics module - define the class inside the factory -vi.mock('../../workerAnalytics.js', () => { - class MockWorkerAnalytics { - compareWorkers = () => ({ +// Mock workerAnalytics module - use vi.hoisted to properly handle class factory +const { MockWorkerAnalytics } = vi.hoisted(() => { + class MockWorkerAnalyticsClass { + compareWorkers = vi.fn(() => ({ worker1: { workerId: 'w-1', beadsCompleted: 10, beadsPerHour: 5, avgCompletionTimeMs: 1000, errorRate: 0.1, costPerBead: 0.5, totalCostUsd: 5, efficiencyScore: 0.8, activeTimeMs: 10000, idlePercentage: 0.2, errorCount: 1, totalTokens: 1000, trend: undefined }, worker2: { workerId: 'w-2', beadsCompleted: 15, beadsPerHour: 7, avgCompletionTimeMs: 800, errorRate: 0.05, costPerBead: 0.3, totalCostUsd: 4.5, efficiencyScore: 0.9, activeTimeMs: 15000, idlePercentage: 0.1, errorCount: 0, totalTokens: 900, trend: undefined }, differences: { beadsCompleted: -5, beadsPerHour: -2, avgCompletionTimeMs: 200, errorRate: 0.05, costPerBead: 0.2, efficiencyScore: -0.1, activeTimeMs: -5000, idlePercentage: 0.1, totalCostUsd: 0.5, totalTokens: 100 }, @@ -82,13 +82,15 @@ vi.mock('../../workerAnalytics.js', () => { betterWorker: { beadsCompleted: 'worker2', beadsPerHour: 'worker2', avgCompletionTimeMs: 'worker2', errorRate: 'worker2', costPerBead: 'worker2', efficiencyScore: 'worker2', activeTimeMs: 'worker2', idlePercentage: 'worker2', totalCostUsd: 'worker2' }, score: { worker1: 0, worker2: 9 }, overallWinner: 'worker2', - }); + })); } - return { - WorkerAnalytics: MockWorkerAnalytics, - }; + return { MockWorkerAnalytics: MockWorkerAnalyticsClass }; }); +vi.mock('../../workerAnalytics.js', () => ({ + WorkerAnalytics: MockWorkerAnalytics, +})); + // Import after mocking import { WorkerAnalyticsPanel } from './WorkerAnalyticsPanel.js'; import { WorkerAnalytics } from '../../workerAnalytics.js';