chore: more linting

This commit is contained in:
Eyal Toledano
2025-06-07 20:32:37 -04:00
parent faae0b419d
commit 54bfc72baa
2 changed files with 528 additions and 528 deletions

View File

@@ -1,404 +1,404 @@
/** /**
* Tests for the add-task.js module * Tests for the add-task.js module
*/ */
import { jest } from "@jest/globals"; import { jest } from '@jest/globals';
// Mock the dependencies before importing the module under test // Mock the dependencies before importing the module under test
jest.unstable_mockModule("../../../../../scripts/modules/utils.js", () => ({ jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
readJSON: jest.fn(), readJSON: jest.fn(),
writeJSON: jest.fn(), writeJSON: jest.fn(),
log: jest.fn(), log: jest.fn(),
CONFIG: { CONFIG: {
model: "mock-claude-model", model: 'mock-claude-model',
maxTokens: 4000, maxTokens: 4000,
temperature: 0.7, temperature: 0.7,
debug: false, debug: false
}, },
truncate: jest.fn((text) => text), truncate: jest.fn((text) => text)
})); }));
jest.unstable_mockModule("../../../../../scripts/modules/ui.js", () => ({ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
displayBanner: jest.fn(), displayBanner: jest.fn(),
getStatusWithColor: jest.fn((status) => status), getStatusWithColor: jest.fn((status) => status),
startLoadingIndicator: jest.fn(), startLoadingIndicator: jest.fn(),
stopLoadingIndicator: jest.fn(), stopLoadingIndicator: jest.fn(),
succeedLoadingIndicator: jest.fn(), succeedLoadingIndicator: jest.fn(),
failLoadingIndicator: jest.fn(), failLoadingIndicator: jest.fn(),
warnLoadingIndicator: jest.fn(), warnLoadingIndicator: jest.fn(),
infoLoadingIndicator: jest.fn(), infoLoadingIndicator: jest.fn(),
displayAiUsageSummary: jest.fn(), displayAiUsageSummary: jest.fn()
})); }));
jest.unstable_mockModule( jest.unstable_mockModule(
"../../../../../scripts/modules/ai-services-unified.js", '../../../../../scripts/modules/ai-services-unified.js',
() => ({ () => ({
generateObjectService: jest.fn().mockResolvedValue({ generateObjectService: jest.fn().mockResolvedValue({
mainResult: { mainResult: {
object: { object: {
title: "Task from prompt: Create a new authentication system", title: 'Task from prompt: Create a new authentication system',
description: description:
"Task generated from: Create a new authentication system", 'Task generated from: Create a new authentication system',
details: details:
"Implementation details for task generated from prompt: Create a new authentication system", 'Implementation details for task generated from prompt: Create a new authentication system',
testStrategy: "Write unit tests to verify functionality", testStrategy: 'Write unit tests to verify functionality',
dependencies: [], dependencies: []
}, }
}, },
telemetryData: { telemetryData: {
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
userId: "1234567890", userId: '1234567890',
commandName: "add-task", commandName: 'add-task',
modelUsed: "claude-3-5-sonnet", modelUsed: 'claude-3-5-sonnet',
providerName: "anthropic", providerName: 'anthropic',
inputTokens: 1000, inputTokens: 1000,
outputTokens: 500, outputTokens: 500,
totalTokens: 1500, totalTokens: 1500,
totalCost: 0.012414, totalCost: 0.012414,
currency: "USD", currency: 'USD'
}, }
}), })
}) })
); );
jest.unstable_mockModule( jest.unstable_mockModule(
"../../../../../scripts/modules/config-manager.js", '../../../../../scripts/modules/config-manager.js',
() => ({ () => ({
getDefaultPriority: jest.fn(() => "medium"), getDefaultPriority: jest.fn(() => 'medium')
}) })
); );
jest.unstable_mockModule( jest.unstable_mockModule(
"../../../../../scripts/modules/task-manager/generate-task-files.js", '../../../../../scripts/modules/task-manager/generate-task-files.js',
() => ({ () => ({
default: jest.fn().mockResolvedValue(), default: jest.fn().mockResolvedValue()
}) })
); );
// Mock external UI libraries // Mock external UI libraries
jest.unstable_mockModule("chalk", () => ({ jest.unstable_mockModule('chalk', () => ({
default: { default: {
white: { bold: jest.fn((text) => text) }, white: { bold: jest.fn((text) => text) },
cyan: Object.assign( cyan: Object.assign(
jest.fn((text) => text), jest.fn((text) => text),
{ {
bold: jest.fn((text) => text), bold: jest.fn((text) => text)
} }
), ),
green: jest.fn((text) => text), green: jest.fn((text) => text),
yellow: jest.fn((text) => text), yellow: jest.fn((text) => text),
bold: jest.fn((text) => text), bold: jest.fn((text) => text)
}, }
})); }));
jest.unstable_mockModule("boxen", () => ({ jest.unstable_mockModule('boxen', () => ({
default: jest.fn((text) => text), default: jest.fn((text) => text)
})); }));
jest.unstable_mockModule("cli-table3", () => ({ jest.unstable_mockModule('cli-table3', () => ({
default: jest.fn().mockImplementation(() => ({ default: jest.fn().mockImplementation(() => ({
push: jest.fn(), push: jest.fn(),
toString: jest.fn(() => "mocked table"), toString: jest.fn(() => 'mocked table')
})), }))
})); }));
// Import the mocked modules // Import the mocked modules
const { readJSON, writeJSON, log } = await import( const { readJSON, writeJSON, log } = await import(
"../../../../../scripts/modules/utils.js" '../../../../../scripts/modules/utils.js'
); );
const { generateObjectService } = await import( const { generateObjectService } = await import(
"../../../../../scripts/modules/ai-services-unified.js" '../../../../../scripts/modules/ai-services-unified.js'
); );
const generateTaskFiles = await import( const generateTaskFiles = await import(
"../../../../../scripts/modules/task-manager/generate-task-files.js" '../../../../../scripts/modules/task-manager/generate-task-files.js'
); );
// Import the module under test // Import the module under test
const { default: addTask } = await import( const { default: addTask } = await import(
"../../../../../scripts/modules/task-manager/add-task.js" '../../../../../scripts/modules/task-manager/add-task.js'
); );
describe("addTask", () => { describe('addTask', () => {
const sampleTasks = { const sampleTasks = {
tasks: [ tasks: [
{ {
id: 1, id: 1,
title: "Task 1", title: 'Task 1',
description: "First task", description: 'First task',
status: "pending", status: 'pending',
dependencies: [], dependencies: []
}, },
{ {
id: 2, id: 2,
title: "Task 2", title: 'Task 2',
description: "Second task", description: 'Second task',
status: "pending", status: 'pending',
dependencies: [], dependencies: []
}, },
{ {
id: 3, id: 3,
title: "Task 3", title: 'Task 3',
description: "Third task", description: 'Third task',
status: "pending", status: 'pending',
dependencies: [1], dependencies: [1]
}, }
], ]
}; };
// Create a helper function for consistent mcpLog mock // Create a helper function for consistent mcpLog mock
const createMcpLogMock = () => ({ const createMcpLogMock = () => ({
info: jest.fn(), info: jest.fn(),
warn: jest.fn(), warn: jest.fn(),
error: jest.fn(), error: jest.fn(),
debug: jest.fn(), debug: jest.fn(),
success: jest.fn(), success: jest.fn()
}); });
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
readJSON.mockReturnValue(JSON.parse(JSON.stringify(sampleTasks))); readJSON.mockReturnValue(JSON.parse(JSON.stringify(sampleTasks)));
// Mock console.log to avoid output during tests // Mock console.log to avoid output during tests
jest.spyOn(console, "log").mockImplementation(() => {}); jest.spyOn(console, 'log').mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
console.log.mockRestore(); console.log.mockRestore();
}); });
test("should add a new task using AI", async () => { test('should add a new task using AI', async () => {
// Arrange // Arrange
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const context = { const context = {
mcpLog: createMcpLogMock(), mcpLog: createMcpLogMock()
}; };
// Act // Act
const result = await addTask( const result = await addTask(
"tasks/tasks.json", 'tasks/tasks.json',
prompt, prompt,
[], [],
"medium", 'medium',
context, context,
"json" 'json'
); );
// Assert // Assert
expect(readJSON).toHaveBeenCalledWith("tasks/tasks.json"); expect(readJSON).toHaveBeenCalledWith('tasks/tasks.json');
expect(generateObjectService).toHaveBeenCalledWith(expect.any(Object)); expect(generateObjectService).toHaveBeenCalledWith(expect.any(Object));
expect(writeJSON).toHaveBeenCalledWith( expect(writeJSON).toHaveBeenCalledWith(
"tasks/tasks.json", 'tasks/tasks.json',
expect.objectContaining({ expect.objectContaining({
tasks: expect.arrayContaining([ tasks: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: 4, // Next ID after existing tasks id: 4, // Next ID after existing tasks
title: expect.stringContaining( title: expect.stringContaining(
"Create a new authentication system" 'Create a new authentication system'
), ),
status: "pending", status: 'pending'
}), })
]), ])
}) })
); );
expect(generateTaskFiles.default).toHaveBeenCalled(); expect(generateTaskFiles.default).toHaveBeenCalled();
expect(result).toEqual( expect(result).toEqual(
expect.objectContaining({ expect.objectContaining({
newTaskId: 4, newTaskId: 4,
telemetryData: expect.any(Object), telemetryData: expect.any(Object)
}) })
); );
}); });
test("should validate dependencies when adding a task", async () => { test('should validate dependencies when adding a task', async () => {
// Arrange // Arrange
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const validDependencies = [1, 2]; // These exist in sampleTasks const validDependencies = [1, 2]; // These exist in sampleTasks
const context = { const context = {
mcpLog: createMcpLogMock(), mcpLog: createMcpLogMock()
}; };
// Act // Act
const result = await addTask( const result = await addTask(
"tasks/tasks.json", 'tasks/tasks.json',
prompt, prompt,
validDependencies, validDependencies,
"medium", 'medium',
context, context,
"json" 'json'
); );
// Assert // Assert
expect(writeJSON).toHaveBeenCalledWith( expect(writeJSON).toHaveBeenCalledWith(
"tasks/tasks.json", 'tasks/tasks.json',
expect.objectContaining({ expect.objectContaining({
tasks: expect.arrayContaining([ tasks: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: 4, id: 4,
dependencies: validDependencies, dependencies: validDependencies
}), })
]), ])
}) })
); );
}); });
test("should filter out invalid dependencies", async () => { test('should filter out invalid dependencies', async () => {
// Arrange // Arrange
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const invalidDependencies = [999]; // Non-existent task ID const invalidDependencies = [999]; // Non-existent task ID
const context = { mcpLog: createMcpLogMock() }; const context = { mcpLog: createMcpLogMock() };
// Act // Act
const result = await addTask( const result = await addTask(
"tasks/tasks.json", 'tasks/tasks.json',
prompt, prompt,
invalidDependencies, invalidDependencies,
"medium", 'medium',
context, context,
"json" 'json'
); );
// Assert // Assert
expect(writeJSON).toHaveBeenCalledWith( expect(writeJSON).toHaveBeenCalledWith(
"tasks/tasks.json", 'tasks/tasks.json',
expect.objectContaining({ expect.objectContaining({
tasks: expect.arrayContaining([ tasks: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: 4, id: 4,
dependencies: [], // Invalid dependencies should be filtered out dependencies: [] // Invalid dependencies should be filtered out
}), })
]), ])
}) })
); );
expect(context.mcpLog.warn).toHaveBeenCalledWith( expect(context.mcpLog.warn).toHaveBeenCalledWith(
expect.stringContaining( expect.stringContaining(
"The following dependencies do not exist or are invalid: 999" 'The following dependencies do not exist or are invalid: 999'
) )
); );
}); });
test("should use specified priority", async () => { test('should use specified priority', async () => {
// Arrange // Arrange
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const priority = "high"; const priority = 'high';
const context = { const context = {
mcpLog: createMcpLogMock(), mcpLog: createMcpLogMock()
}; };
// Act // Act
await addTask("tasks/tasks.json", prompt, [], priority, context, "json"); await addTask('tasks/tasks.json', prompt, [], priority, context, 'json');
// Assert // Assert
expect(writeJSON).toHaveBeenCalledWith( expect(writeJSON).toHaveBeenCalledWith(
"tasks/tasks.json", 'tasks/tasks.json',
expect.objectContaining({ expect.objectContaining({
tasks: expect.arrayContaining([ tasks: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
priority: priority, priority: priority
}), })
]), ])
}) })
); );
}); });
test("should handle empty tasks file", async () => { test('should handle empty tasks file', async () => {
// Arrange // Arrange
readJSON.mockReturnValue({ tasks: [] }); readJSON.mockReturnValue({ tasks: [] });
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const context = { const context = {
mcpLog: createMcpLogMock(), mcpLog: createMcpLogMock()
}; };
// Act // Act
const result = await addTask( const result = await addTask(
"tasks/tasks.json", 'tasks/tasks.json',
prompt, prompt,
[], [],
"medium", 'medium',
context, context,
"json" 'json'
); );
// Assert // Assert
expect(result.newTaskId).toBe(1); // First task should have ID 1 expect(result.newTaskId).toBe(1); // First task should have ID 1
expect(writeJSON).toHaveBeenCalledWith( expect(writeJSON).toHaveBeenCalledWith(
"tasks/tasks.json", 'tasks/tasks.json',
expect.objectContaining({ expect.objectContaining({
tasks: expect.arrayContaining([ tasks: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: 1, id: 1
}), })
]), ])
}) })
); );
}); });
test("should handle missing tasks file", async () => { test('should handle missing tasks file', async () => {
// Arrange // Arrange
readJSON.mockReturnValue(null); readJSON.mockReturnValue(null);
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const context = { const context = {
mcpLog: createMcpLogMock(), mcpLog: createMcpLogMock()
}; };
// Act // Act
const result = await addTask( const result = await addTask(
"tasks/tasks.json", 'tasks/tasks.json',
prompt, prompt,
[], [],
"medium", 'medium',
context, context,
"json" 'json'
); );
// Assert // Assert
expect(result.newTaskId).toBe(1); // First task should have ID 1 expect(result.newTaskId).toBe(1); // First task should have ID 1
expect(writeJSON).toHaveBeenCalledTimes(2); // Once to create file, once to add task expect(writeJSON).toHaveBeenCalledTimes(2); // Once to create file, once to add task
}); });
test("should handle AI service errors", async () => { test('should handle AI service errors', async () => {
// Arrange // Arrange
generateObjectService.mockRejectedValueOnce(new Error("AI service failed")); generateObjectService.mockRejectedValueOnce(new Error('AI service failed'));
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const context = { const context = {
mcpLog: createMcpLogMock(), mcpLog: createMcpLogMock()
}; };
// Act & Assert // Act & Assert
await expect( await expect(
addTask("tasks/tasks.json", prompt, [], "medium", context, "json") addTask('tasks/tasks.json', prompt, [], 'medium', context, 'json')
).rejects.toThrow("AI service failed"); ).rejects.toThrow('AI service failed');
}); });
test("should handle file read errors", async () => { test('should handle file read errors', async () => {
// Arrange // Arrange
readJSON.mockImplementation(() => { readJSON.mockImplementation(() => {
throw new Error("File read failed"); throw new Error('File read failed');
}); });
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const context = { const context = {
mcpLog: createMcpLogMock(), mcpLog: createMcpLogMock()
}; };
// Act & Assert // Act & Assert
await expect( await expect(
addTask("tasks/tasks.json", prompt, [], "medium", context, "json") addTask('tasks/tasks.json', prompt, [], 'medium', context, 'json')
).rejects.toThrow("File read failed"); ).rejects.toThrow('File read failed');
}); });
test("should handle file write errors", async () => { test('should handle file write errors', async () => {
// Arrange // Arrange
writeJSON.mockImplementation(() => { writeJSON.mockImplementation(() => {
throw new Error("File write failed"); throw new Error('File write failed');
}); });
const prompt = "Create a new authentication system"; const prompt = 'Create a new authentication system';
const context = { const context = {
mcpLog: createMcpLogMock(), mcpLog: createMcpLogMock()
}; };
// Act & Assert // Act & Assert
await expect( await expect(
addTask("tasks/tasks.json", prompt, [], "medium", context, "json") addTask('tasks/tasks.json', prompt, [], 'medium', context, 'json')
).rejects.toThrow("File write failed"); ).rejects.toThrow('File write failed');
}); });
}); });

