Skip to main content
Glama
dashboard.component.spec.ts7.13 kB
/** * @fileoverview Tests for dashboard component calculations * Bug fix: Cancelled tasks should be treated as complete */ import type { Subtask, Task, TaskStatus } from '@tm/core'; import { describe, expect, it } from 'vitest'; import { calculateDependencyStatistics, calculateSubtaskStatistics, calculateTaskStatistics } from './dashboard.component.js'; /** * Local test helpers for dashboard statistics tests. * * These helpers create minimal task structures focused on status for statistics * calculations. Only `id` and `status` are typically needed - all other fields * have sensible defaults. */ const createTestTask = ( overrides: Partial<Omit<Task, 'id'>> & Pick<Task, 'id'> ): Task => ({ title: '', description: '', status: 'pending', priority: 'medium', dependencies: [], details: '', testStrategy: '', subtasks: [], ...overrides }); const createTestSubtask = ( id: number | string, parentId: string, status: TaskStatus ): Subtask => ({ id, parentId, title: '', status, description: '', priority: 'medium', dependencies: [], details: '', testStrategy: '' }); describe('dashboard.component - Bug Fix: Cancelled Tasks as Complete', () => { describe('calculateTaskStatistics', () => { it('should treat cancelled tasks as complete in percentage calculation', () => { // Arrange: 14 done, 1 cancelled = 100% complete const tasks: Task[] = [ ...Array.from({ length: 14 }, (_, i) => createTestTask({ id: String(i + 1), status: 'done' }) ), createTestTask({ id: '15', status: 'cancelled' }) ]; // Act const stats = calculateTaskStatistics(tasks); // Assert expect(stats.total).toBe(15); expect(stats.done).toBe(14); expect(stats.cancelled).toBe(1); expect(stats.completedCount).toBe(15); // done + cancelled expect(stats.completionPercentage).toBe(100); }); it('should treat completed status as complete in percentage calculation', () => { // Arrange: Mix of done, completed, cancelled, pending const tasks: Task[] = [ createTestTask({ id: '1', status: 'done' }), createTestTask({ id: '2', status: 'completed' }), createTestTask({ id: '3', status: 'cancelled' }), createTestTask({ id: '4', status: 'pending' }) ]; // Act const stats = calculateTaskStatistics(tasks); // Assert expect(stats.total).toBe(4); expect(stats.done).toBe(1); expect(stats.cancelled).toBe(1); expect(stats.completedCount).toBe(3); // done + completed + cancelled // 3 complete out of 4 total = 75% expect(stats.completionPercentage).toBe(75); }); it('should show 100% completion when all tasks are cancelled', () => { // Arrange const tasks: Task[] = [ createTestTask({ id: '1', status: 'cancelled' }), createTestTask({ id: '2', status: 'cancelled' }) ]; // Act const stats = calculateTaskStatistics(tasks); // Assert expect(stats.total).toBe(2); expect(stats.cancelled).toBe(2); expect(stats.completedCount).toBe(2); // All cancelled = all complete expect(stats.completionPercentage).toBe(100); }); it('should show 0% completion when no tasks are complete', () => { // Arrange const tasks: Task[] = [ createTestTask({ id: '1', status: 'pending' }), createTestTask({ id: '2', status: 'in-progress' }) ]; // Act const stats = calculateTaskStatistics(tasks); // Assert expect(stats.completionPercentage).toBe(0); }); }); describe('calculateSubtaskStatistics', () => { it('should treat cancelled subtasks as complete in percentage calculation', () => { // Arrange: Task with 3 done subtasks and 1 cancelled = 100% const tasks: Task[] = [ createTestTask({ id: '1', status: 'in-progress', subtasks: [ createTestSubtask('1', '1', 'done'), createTestSubtask('2', '1', 'done'), createTestSubtask('3', '1', 'done'), createTestSubtask('4', '1', 'cancelled') ] }) ]; // Act const stats = calculateSubtaskStatistics(tasks); // Assert expect(stats.total).toBe(4); expect(stats.done).toBe(3); expect(stats.cancelled).toBe(1); expect(stats.completedCount).toBe(4); // done + cancelled expect(stats.completionPercentage).toBe(100); }); it('should handle completed status in subtasks', () => { // Arrange const tasks: Task[] = [ createTestTask({ id: '1', status: 'in-progress', subtasks: [ createTestSubtask('1', '1', 'done'), createTestSubtask('2', '1', 'completed'), createTestSubtask('3', '1', 'pending') ] }) ]; // Act const stats = calculateSubtaskStatistics(tasks); // Assert expect(stats.total).toBe(3); expect(stats.completedCount).toBe(2); // done + completed // 2 complete (done + completed) out of 3 = 67% expect(stats.completionPercentage).toBe(67); }); }); describe('calculateDependencyStatistics', () => { it('should treat cancelled tasks as satisfied dependencies', () => { // Arrange: Task 15 depends on cancelled task 14 const tasks: Task[] = [ ...Array.from({ length: 13 }, (_, i) => createTestTask({ id: String(i + 1), status: 'done' }) ), createTestTask({ id: '14', status: 'cancelled' }), createTestTask({ id: '15', status: 'pending', dependencies: ['14'] }) ]; // Act const stats = calculateDependencyStatistics(tasks); // Assert: Task 15 should be ready since its dependency (14) is cancelled expect(stats.tasksBlockedByDeps).toBe(0); expect(stats.tasksReadyToWork).toBe(1); }); it('should treat completed status as satisfied dependencies', () => { // Arrange const tasks: Task[] = [ createTestTask({ id: '1', status: 'completed' }), createTestTask({ id: '2', status: 'pending', dependencies: ['1'] }) ]; // Act const stats = calculateDependencyStatistics(tasks); // Assert expect(stats.tasksBlockedByDeps).toBe(0); expect(stats.tasksReadyToWork).toBe(1); }); it('should count tasks with cancelled dependencies as ready', () => { // Arrange: Multiple tasks depending on cancelled task const tasks: Task[] = [ createTestTask({ id: '1', status: 'cancelled' }), createTestTask({ id: '2', status: 'pending', dependencies: ['1'] }), createTestTask({ id: '3', status: 'pending', dependencies: ['1'] }) ]; // Act const stats = calculateDependencyStatistics(tasks); // Assert expect(stats.tasksBlockedByDeps).toBe(0); expect(stats.tasksReadyToWork).toBe(2); // Both dependents should be ready }); it('should block tasks when only some dependencies are complete', () => { // Arrange: Task 3 depends on task 1 (cancelled) and task 2 (pending) const tasks: Task[] = [ createTestTask({ id: '1', status: 'cancelled' }), createTestTask({ id: '2', status: 'pending' }), createTestTask({ id: '3', status: 'pending', dependencies: ['1', '2'] }) ]; // Act const stats = calculateDependencyStatistics(tasks); // Assert: Task 3 blocked by pending task 2, only task 2 is ready expect(stats.tasksBlockedByDeps).toBe(1); expect(stats.tasksReadyToWork).toBe(1); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/eyaltoledano/claude-task-master'

If you have feedback or need assistance with the MCP directory API, please join our Discord server