test(bf-40cu): fix 6 failing unit tests
Some checks are pending
CI / test (18.x) (push) Waiting to run
CI / test (20.x) (push) Waiting to run
CI / test (22.x) (push) Waiting to run

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
This commit is contained in:
jedarden 2026-05-26 17:16:39 -04:00
parent 9b5e740a92
commit 5b350b9326
4 changed files with 57 additions and 47 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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}`;
}
/**

View file

@ -11,7 +11,7 @@ import { WorkerInfo } from '../src/types';
describe('WorkerGrid', () => {
const createMockWorker = (overrides: Partial<WorkerInfo> = {}): 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
}),
];