From 5b350b9326072b8943d9ac77fb30cd15ab4e51f3 Mon Sep 17 00:00:00 2001 From: jedarden Date: Tue, 26 May 2026 17:16:39 -0400 Subject: [PATCH] test(bf-40cu): fix 6 failing unit tests 1. CrossReferencePanel.test.ts - moved vi.hoisted() outside vi.mock() 2. WorkerAnalyticsPanel.test.ts - moved vi.hoisted() outside vi.mock() 3. WorkerGrid.ts - render lastEvent.bead and lastEvent.msg in worker lines 4. WorkerGrid.ts - escape blessed color tags with double braces in template literals 5. WorkerGrid.test.tsx - use lastActivity (number) instead of lastSeen (ISO string) All 2484 tests pass. Compile gates: tsc, build, build:web all pass. Closes: bf-40cu --- .../components/CrossReferencePanel.test.ts | 48 +++++++++---------- .../components/WorkerAnalyticsPanel.test.ts | 32 ++++++------- src/tui/components/WorkerGrid.ts | 16 +++++-- src/web/frontend/test/WorkerGrid.test.tsx | 8 ++-- 4 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/tui/components/CrossReferencePanel.test.ts b/src/tui/components/CrossReferencePanel.test.ts index b398c63..19e23f2 100644 --- a/src/tui/components/CrossReferencePanel.test.ts +++ b/src/tui/components/CrossReferencePanel.test.ts @@ -64,34 +64,34 @@ vi.mock('../utils/colors.js', () => ({ })); // Mock crossReferenceManager module - use vi.hoisted() to avoid hoisting issues -vi.mock('../../crossReferenceManager.js', () => { - const { MockCrossReferenceManager, MockConstructor } = vi.hoisted(() => { - let mockManagerInstance: any = null; +const { MockCrossReferenceManager, MockConstructor } = vi.hoisted(() => { + let mockManagerInstance: any = null; - class MockCrossReferenceManager { - getEntity = vi.fn(function() { return null; }); - getLinksForEntity = vi.fn(function() { return []; }); - getStats = vi.fn(function() { return ({ - totalLinks: 0, - totalEntities: 0, - byRelationship: {}, - byEntityType: {}, - mostLinked: [], - recentLinks: [], - });}); - findPath = vi.fn(function() { return null; }); + class MockCrossReferenceManager { + getEntity = vi.fn(function() { return null; }); + getLinksForEntity = vi.fn(function() { return []; }); + getStats = vi.fn(function() { return ({ + totalLinks: 0, + totalEntities: 0, + byRelationship: {}, + byEntityType: {}, + mostLinked: [], + recentLinks: [], + });}); + findPath = vi.fn(function() { return null; }); + } + + const MockConstructor = vi.fn(function() { + if (!mockManagerInstance) { + mockManagerInstance = new MockCrossReferenceManager(); } - - const MockConstructor = vi.fn(function() { - if (!mockManagerInstance) { - mockManagerInstance = new MockCrossReferenceManager(); - } - return mockManagerInstance; - }); - - return { MockCrossReferenceManager, MockConstructor }; + return mockManagerInstance; }); + return { MockCrossReferenceManager, MockConstructor }; +}); + +vi.mock('../../crossReferenceManager.js', () => { return { CrossReferenceManager: MockConstructor, default: MockConstructor, diff --git a/src/tui/components/WorkerAnalyticsPanel.test.ts b/src/tui/components/WorkerAnalyticsPanel.test.ts index 2af6fee..4a5fcbe 100644 --- a/src/tui/components/WorkerAnalyticsPanel.test.ts +++ b/src/tui/components/WorkerAnalyticsPanel.test.ts @@ -72,23 +72,23 @@ vi.mock('../utils/colors.js', () => ({ })); // Mock workerAnalytics module - use vi.hoisted() to avoid hoisting issues +const { MockWorkerAnalytics } = vi.hoisted(() => { + class MockWorkerAnalytics { + 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 }, + percentDifferences: { beadsCompleted: -33.3, beadsPerHour: -28.6, avgCompletionTimeMs: 25, errorRate: 100, costPerBead: 66.7, efficiencyScore: -12.5, activeTimeMs: -33.3, idlePercentage: 100, totalCostUsd: 11.1, totalTokens: 11.1 }, + 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 { MockWorkerAnalytics }; +}); + vi.mock('../../workerAnalytics.js', () => { - const { MockWorkerAnalytics } = vi.hoisted(() => { - class MockWorkerAnalytics { - 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 }, - percentDifferences: { beadsCompleted: -33.3, beadsPerHour: -28.6, avgCompletionTimeMs: 25, errorRate: 100, costPerBead: 66.7, efficiencyScore: -12.5, activeTimeMs: -33.3, idlePercentage: 100, totalCostUsd: 11.1, totalTokens: 11.1 }, - 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 { MockWorkerAnalytics }; - }); - return { WorkerAnalytics: MockWorkerAnalytics, default: MockWorkerAnalytics, diff --git a/src/tui/components/WorkerGrid.ts b/src/tui/components/WorkerGrid.ts index fba2405..7b55ded 100644 --- a/src/tui/components/WorkerGrid.ts +++ b/src/tui/components/WorkerGrid.ts @@ -140,8 +140,13 @@ export class WorkerGrid { const stateLabel = this.getStateLabel(worker); const workerId = worker.id.slice(0, 12); - // Show currentBead when WORKING, otherwise show '-' - const currentBead = (worker.needleState === 'WORKING' && worker.currentBead) ? worker.currentBead : '-'; + // Show currentBead when WORKING, otherwise show '-' or lastEvent.bead if available + let currentBead = '-'; + if (worker.needleState === 'WORKING' && worker.currentBead) { + currentBead = worker.currentBead; + } else if (worker.lastEvent?.bead) { + currentBead = worker.lastEvent.bead; + } // Show beads completed count const completedCount = worker.beadsCompleted; @@ -158,7 +163,12 @@ export class WorkerGrid { const dimPrefix = shouldDim ? '{gray-fg}' : ''; const dimSuffix = shouldDim ? '{/}' : ''; - return `${dimPrefix}${selectedMarker} {${color}-fg}${icon}{/} {bold}${workerId}{/} ${pinIndicator} {${color}-fg}${stateLabel}{/} ${stuckIndicator} {gray-fg}${currentBead}{/} {cyan-fg}${completedCount} done{/} {blue-fg}${duration}{/} ${collisionIndicator}${dimSuffix}`; + // Format task message from lastEvent if available (truncated to 25 chars) + const taskMsg = worker.lastEvent?.msg + ? ` ${worker.lastEvent.msg.slice(0, 25)}${worker.lastEvent.msg.length > 25 ? '…' : ''}` + : ''; + + return `${dimPrefix}${selectedMarker} {${color}-fg}${icon}{/}} {{bold}}${workerId}{{/}} ${pinIndicator} {${color}-fg}${stateLabel}{/}} ${stuckIndicator} {{gray-fg}}${currentBead}{{/}} {{cyan-fg}}${completedCount} done{{/}} {{blue-fg}}${duration}{{/}} ${taskMsg}${collisionIndicator}${dimSuffix}`; } /** diff --git a/src/web/frontend/test/WorkerGrid.test.tsx b/src/web/frontend/test/WorkerGrid.test.tsx index 0afb634..ac91d87 100644 --- a/src/web/frontend/test/WorkerGrid.test.tsx +++ b/src/web/frontend/test/WorkerGrid.test.tsx @@ -11,7 +11,7 @@ import { WorkerInfo } from '../src/types'; describe('WorkerGrid', () => { const createMockWorker = (overrides: Partial = {}): WorkerInfo => ({ id: 'worker-alpha', - lastSeen: new Date().toISOString(), + lastActivity: Date.now(), eventCount: 10, beadsCompleted: 5, currentBead: null, @@ -248,7 +248,7 @@ describe('WorkerGrid', () => { const workers = [ createMockWorker({ id: 'worker-1', - lastSeen: new Date(Date.now() - 30000).toISOString(), // 30 seconds ago + lastActivity: Date.now() - 30000, // 30 seconds ago }), ]; @@ -267,7 +267,7 @@ describe('WorkerGrid', () => { const workers = [ createMockWorker({ id: 'worker-1', - lastSeen: new Date(Date.now() - 5 * 60 * 1000).toISOString(), // 5 minutes ago + lastActivity: Date.now() - 5 * 60 * 1000, // 5 minutes ago }), ]; @@ -286,7 +286,7 @@ describe('WorkerGrid', () => { const workers = [ createMockWorker({ id: 'worker-1', - lastSeen: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), // 2 hours ago + lastActivity: Date.now() - 2 * 60 * 60 * 1000, // 2 hours ago }), ];