- 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
159 lines
4.4 KiB
PHP
159 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Framework\Console\Components;
|
|
|
|
use App\Framework\Console\Components\InteractiveMenu;
|
|
use App\Framework\Console\ConsoleOutput;
|
|
use Tests\Framework\Console\Helpers\TestConsoleOutput;
|
|
|
|
describe('InteractiveMenu', function () {
|
|
beforeEach(function () {
|
|
$this->output = new ConsoleOutput();
|
|
$this->menu = new InteractiveMenu($this->output);
|
|
});
|
|
|
|
it('can be instantiated', function () {
|
|
expect($this->menu)->toBeInstanceOf(InteractiveMenu::class);
|
|
});
|
|
|
|
it('sets title', function () {
|
|
$menu = $this->menu->setTitle('Test Menu');
|
|
|
|
expect($menu)->toBe($this->menu); // Fluent interface
|
|
});
|
|
|
|
it('adds menu items', function () {
|
|
$menu = $this->menu
|
|
->addItem('Option 1', null, 'value1')
|
|
->addItem('Option 2', null, 'value2');
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
|
|
it('adds menu items with callable actions', function () {
|
|
$action = fn () => 'action result';
|
|
$menu = $this->menu->addItem('Option 1', $action);
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
|
|
it('adds separators', function () {
|
|
$menu = $this->menu
|
|
->addItem('Option 1')
|
|
->addSeparator()
|
|
->addItem('Option 2');
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
|
|
it('shows numbers by default', function () {
|
|
$menu = $this->menu->showNumbers(true);
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
|
|
it('hides numbers', function () {
|
|
$menu = $this->menu->showNumbers(false);
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
|
|
it('has showSimple method', function () {
|
|
expect(method_exists($this->menu, 'showSimple'))->toBeTrue();
|
|
});
|
|
|
|
it('has showInteractive method', function () {
|
|
expect(method_exists($this->menu, 'showInteractive'))->toBeTrue();
|
|
});
|
|
|
|
it('builds menu with fluent interface', function () {
|
|
$menu = $this->menu
|
|
->setTitle('Test Menu')
|
|
->addItem('Option 1', null, 'val1')
|
|
->addSeparator()
|
|
->addItem('Option 2', null, 'val2')
|
|
->showNumbers(true);
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
|
|
it('handles empty menu', function () {
|
|
// Should not throw
|
|
expect($this->menu)->toBeInstanceOf(InteractiveMenu::class);
|
|
});
|
|
|
|
it('handles menu with only separators', function () {
|
|
$menu = $this->menu
|
|
->addSeparator()
|
|
->addSeparator();
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
|
|
it('handles very long menu item labels', function () {
|
|
$longLabel = str_repeat('A', 200);
|
|
$menu = $this->menu->addItem($longLabel);
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
|
|
it('handles menu with many items', function () {
|
|
$menu = $this->menu;
|
|
for ($i = 1; $i <= 100; $i++) {
|
|
$menu = $menu->addItem("Option {$i}", null, "value{$i}");
|
|
}
|
|
|
|
expect($menu)->toBe($this->menu);
|
|
});
|
|
});
|
|
|
|
describe('InteractiveMenu Rendering', function () {
|
|
beforeEach(function () {
|
|
$this->output = new TestConsoleOutput();
|
|
$this->menu = new InteractiveMenu($this->output);
|
|
});
|
|
|
|
it('renders menu title in showSimple', function () {
|
|
$this->menu
|
|
->setTitle('Test Menu')
|
|
->addItem('Option 1');
|
|
|
|
// showSimple requires STDIN, so we can't fully test it
|
|
// But we can verify the structure
|
|
expect(method_exists($this->menu, 'showSimple'))->toBeTrue();
|
|
});
|
|
|
|
it('renders menu items in showSimple', function () {
|
|
$this->menu
|
|
->addItem('Option 1')
|
|
->addItem('Option 2')
|
|
->addItem('Option 3');
|
|
|
|
// showSimple requires STDIN
|
|
expect(method_exists($this->menu, 'showSimple'))->toBeTrue();
|
|
});
|
|
|
|
it('renders separators in showSimple', function () {
|
|
$this->menu
|
|
->addItem('Option 1')
|
|
->addSeparator()
|
|
->addItem('Option 2');
|
|
|
|
// showSimple requires STDIN
|
|
expect(method_exists($this->menu, 'showSimple'))->toBeTrue();
|
|
});
|
|
|
|
it('renders interactive menu', function () {
|
|
$this->menu
|
|
->setTitle('Interactive Menu')
|
|
->addItem('Option 1')
|
|
->addItem('Option 2');
|
|
|
|
// showInteractive requires STDIN and terminal capabilities
|
|
expect(method_exists($this->menu, 'showInteractive'))->toBeTrue();
|
|
});
|
|
});
|
|
|