feat(ui): replace emoji complexity indicators with clean filled circle characters

Replace 🟢, 🟡, 🔴 emojis with ● character in getComplexityWithColor function

Update corresponding unit tests to expect ● instead of emojis

Improves UI continuity
This commit is contained in:
Eyal Toledano
2025-06-07 12:57:45 -04:00
parent ee0be04302
commit bf2053e140
4 changed files with 1953 additions and 1953 deletions

View File

@@ -1,6 +1,6 @@
# Task ID: 95
# Title: Implement .taskmaster Directory Structure
# Status: in-progress
# Status: done
# Dependencies: 1, 3, 4, 17
# Priority: high
# Description: Consolidate all Task Master-managed files in user projects into a clean, centralized .taskmaster/ directory structure to improve organization and keep user project directories clean, based on GitHub issue #275.
@@ -105,7 +105,7 @@ Update Task Master's file handling code to use the new paths: tasks in .taskmast
### Details:
Update the task file generation system to create and read task files from .taskmaster/tasks/ instead of tasks/. Ensure all template paths are updated. Modify any path resolution logic specific to task file handling.
## 4. Implement backward compatibility logic [in-progress]
## 4. Implement backward compatibility logic [done]
### Dependencies: 95.2, 95.3
### Description: Add fallback mechanisms to support both old and new file locations during transition
### Details:
@@ -141,7 +141,7 @@ Update README.md and other documentation to reflect the new .taskmaster structur
### Details:
Create functionality to support user-defined templates in .taskmaster/templates/. Allow users to store custom task templates, PRD templates, or other reusable files. Update Task Master commands to recognize and use templates from this directory when available.
## 10. Verify clean user project directories [in-progress]
## 10. Verify clean user project directories [done]
### Dependencies: 95.8, 95.9
### Description: Ensure the new structure keeps user project root directories clean and organized
### Details:

View File

@@ -5681,7 +5681,7 @@
"id": 95,
"title": "Implement .taskmaster Directory Structure",
"description": "Consolidate all Task Master-managed files in user projects into a clean, centralized .taskmaster/ directory structure to improve organization and keep user project directories clean, based on GitHub issue #275.",
"status": "in-progress",
"status": "done",
"dependencies": [
1,
3,
@@ -5732,7 +5732,7 @@
3
],
"details": "Implement path fallback logic that checks both old and new locations when files aren't found. Add deprecation warnings when old paths are used, informing users about the new structure. Ensure error messages are clear about the transition.",
"status": "in-progress",
"status": "done",
"testStrategy": "Test with both old and new directory structures to verify fallback works correctly. Verify deprecation warnings appear when using old paths."
},
{
@@ -5804,7 +5804,7 @@
9
],
"details": "Validate that after implementing the new structure, user project root directories only contain their actual project files plus the single .taskmaster/ directory. Verify that no Task Master files are created outside of .taskmaster/. Test that users can easily add .taskmaster/ to .gitignore if they choose to exclude Task Master files from version control.",
"status": "in-progress",
"status": "done",
"testStrategy": "Test complete workflows and verify only .taskmaster/ directory is created in project root. Check that all Task Master operations respect the new file organization. Verify .gitignore compatibility."
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -2,245 +2,245 @@
* UI module tests
*/
import { jest } from '@jest/globals';
import { jest } from "@jest/globals";
import {
getStatusWithColor,
formatDependenciesWithStatus,
createProgressBar,
getComplexityWithColor
} from '../../scripts/modules/ui.js';
import { sampleTasks } from '../fixtures/sample-tasks.js';
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;
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;
// Add hex and other methods
chalk.hex = () => origChalkFn;
chalk.rgb = () => origChalkFn;
return chalk;
return chalk;
});
jest.mock('figlet', () => ({
textSync: jest.fn(() => 'Task Master Banner')
jest.mock("figlet", () => ({
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.fn(() => ({
start: jest.fn(),
succeed: jest.fn(),
fail: jest.fn(),
stop: jest.fn()
}))
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("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("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/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()
jest.mock("../../scripts/modules/task-manager.js", () => ({
findNextTask: jest.fn(),
analyzeTaskComplexity: jest.fn(),
}));
describe('UI Module', () => {
beforeEach(() => {
jest.clearAllMocks();
});
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('✅');
});
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 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('⏱️');
});
test("should return deferred status with emoji for console output", () => {
const result = getStatusWithColor("deferred");
expect(result).toMatch(/deferred/);
expect(result).toContain("⏱️");
});
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 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 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('✓');
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 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 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');
});
});
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' }
];
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);
const result = formatDependenciesWithStatus(dependencies, allTasks);
// With recent changes, we expect just plain IDs when forConsole is false
expect(result).toBe('1, 2, 3');
});
// 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' }
];
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);
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');
// 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 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 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' }];
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)');
});
});
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%');
});
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 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 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%');
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%');
});
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
});
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%');
});
});
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('🔴');
});
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 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 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('🔴');
});
});
test("should handle non-numeric inputs", () => {
const result = getComplexityWithColor("high");
expect(result).toMatch(/high/);
expect(result).toContain("●");
});
});
});