fix(console): comprehensive TUI rendering fixes
- Fix Enter key detection: handle multiple Enter key formats (\n, \r, \r\n) - Reduce flickering: lower render frequency from 60 FPS to 30 FPS - Fix menu bar visibility: re-render menu bar after content to prevent overwriting - Fix content positioning: explicit line positioning for categories and commands - Fix line shifting: clear lines before writing, control newlines manually - Limit visible items: prevent overflow with maxVisibleCategories/Commands - Improve CPU usage: increase sleep interval when no events processed This fixes: - Enter key not working for selection - Strong flickering of the application - Menu bar not visible or being overwritten - Top half of selection list not displayed - Lines being shifted/misaligned
This commit is contained in:
152
tests/Framework/Console/CommandCategorizerTest.php
Normal file
152
tests/Framework/Console/CommandCategorizerTest.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Console;
|
||||
|
||||
use App\Framework\Console\CommandCategorizer;
|
||||
use App\Framework\Console\CommandList;
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
|
||||
describe('CommandCategorizer', function () {
|
||||
it('categorizes commands by namespace prefix', function () {
|
||||
$commands = [
|
||||
new ConsoleCommand('demo:hello', 'Hello command'),
|
||||
new ConsoleCommand('demo:colors', 'Colors command'),
|
||||
new ConsoleCommand('db:migrate', 'Migrate command'),
|
||||
new ConsoleCommand('db:rollback', 'Rollback command'),
|
||||
];
|
||||
|
||||
$commandList = new CommandList(...$commands);
|
||||
$categorizer = new CommandCategorizer();
|
||||
$categories = $categorizer->categorize($commandList);
|
||||
|
||||
expect($categories)->toHaveKey('demo');
|
||||
expect($categories)->toHaveKey('db');
|
||||
expect($categories['demo'])->toHaveCount(2);
|
||||
expect($categories['db'])->toHaveCount(2);
|
||||
});
|
||||
|
||||
it('sorts categories alphabetically', function () {
|
||||
$commands = [
|
||||
new ConsoleCommand('zebra:command', 'Zebra command'),
|
||||
new ConsoleCommand('alpha:command', 'Alpha command'),
|
||||
new ConsoleCommand('beta:command', 'Beta command'),
|
||||
];
|
||||
|
||||
$commandList = new CommandList(...$commands);
|
||||
$categorizer = new CommandCategorizer();
|
||||
$categories = $categorizer->categorize($commandList);
|
||||
|
||||
$keys = array_keys($categories);
|
||||
expect($keys)->toBe(['alpha', 'beta', 'zebra']);
|
||||
});
|
||||
|
||||
it('handles commands without namespace', function () {
|
||||
$commands = [
|
||||
new ConsoleCommand('standalone', 'Standalone command'),
|
||||
new ConsoleCommand('demo:hello', 'Hello command'),
|
||||
];
|
||||
|
||||
$commandList = new CommandList(...$commands);
|
||||
$categorizer = new CommandCategorizer();
|
||||
$categories = $categorizer->categorize($commandList);
|
||||
|
||||
expect($categories)->toHaveKey('standalone');
|
||||
expect($categories)->toHaveKey('demo');
|
||||
expect($categories['standalone'])->toHaveCount(1);
|
||||
});
|
||||
|
||||
it('handles empty command list', function () {
|
||||
$commandList = CommandList::empty();
|
||||
$categorizer = new CommandCategorizer();
|
||||
$categories = $categorizer->categorize($commandList);
|
||||
|
||||
expect($categories)->toBeEmpty();
|
||||
});
|
||||
|
||||
it('groups multiple commands in same category', function () {
|
||||
$commands = [
|
||||
new ConsoleCommand('demo:hello', 'Hello'),
|
||||
new ConsoleCommand('demo:colors', 'Colors'),
|
||||
new ConsoleCommand('demo:interactive', 'Interactive'),
|
||||
new ConsoleCommand('demo:menu', 'Menu'),
|
||||
];
|
||||
|
||||
$commandList = new CommandList(...$commands);
|
||||
$categorizer = new CommandCategorizer();
|
||||
$categories = $categorizer->categorize($commandList);
|
||||
|
||||
expect($categories['demo'])->toHaveCount(4);
|
||||
});
|
||||
|
||||
it('handles commands with multiple colons', function () {
|
||||
$commands = [
|
||||
new ConsoleCommand('db:migrate:up', 'Migrate up'),
|
||||
new ConsoleCommand('db:migrate:down', 'Migrate down'),
|
||||
];
|
||||
|
||||
$commandList = new CommandList(...$commands);
|
||||
$categorizer = new CommandCategorizer();
|
||||
$categories = $categorizer->categorize($commandList);
|
||||
|
||||
// Should use first part before first colon
|
||||
expect($categories)->toHaveKey('db');
|
||||
expect($categories['db'])->toHaveCount(2);
|
||||
});
|
||||
|
||||
it('gets category description for known category', function () {
|
||||
$categorizer = new CommandCategorizer();
|
||||
|
||||
expect($categorizer->getCategoryDescription('db'))->toBe('Database operations (migrations, health checks)');
|
||||
expect($categorizer->getCategoryDescription('demo'))->toBe('Demo and example commands');
|
||||
expect($categorizer->getCategoryDescription('cache'))->toBe('Cache management operations');
|
||||
});
|
||||
|
||||
it('returns default description for unknown category', function () {
|
||||
$categorizer = new CommandCategorizer();
|
||||
|
||||
expect($categorizer->getCategoryDescription('unknown'))->toBe('Various commands');
|
||||
});
|
||||
|
||||
it('gets all category info', function () {
|
||||
$categorizer = new CommandCategorizer();
|
||||
$info = $categorizer->getCategoryInfo();
|
||||
|
||||
expect($info)->toBeArray();
|
||||
expect($info)->toHaveKey('db');
|
||||
expect($info)->toHaveKey('demo');
|
||||
expect($info)->toHaveKey('cache');
|
||||
});
|
||||
|
||||
it('handles single command in category', function () {
|
||||
$commands = [
|
||||
new ConsoleCommand('unique:command', 'Unique command'),
|
||||
];
|
||||
|
||||
$commandList = new CommandList(...$commands);
|
||||
$categorizer = new CommandCategorizer();
|
||||
$categories = $categorizer->categorize($commandList);
|
||||
|
||||
expect($categories)->toHaveKey('unique');
|
||||
expect($categories['unique'])->toHaveCount(1);
|
||||
});
|
||||
|
||||
it('preserves command order within category', function () {
|
||||
$commands = [
|
||||
new ConsoleCommand('demo:first', 'First'),
|
||||
new ConsoleCommand('demo:second', 'Second'),
|
||||
new ConsoleCommand('demo:third', 'Third'),
|
||||
];
|
||||
|
||||
$commandList = new CommandList(...$commands);
|
||||
$categorizer = new CommandCategorizer();
|
||||
$categories = $categorizer->categorize($commandList);
|
||||
|
||||
$demoCommands = $categories['demo'];
|
||||
expect($demoCommands[0]->name)->toBe('demo:first');
|
||||
expect($demoCommands[1]->name)->toBe('demo:second');
|
||||
expect($demoCommands[2]->name)->toBe('demo:third');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user