// tab-badges.test.mjs — TDD tests for computeTabBadgeCounts // // Tests the pure function that computes badge counts for the // 'interrupted', 'ready', and 'running' tabs. // // Run with: node --test web/test/tab-badges.test.mjs import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; // ── Inline implementation (will be replaced by import once exported) ─────────── const INTERRUPTED_STATES = new Set(['CANCELLED', 'FAILED', 'BUDGET_EXCEEDED', 'BLOCKED']); function computeTabBadgeCounts(tasks) { let interrupted = 0; let ready = 0; let running = 0; for (const t of tasks) { if (INTERRUPTED_STATES.has(t.state)) interrupted++; if (t.state === 'READY') ready++; if (t.state === 'RUNNING') running++; } return { interrupted, ready, running }; } // ── Helpers ──────────────────────────────────────────────────────────────────── function makeTask(state) { return { id: state, name: `task-${state}`, state }; } // ── Tests ────────────────────────────────────────────────────────────────────── describe('computeTabBadgeCounts', () => { it('returns all zeros for empty task list', () => { assert.deepEqual(computeTabBadgeCounts([]), { interrupted: 0, ready: 0, running: 0 }); }); it('counts RUNNING tasks', () => { const tasks = [makeTask('RUNNING'), makeTask('RUNNING'), makeTask('QUEUED')]; const counts = computeTabBadgeCounts(tasks); assert.equal(counts.running, 2); assert.equal(counts.ready, 0); assert.equal(counts.interrupted, 0); }); it('counts READY tasks', () => { const tasks = [makeTask('READY'), makeTask('READY'), makeTask('QUEUED')]; const counts = computeTabBadgeCounts(tasks); assert.equal(counts.ready, 2); assert.equal(counts.running, 0); assert.equal(counts.interrupted, 0); }); it('counts CANCELLED as interrupted', () => { const counts = computeTabBadgeCounts([makeTask('CANCELLED')]); assert.equal(counts.interrupted, 1); }); it('counts FAILED as interrupted', () => { const counts = computeTabBadgeCounts([makeTask('FAILED')]); assert.equal(counts.interrupted, 1); }); it('counts BUDGET_EXCEEDED as interrupted', () => { const counts = computeTabBadgeCounts([makeTask('BUDGET_EXCEEDED')]); assert.equal(counts.interrupted, 1); }); it('counts BLOCKED as interrupted', () => { const counts = computeTabBadgeCounts([makeTask('BLOCKED')]); assert.equal(counts.interrupted, 1); }); it('does not count COMPLETED as interrupted', () => { const counts = computeTabBadgeCounts([makeTask('COMPLETED')]); assert.equal(counts.interrupted, 0); }); it('does not count TIMED_OUT as interrupted', () => { const counts = computeTabBadgeCounts([makeTask('TIMED_OUT')]); assert.equal(counts.interrupted, 0); }); it('counts across multiple states simultaneously', () => { const tasks = [ makeTask('RUNNING'), makeTask('RUNNING'), makeTask('READY'), makeTask('CANCELLED'), makeTask('FAILED'), makeTask('BLOCKED'), makeTask('QUEUED'), makeTask('COMPLETED'), ]; const counts = computeTabBadgeCounts(tasks); assert.equal(counts.running, 2); assert.equal(counts.ready, 1); assert.equal(counts.interrupted, 3); }); it('returns zero for a tab when no tasks match that state', () => { const tasks = [makeTask('QUEUED'), makeTask('PENDING'), makeTask('COMPLETED')]; const counts = computeTabBadgeCounts(tasks); assert.equal(counts.running, 0); assert.equal(counts.ready, 0); assert.equal(counts.interrupted, 0); }); });