feat: CLI & MCP progress tracking for parse-prd command (#1048)
* initial cutover * update log to debug * update tracker to pass units * update test to match new base tracker format * add streamTextService mocks * remove unused imports * Ensure the CLI waits for async main() completion * refactor to reduce code duplication * update comment * reuse function * ensure targetTag is defined in streaming mode * avoid throwing inside process.exit spy * check for null * remove reference to generate * fix formatting * fix textStream assignment * ensure no division by 0 * fix jest chalk mocks * refactor for maintainability * Improve bar chart calculation logic for consistent visual representation * use custom streaming error types; fix mocks * Update streamText extraction in parse-prd.js to match actual service response * remove check - doesn't belong here * update mocks * remove streaming test that wasn't really doing anything * add comment * make parsing logic more DRY * fix formatting * Fix textStream extraction to match actual service response * fix mock * Add a cleanup method to ensure proper resource disposal and prevent memory leaks * debounce progress updates to reduce UI flicker during rapid updates * Implement timeout protection for streaming operations (60-second timeout) with automatic fallback to non-streaming mode. * clear timeout properly * Add a maximum buffer size limit (1MB) to prevent unbounded memory growth with very large streaming responses. * fix formatting * remove duplicate mock * better docs * fix formatting * sanitize the dynamic property name * Fix incorrect remaining progress calculation * Use onError callback instead of console.warn * Remove unused chalk import * Add missing custom validator in fallback parsing configuration * add custom validator parameter in fallback parsing * chore: fix package-lock.json * chore: large code refactor * chore: increase timeout from 1 minute to 3 minutes * fix: refactor and fix streaming * Merge remote-tracking branch 'origin/next' into joedanz/parse-prd-progress * fix: cleanup and fix unit tests * chore: fix unit tests * chore: fix format * chore: run format * chore: fix weird CI unit test error * chore: fix format --------- Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
This commit is contained in:
169
tests/unit/ui/indicators.test.js
Normal file
169
tests/unit/ui/indicators.test.js
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Unit tests for indicators module (priority and complexity indicators)
|
||||
*/
|
||||
import { jest } from '@jest/globals';
|
||||
|
||||
// Mock chalk using unstable_mockModule for ESM compatibility
|
||||
jest.unstable_mockModule('chalk', () => ({
|
||||
default: {
|
||||
red: jest.fn((str) => str),
|
||||
yellow: jest.fn((str) => str),
|
||||
green: jest.fn((str) => str),
|
||||
white: jest.fn((str) => str),
|
||||
hex: jest.fn(() => jest.fn((str) => str))
|
||||
}
|
||||
}));
|
||||
|
||||
// Import after mocking
|
||||
const {
|
||||
getMcpPriorityIndicators,
|
||||
getCliPriorityIndicators,
|
||||
getPriorityIndicators,
|
||||
getPriorityIndicator,
|
||||
getStatusBarPriorityIndicators,
|
||||
getPriorityColors,
|
||||
getCliComplexityIndicators,
|
||||
getStatusBarComplexityIndicators,
|
||||
getComplexityColors,
|
||||
getComplexityIndicator
|
||||
} = await import('../../../src/ui/indicators.js');
|
||||
|
||||
describe('Priority Indicators', () => {
|
||||
describe('getMcpPriorityIndicators', () => {
|
||||
it('should return emoji indicators for MCP context', () => {
|
||||
const indicators = getMcpPriorityIndicators();
|
||||
expect(indicators).toEqual({
|
||||
high: '🔴',
|
||||
medium: '🟠',
|
||||
low: '🟢'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCliPriorityIndicators', () => {
|
||||
it('should return colored dot indicators for CLI context', () => {
|
||||
const indicators = getCliPriorityIndicators();
|
||||
expect(indicators).toHaveProperty('high');
|
||||
expect(indicators).toHaveProperty('medium');
|
||||
expect(indicators).toHaveProperty('low');
|
||||
// Since chalk is mocked, we're just verifying structure
|
||||
expect(indicators.high).toContain('●');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPriorityIndicators', () => {
|
||||
it('should return MCP indicators when isMcp is true', () => {
|
||||
const indicators = getPriorityIndicators(true);
|
||||
expect(indicators).toEqual({
|
||||
high: '🔴',
|
||||
medium: '🟠',
|
||||
low: '🟢'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return CLI indicators when isMcp is false', () => {
|
||||
const indicators = getPriorityIndicators(false);
|
||||
expect(indicators).toHaveProperty('high');
|
||||
expect(indicators).toHaveProperty('medium');
|
||||
expect(indicators).toHaveProperty('low');
|
||||
});
|
||||
|
||||
it('should default to CLI indicators when no parameter provided', () => {
|
||||
const indicators = getPriorityIndicators();
|
||||
expect(indicators).toHaveProperty('high');
|
||||
expect(indicators.high).toContain('●');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPriorityIndicator', () => {
|
||||
it('should return correct MCP indicator for valid priority', () => {
|
||||
expect(getPriorityIndicator('high', true)).toBe('🔴');
|
||||
expect(getPriorityIndicator('medium', true)).toBe('🟠');
|
||||
expect(getPriorityIndicator('low', true)).toBe('🟢');
|
||||
});
|
||||
|
||||
it('should return correct CLI indicator for valid priority', () => {
|
||||
const highIndicator = getPriorityIndicator('high', false);
|
||||
const mediumIndicator = getPriorityIndicator('medium', false);
|
||||
const lowIndicator = getPriorityIndicator('low', false);
|
||||
|
||||
expect(highIndicator).toContain('●');
|
||||
expect(mediumIndicator).toContain('●');
|
||||
expect(lowIndicator).toContain('●');
|
||||
});
|
||||
|
||||
it('should return medium indicator for invalid priority', () => {
|
||||
expect(getPriorityIndicator('invalid', true)).toBe('🟠');
|
||||
expect(getPriorityIndicator(null, true)).toBe('🟠');
|
||||
expect(getPriorityIndicator(undefined, true)).toBe('🟠');
|
||||
});
|
||||
|
||||
it('should default to CLI context when isMcp not provided', () => {
|
||||
const indicator = getPriorityIndicator('high');
|
||||
expect(indicator).toContain('●');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Complexity Indicators', () => {
|
||||
describe('getCliComplexityIndicators', () => {
|
||||
it('should return colored dot indicators for complexity levels', () => {
|
||||
const indicators = getCliComplexityIndicators();
|
||||
expect(indicators).toHaveProperty('high');
|
||||
expect(indicators).toHaveProperty('medium');
|
||||
expect(indicators).toHaveProperty('low');
|
||||
expect(indicators.high).toContain('●');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getStatusBarComplexityIndicators', () => {
|
||||
it('should return single character indicators for status bars', () => {
|
||||
const indicators = getStatusBarComplexityIndicators();
|
||||
// Since chalk is mocked, we need to check for the actual characters
|
||||
expect(indicators.high).toContain('⋮');
|
||||
expect(indicators.medium).toContain(':');
|
||||
expect(indicators.low).toContain('.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getComplexityColors', () => {
|
||||
it('should return complexity color functions', () => {
|
||||
const colors = getComplexityColors();
|
||||
expect(colors).toHaveProperty('high');
|
||||
expect(colors).toHaveProperty('medium');
|
||||
expect(colors).toHaveProperty('low');
|
||||
// Verify they are functions (mocked chalk functions)
|
||||
expect(typeof colors.high).toBe('function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getComplexityIndicator', () => {
|
||||
it('should return high indicator for scores >= 7', () => {
|
||||
const cliIndicators = getCliComplexityIndicators();
|
||||
expect(getComplexityIndicator(7)).toBe(cliIndicators.high);
|
||||
expect(getComplexityIndicator(8)).toBe(cliIndicators.high);
|
||||
expect(getComplexityIndicator(10)).toBe(cliIndicators.high);
|
||||
});
|
||||
|
||||
it('should return low indicator for scores <= 3', () => {
|
||||
const cliIndicators = getCliComplexityIndicators();
|
||||
expect(getComplexityIndicator(1)).toBe(cliIndicators.low);
|
||||
expect(getComplexityIndicator(2)).toBe(cliIndicators.low);
|
||||
expect(getComplexityIndicator(3)).toBe(cliIndicators.low);
|
||||
});
|
||||
|
||||
it('should return medium indicator for scores 4-6', () => {
|
||||
const cliIndicators = getCliComplexityIndicators();
|
||||
expect(getComplexityIndicator(4)).toBe(cliIndicators.medium);
|
||||
expect(getComplexityIndicator(5)).toBe(cliIndicators.medium);
|
||||
expect(getComplexityIndicator(6)).toBe(cliIndicators.medium);
|
||||
});
|
||||
|
||||
it('should return status bar indicators when statusBar is true', () => {
|
||||
const statusBarIndicators = getStatusBarComplexityIndicators();
|
||||
expect(getComplexityIndicator(8, true)).toBe(statusBarIndicators.high);
|
||||
expect(getComplexityIndicator(5, true)).toBe(statusBarIndicators.medium);
|
||||
expect(getComplexityIndicator(2, true)).toBe(statusBarIndicators.low);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user