View File

@@ -2,245 +2,245 @@
* UI module tests * UI module tests
*/ */
import { jest } from "@jest/globals"; import { jest } from '@jest/globals';
import { import {
getStatusWithColor, getStatusWithColor,
formatDependenciesWithStatus, formatDependenciesWithStatus,
createProgressBar, createProgressBar,
getComplexityWithColor, getComplexityWithColor
} from "../../scripts/modules/ui.js"; } from '../../scripts/modules/ui.js';
import { sampleTasks } from "../fixtures/sample-tasks.js"; import { sampleTasks } from '../fixtures/sample-tasks.js';
// Mock dependencies // Mock dependencies
jest.mock("chalk", () => { jest.mock('chalk', () => {
const origChalkFn = (text) => text; const origChalkFn = (text) => text;
const chalk = origChalkFn; const chalk = origChalkFn;
chalk.green = (text) => text; // Return text as-is for status functions chalk.green = (text) => text; // Return text as-is for status functions
chalk.yellow = (text) => text; chalk.yellow = (text) => text;
chalk.red = (text) => text; chalk.red = (text) => text;
chalk.cyan = (text) => text; chalk.cyan = (text) => text;
chalk.blue = (text) => text; chalk.blue = (text) => text;
chalk.gray = (text) => text; chalk.gray = (text) => text;
chalk.white = (text) => text; chalk.white = (text) => text;
chalk.bold = (text) => text; chalk.bold = (text) => text;
chalk.dim = (text) => text; chalk.dim = (text) => text;
// Add hex and other methods // Add hex and other methods
chalk.hex = () => origChalkFn; chalk.hex = () => origChalkFn;
chalk.rgb = () => origChalkFn; chalk.rgb = () => origChalkFn;
return chalk; return chalk;
}); });
jest.mock("figlet", () => ({ jest.mock('figlet', () => ({
textSync: jest.fn(() => "Task Master Banner"), textSync: jest.fn(() => 'Task Master Banner')
})); }));
jest.mock("boxen", () => jest.fn((text) => `[boxed: ${text}]`)); jest.mock('boxen', () => jest.fn((text) => `[boxed: ${text}]`));
jest.mock("ora", () => jest.mock('ora', () =>
jest.fn(() => ({ jest.fn(() => ({
start: jest.fn(), start: jest.fn(),
succeed: jest.fn(), succeed: jest.fn(),
fail: jest.fn(), fail: jest.fn(),
stop: jest.fn(), stop: jest.fn()
})) }))
); );
jest.mock("cli-table3", () => jest.mock('cli-table3', () =>
jest.fn().mockImplementation(() => ({ jest.fn().mockImplementation(() => ({
push: jest.fn(), push: jest.fn(),
toString: jest.fn(() => "Table Content"), toString: jest.fn(() => 'Table Content')
})) }))
); );
jest.mock("gradient-string", () => jest.fn(() => jest.fn((text) => text))); jest.mock('gradient-string', () => jest.fn(() => jest.fn((text) => text)));
jest.mock("../../scripts/modules/utils.js", () => ({ jest.mock('../../scripts/modules/utils.js', () => ({
CONFIG: { CONFIG: {
projectName: "Test Project", projectName: 'Test Project',
projectVersion: "1.0.0", projectVersion: '1.0.0'
}, },
log: jest.fn(), log: jest.fn(),
findTaskById: jest.fn(), findTaskById: jest.fn(),
readJSON: jest.fn(), readJSON: jest.fn(),
readComplexityReport: jest.fn(), readComplexityReport: jest.fn(),
truncate: jest.fn((text) => text), truncate: jest.fn((text) => text)
})); }));
jest.mock("../../scripts/modules/task-manager.js", () => ({ jest.mock('../../scripts/modules/task-manager.js', () => ({
findNextTask: jest.fn(), findNextTask: jest.fn(),
analyzeTaskComplexity: jest.fn(), analyzeTaskComplexity: jest.fn()
})); }));
describe("UI Module", () => { describe('UI Module', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
describe("getStatusWithColor function", () => { describe('getStatusWithColor function', () => {
test("should return done status with emoji for console output", () => { test('should return done status with emoji for console output', () => {
const result = getStatusWithColor("done"); const result = getStatusWithColor('done');
expect(result).toMatch(/done/); expect(result).toMatch(/done/);
expect(result).toContain("✓"); expect(result).toContain('✓');
}); });
test("should return pending status with emoji for console output", () => { test('should return pending status with emoji for console output', () => {
const result = getStatusWithColor("pending"); const result = getStatusWithColor('pending');
expect(result).toMatch(/pending/); expect(result).toMatch(/pending/);
expect(result).toContain("○"); expect(result).toContain('○');
}); });
test("should return deferred status with emoji for console output", () => { test('should return deferred status with emoji for console output', () => {
const result = getStatusWithColor("deferred"); const result = getStatusWithColor('deferred');
expect(result).toMatch(/deferred/); expect(result).toMatch(/deferred/);
expect(result).toContain("x"); expect(result).toContain('x');
}); });
test("should return in-progress status with emoji for console output", () => { test('should return in-progress status with emoji for console output', () => {
const result = getStatusWithColor("in-progress"); const result = getStatusWithColor('in-progress');
expect(result).toMatch(/in-progress/); expect(result).toMatch(/in-progress/);
expect(result).toContain("🔄"); expect(result).toContain('🔄');
}); });
test("should return unknown status with emoji for console output", () => { test('should return unknown status with emoji for console output', () => {
const result = getStatusWithColor("unknown"); const result = getStatusWithColor('unknown');
expect(result).toMatch(/unknown/); expect(result).toMatch(/unknown/);
expect(result).toContain("❌"); expect(result).toContain('❌');
}); });
test("should use simple icons when forTable is true", () => { test('should use simple icons when forTable is true', () => {
const doneResult = getStatusWithColor("done", true); const doneResult = getStatusWithColor('done', true);
expect(doneResult).toMatch(/done/); expect(doneResult).toMatch(/done/);
expect(doneResult).toContain("✓"); expect(doneResult).toContain('✓');
const pendingResult = getStatusWithColor("pending", true); const pendingResult = getStatusWithColor('pending', true);
expect(pendingResult).toMatch(/pending/); expect(pendingResult).toMatch(/pending/);
expect(pendingResult).toContain("○"); expect(pendingResult).toContain('○');
const inProgressResult = getStatusWithColor("in-progress", true); const inProgressResult = getStatusWithColor('in-progress', true);
expect(inProgressResult).toMatch(/in-progress/); expect(inProgressResult).toMatch(/in-progress/);
expect(inProgressResult).toContain("►"); expect(inProgressResult).toContain('►');
const deferredResult = getStatusWithColor("deferred", true); const deferredResult = getStatusWithColor('deferred', true);
expect(deferredResult).toMatch(/deferred/); expect(deferredResult).toMatch(/deferred/);
expect(deferredResult).toContain("x"); expect(deferredResult).toContain('x');
}); });
}); });
describe("formatDependenciesWithStatus function", () => { describe('formatDependenciesWithStatus function', () => {
test("should format dependencies as plain IDs when forConsole is false (default)", () => { test('should format dependencies as plain IDs when forConsole is false (default)', () => {
const dependencies = [1, 2, 3]; const dependencies = [1, 2, 3];
const allTasks = [ const allTasks = [
{ id: 1, status: "done" }, { id: 1, status: 'done' },
{ id: 2, status: "pending" }, { id: 2, status: 'pending' },
{ id: 3, status: "deferred" }, { id: 3, status: 'deferred' }
]; ];
const result = formatDependenciesWithStatus(dependencies, allTasks); const result = formatDependenciesWithStatus(dependencies, allTasks);
// With recent changes, we expect just plain IDs when forConsole is false // With recent changes, we expect just plain IDs when forConsole is false
expect(result).toBe("1, 2, 3"); expect(result).toBe('1, 2, 3');
}); });
test("should format dependencies with status indicators when forConsole is true", () => { test('should format dependencies with status indicators when forConsole is true', () => {
const dependencies = [1, 2, 3]; const dependencies = [1, 2, 3];
const allTasks = [ const allTasks = [
{ id: 1, status: "done" }, { id: 1, status: 'done' },
{ id: 2, status: "pending" }, { id: 2, status: 'pending' },
{ id: 3, status: "deferred" }, { id: 3, status: 'deferred' }
]; ];
const result = formatDependenciesWithStatus(dependencies, allTasks, true); const result = formatDependenciesWithStatus(dependencies, allTasks, true);
// We can't test for exact color formatting due to our chalk mocks // We can't test for exact color formatting due to our chalk mocks
// Instead, test that the result contains all the expected IDs // Instead, test that the result contains all the expected IDs
expect(result).toContain("1"); expect(result).toContain('1');
expect(result).toContain("2"); expect(result).toContain('2');
expect(result).toContain("3"); expect(result).toContain('3');
// Test that it's a comma-separated list // Test that it's a comma-separated list
expect(result.split(", ").length).toBe(3); expect(result.split(', ').length).toBe(3);
}); });
test('should return "None" for empty dependencies', () => { test('should return "None" for empty dependencies', () => {
const result = formatDependenciesWithStatus([], []); const result = formatDependenciesWithStatus([], []);
expect(result).toBe("None"); expect(result).toBe('None');
}); });
test("should handle missing tasks in the task list", () => { test('should handle missing tasks in the task list', () => {
const dependencies = [1, 999]; const dependencies = [1, 999];
const allTasks = [{ id: 1, status: "done" }]; const allTasks = [{ id: 1, status: 'done' }];
const result = formatDependenciesWithStatus(dependencies, allTasks); const result = formatDependenciesWithStatus(dependencies, allTasks);
expect(result).toBe("1, 999 (Not found)"); expect(result).toBe('1, 999 (Not found)');
}); });
}); });
describe("createProgressBar function", () => { describe('createProgressBar function', () => {
test("should create a progress bar with the correct percentage", () => { test('should create a progress bar with the correct percentage', () => {
const result = createProgressBar(50, 10, { const result = createProgressBar(50, 10, {
pending: 20, pending: 20,
"in-progress": 15, 'in-progress': 15,
blocked: 5, blocked: 5
}); });
expect(result).toContain("50%"); expect(result).toContain('50%');
}); });
test("should handle 0% progress", () => { test('should handle 0% progress', () => {
const result = createProgressBar(0, 10); const result = createProgressBar(0, 10);
expect(result).toContain("0%"); expect(result).toContain('0%');
}); });
test("should handle 100% progress", () => { test('should handle 100% progress', () => {
const result = createProgressBar(100, 10); const result = createProgressBar(100, 10);
expect(result).toContain("100%"); expect(result).toContain('100%');
}); });
test("should handle invalid percentages by clamping", () => { test('should handle invalid percentages by clamping', () => {
const result1 = createProgressBar(0, 10); const result1 = createProgressBar(0, 10);
expect(result1).toContain("0%"); expect(result1).toContain('0%');
const result2 = createProgressBar(100, 10); const result2 = createProgressBar(100, 10);
expect(result2).toContain("100%"); expect(result2).toContain('100%');
}); });
test("should support status breakdown in the progress bar", () => { test('should support status breakdown in the progress bar', () => {
const result = createProgressBar(30, 10, { const result = createProgressBar(30, 10, {
pending: 30, pending: 30,
"in-progress": 20, 'in-progress': 20,
blocked: 10, blocked: 10,
deferred: 5, deferred: 5,
cancelled: 5, cancelled: 5
}); });
expect(result).toContain("40%"); expect(result).toContain('40%');
}); });
}); });
describe("getComplexityWithColor function", () => { describe('getComplexityWithColor function', () => {
test("should return high complexity in red", () => { test('should return high complexity in red', () => {
const result = getComplexityWithColor(8); const result = getComplexityWithColor(8);
expect(result).toMatch(/8/); expect(result).toMatch(/8/);
expect(result).toContain("●"); expect(result).toContain('●');
}); });
test("should return medium complexity in yellow", () => { test('should return medium complexity in yellow', () => {
const result = getComplexityWithColor(5); const result = getComplexityWithColor(5);
expect(result).toMatch(/5/); expect(result).toMatch(/5/);
expect(result).toContain("●"); expect(result).toContain('●');
}); });
test("should return low complexity in green", () => { test('should return low complexity in green', () => {
const result = getComplexityWithColor(3); const result = getComplexityWithColor(3);
expect(result).toMatch(/3/); expect(result).toMatch(/3/);
expect(result).toContain("●"); expect(result).toContain('●');
}); });
test("should handle non-numeric inputs", () => { test('should handle non-numeric inputs', () => {
const result = getComplexityWithColor("high"); const result = getComplexityWithColor('high');
expect(result).toMatch(/high/); expect(result).toMatch(/high/);
expect(result).toContain("●"); expect(result).toContain('●');
}); });
}); });
}); });