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