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:
291
tests/Framework/Console/Components/ConsoleDialogTest.php
Normal file
291
tests/Framework/Console/Components/ConsoleDialogTest.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Console\Components;
|
||||
|
||||
use App\Framework\Console\CommandHistory;
|
||||
use App\Framework\Console\CommandList;
|
||||
use App\Framework\Console\CommandGroupRegistry;
|
||||
use App\Framework\Console\Components\ConsoleDialog;
|
||||
use App\Framework\Console\Components\DialogCommandExecutor;
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\DI\DefaultContainer;
|
||||
use App\Framework\Discovery\Results\AttributeRegistry;
|
||||
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
use App\Framework\Discovery\Results\InterfaceRegistry;
|
||||
use App\Framework\Discovery\Results\TemplateRegistry;
|
||||
use Tests\Framework\Console\Helpers\TestConsoleOutput;
|
||||
|
||||
describe('ConsoleDialog', function () {
|
||||
beforeEach(function () {
|
||||
$this->container = new DefaultContainer();
|
||||
$this->output = new TestConsoleOutput();
|
||||
$this->discoveryRegistry = new DiscoveryRegistry(
|
||||
attributes: new AttributeRegistry(),
|
||||
interfaces: new InterfaceRegistry([]),
|
||||
templates: new TemplateRegistry([])
|
||||
);
|
||||
$this->commandHistory = new CommandHistory();
|
||||
$this->groupRegistry = new CommandGroupRegistry($this->discoveryRegistry);
|
||||
$this->commandList = CommandList::empty();
|
||||
$this->commandExecutor = new DialogCommandExecutor(
|
||||
$this->output,
|
||||
new \App\Framework\Console\CommandRegistry($this->container, $this->discoveryRegistry),
|
||||
$this->commandHistory,
|
||||
'test-console'
|
||||
);
|
||||
});
|
||||
|
||||
it('can be instantiated', function () {
|
||||
$dialog = new ConsoleDialog(
|
||||
$this->output,
|
||||
$this->discoveryRegistry,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->commandExecutor,
|
||||
$this->commandList,
|
||||
$this->container
|
||||
);
|
||||
|
||||
expect($dialog)->toBeInstanceOf(ConsoleDialog::class);
|
||||
});
|
||||
|
||||
it('can be instantiated with custom prompt', function () {
|
||||
$dialog = new ConsoleDialog(
|
||||
$this->output,
|
||||
$this->discoveryRegistry,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->commandExecutor,
|
||||
$this->commandList,
|
||||
$this->container,
|
||||
'custom> '
|
||||
);
|
||||
|
||||
expect($dialog)->toBeInstanceOf(ConsoleDialog::class);
|
||||
});
|
||||
|
||||
it('has run method', function () {
|
||||
$dialog = new ConsoleDialog(
|
||||
$this->output,
|
||||
$this->discoveryRegistry,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->commandExecutor,
|
||||
$this->commandList,
|
||||
$this->container
|
||||
);
|
||||
|
||||
expect(method_exists($dialog, 'run'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has completeCommand method for readline', function () {
|
||||
$dialog = new ConsoleDialog(
|
||||
$this->output,
|
||||
$this->discoveryRegistry,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->commandExecutor,
|
||||
$this->commandList,
|
||||
$this->container
|
||||
);
|
||||
|
||||
expect(method_exists($dialog, 'completeCommand'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('detects readline availability', function () {
|
||||
$dialog = new ConsoleDialog(
|
||||
$this->output,
|
||||
$this->discoveryRegistry,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->commandExecutor,
|
||||
$this->commandList,
|
||||
$this->container
|
||||
);
|
||||
|
||||
// Should detect readline if available
|
||||
expect($dialog)->toBeInstanceOf(ConsoleDialog::class);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ConsoleDialog Input Parsing', function () {
|
||||
beforeEach(function () {
|
||||
$this->container = new DefaultContainer();
|
||||
$this->output = new TestConsoleOutput();
|
||||
$this->discoveryRegistry = new DiscoveryRegistry(
|
||||
attributes: new AttributeRegistry(),
|
||||
interfaces: new InterfaceRegistry([]),
|
||||
templates: new TemplateRegistry([])
|
||||
);
|
||||
$this->commandHistory = new CommandHistory();
|
||||
$this->groupRegistry = new CommandGroupRegistry($this->discoveryRegistry);
|
||||
$this->commandList = CommandList::empty();
|
||||
$this->commandExecutor = new DialogCommandExecutor(
|
||||
$this->output,
|
||||
new \App\Framework\Console\CommandRegistry($this->container, $this->discoveryRegistry),
|
||||
$this->commandHistory,
|
||||
'test-console'
|
||||
);
|
||||
$this->dialog = new ConsoleDialog(
|
||||
$this->output,
|
||||
$this->discoveryRegistry,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->commandExecutor,
|
||||
$this->commandList,
|
||||
$this->container
|
||||
);
|
||||
});
|
||||
|
||||
it('parses simple command', function () {
|
||||
// Use reflection to access private parseInput method
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('parseInput');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->dialog, 'demo:hello');
|
||||
|
||||
expect($result)->toHaveKey('command');
|
||||
expect($result)->toHaveKey('arguments');
|
||||
expect($result['command'])->toBe('demo:hello');
|
||||
expect($result['arguments'])->toBeEmpty();
|
||||
});
|
||||
|
||||
it('parses command with arguments', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('parseInput');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->dialog, 'demo:hello arg1 arg2 arg3');
|
||||
|
||||
expect($result['command'])->toBe('demo:hello');
|
||||
expect($result['arguments'])->toBe(['arg1', 'arg2', 'arg3']);
|
||||
});
|
||||
|
||||
it('parses command with quoted arguments', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('parseInput');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->dialog, 'command "arg with spaces"');
|
||||
|
||||
expect($result['command'])->toBe('command');
|
||||
expect($result['arguments'])->toHaveCount(1);
|
||||
expect($result['arguments'][0])->toBe('arg with spaces');
|
||||
});
|
||||
|
||||
it('parses command with single-quoted arguments', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('parseInput');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->dialog, "command 'arg with spaces'");
|
||||
|
||||
expect($result['command'])->toBe('command');
|
||||
expect($result['arguments'])->toHaveCount(1);
|
||||
expect($result['arguments'][0])->toBe('arg with spaces');
|
||||
});
|
||||
|
||||
it('parses empty input', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('parseInput');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->dialog, '');
|
||||
|
||||
expect($result['command'])->toBe('');
|
||||
expect($result['arguments'])->toBeEmpty();
|
||||
});
|
||||
|
||||
it('handles multiple spaces between arguments', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('parseInput');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->dialog, 'command arg1 arg2');
|
||||
|
||||
expect($result['command'])->toBe('command');
|
||||
expect($result['arguments'])->toBe(['arg1', 'arg2']);
|
||||
});
|
||||
|
||||
it('handles escaped quotes in quoted strings', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('parseInput');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->dialog, 'command "arg with \\"quotes\\""');
|
||||
|
||||
expect($result['command'])->toBe('command');
|
||||
expect($result['arguments'])->toHaveCount(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ConsoleDialog Command Suggestions', function () {
|
||||
beforeEach(function () {
|
||||
$this->container = new DefaultContainer();
|
||||
$this->output = new TestConsoleOutput();
|
||||
$this->discoveryRegistry = new DiscoveryRegistry(
|
||||
attributes: new AttributeRegistry(),
|
||||
interfaces: new InterfaceRegistry([]),
|
||||
templates: new TemplateRegistry([])
|
||||
);
|
||||
$this->commandHistory = new CommandHistory();
|
||||
$this->groupRegistry = new CommandGroupRegistry($this->discoveryRegistry);
|
||||
$this->commandList = new CommandList(
|
||||
new ConsoleCommand('demo:hello', 'Hello command'),
|
||||
new ConsoleCommand('demo:colors', 'Colors command'),
|
||||
new ConsoleCommand('db:migrate', 'Migrate command')
|
||||
);
|
||||
$this->commandExecutor = new DialogCommandExecutor(
|
||||
$this->output,
|
||||
new \App\Framework\Console\CommandRegistry($this->container, $this->discoveryRegistry),
|
||||
$this->commandHistory,
|
||||
'test-console'
|
||||
);
|
||||
$this->dialog = new ConsoleDialog(
|
||||
$this->output,
|
||||
$this->discoveryRegistry,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->commandExecutor,
|
||||
$this->commandList,
|
||||
$this->container
|
||||
);
|
||||
});
|
||||
|
||||
it('gets command suggestions for partial match', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('getCommandSuggestions');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$suggestions = $method->invoke($this->dialog, 'demo');
|
||||
|
||||
expect($suggestions)->toBeArray();
|
||||
expect($suggestions)->toContain('demo:hello');
|
||||
expect($suggestions)->toContain('demo:colors');
|
||||
});
|
||||
|
||||
it('gets empty suggestions for no match', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('getCommandSuggestions');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$suggestions = $method->invoke($this->dialog, 'nonexistent');
|
||||
|
||||
expect($suggestions)->toBeArray();
|
||||
});
|
||||
|
||||
it('gets case-insensitive suggestions', function () {
|
||||
$reflection = new \ReflectionClass($this->dialog);
|
||||
$method = $reflection->getMethod('getCommandSuggestions');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$suggestions = $method->invoke($this->dialog, 'DEMO');
|
||||
|
||||
expect($suggestions)->toBeArray();
|
||||
});
|
||||
});
|
||||
|
||||
169
tests/Framework/Console/Components/ConsoleTUITest.php
Normal file
169
tests/Framework/Console/Components/ConsoleTUITest.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Console\Components;
|
||||
|
||||
use App\Framework\Console\CommandGroupRegistry;
|
||||
use App\Framework\Console\CommandHistory;
|
||||
use App\Framework\Console\Components\ConsoleTUI;
|
||||
use App\Framework\Console\Components\TuiCommandExecutor;
|
||||
use App\Framework\Console\Components\TuiRenderer;
|
||||
use App\Framework\Console\Components\TuiState;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\Console\SimpleWorkflowExecutor;
|
||||
use App\Framework\DI\DefaultContainer;
|
||||
use App\Framework\Discovery\Results\AttributeRegistry;
|
||||
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
use App\Framework\Discovery\Results\InterfaceRegistry;
|
||||
use App\Framework\Discovery\Results\TemplateRegistry;
|
||||
|
||||
describe('ConsoleTUI', function () {
|
||||
beforeEach(function () {
|
||||
$this->container = new DefaultContainer();
|
||||
$this->output = new ConsoleOutput();
|
||||
$this->discoveryRegistry = new DiscoveryRegistry(
|
||||
attributes: new AttributeRegistry(),
|
||||
interfaces: new InterfaceRegistry([]),
|
||||
templates: new TemplateRegistry([])
|
||||
);
|
||||
$this->state = new TuiState();
|
||||
$this->renderer = new TuiRenderer($this->output, $this->state);
|
||||
$this->commandExecutor = new TuiCommandExecutor(
|
||||
new \App\Framework\Console\CommandRegistry($this->container, $this->discoveryRegistry),
|
||||
$this->container,
|
||||
$this->discoveryRegistry,
|
||||
new CommandHistory(),
|
||||
new \App\Framework\Console\CommandValidator(),
|
||||
new \App\Framework\Console\CommandHelpGenerator(new \App\Framework\Console\ParameterInspector()),
|
||||
'test-console'
|
||||
);
|
||||
$this->commandHistory = new CommandHistory();
|
||||
$this->groupRegistry = new CommandGroupRegistry($this->discoveryRegistry);
|
||||
$this->workflowExecutor = new SimpleWorkflowExecutor($this->container, $this->discoveryRegistry);
|
||||
});
|
||||
|
||||
it('can be instantiated', function () {
|
||||
$tui = new ConsoleTUI(
|
||||
$this->output,
|
||||
$this->container,
|
||||
$this->discoveryRegistry,
|
||||
$this->state,
|
||||
$this->renderer,
|
||||
$this->commandExecutor,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->workflowExecutor
|
||||
);
|
||||
|
||||
expect($tui)->toBeInstanceOf(ConsoleTUI::class);
|
||||
});
|
||||
|
||||
it('has run method', function () {
|
||||
$tui = new ConsoleTUI(
|
||||
$this->output,
|
||||
$this->container,
|
||||
$this->discoveryRegistry,
|
||||
$this->state,
|
||||
$this->renderer,
|
||||
$this->commandExecutor,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->workflowExecutor
|
||||
);
|
||||
|
||||
expect(method_exists($tui, 'run'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has handleShutdownSignal method', function () {
|
||||
$tui = new ConsoleTUI(
|
||||
$this->output,
|
||||
$this->container,
|
||||
$this->discoveryRegistry,
|
||||
$this->state,
|
||||
$this->renderer,
|
||||
$this->commandExecutor,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->workflowExecutor
|
||||
);
|
||||
|
||||
expect(method_exists($tui, 'handleShutdownSignal'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has handleShutdownSignalLegacy method', function () {
|
||||
$tui = new ConsoleTUI(
|
||||
$this->output,
|
||||
$this->container,
|
||||
$this->discoveryRegistry,
|
||||
$this->state,
|
||||
$this->renderer,
|
||||
$this->commandExecutor,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->workflowExecutor
|
||||
);
|
||||
|
||||
expect(method_exists($tui, 'handleShutdownSignalLegacy'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('initializes with all required dependencies', function () {
|
||||
$tui = new ConsoleTUI(
|
||||
$this->output,
|
||||
$this->container,
|
||||
$this->discoveryRegistry,
|
||||
$this->state,
|
||||
$this->renderer,
|
||||
$this->commandExecutor,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->workflowExecutor
|
||||
);
|
||||
|
||||
expect($tui)->toBeInstanceOf(ConsoleTUI::class);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ConsoleTUI Terminal Compatibility', function () {
|
||||
beforeEach(function () {
|
||||
$this->container = new DefaultContainer();
|
||||
$this->output = new ConsoleOutput();
|
||||
$this->discoveryRegistry = new DiscoveryRegistry(
|
||||
attributes: new AttributeRegistry(),
|
||||
interfaces: new InterfaceRegistry([]),
|
||||
templates: new TemplateRegistry([])
|
||||
);
|
||||
$this->state = new TuiState();
|
||||
$this->renderer = new TuiRenderer($this->output, $this->state);
|
||||
$this->commandExecutor = new TuiCommandExecutor(
|
||||
new \App\Framework\Console\CommandRegistry($this->container, $this->discoveryRegistry),
|
||||
$this->container,
|
||||
$this->discoveryRegistry,
|
||||
new CommandHistory(),
|
||||
new \App\Framework\Console\CommandValidator(),
|
||||
new \App\Framework\Console\CommandHelpGenerator(new \App\Framework\Console\ParameterInspector()),
|
||||
'test-console'
|
||||
);
|
||||
$this->commandHistory = new CommandHistory();
|
||||
$this->groupRegistry = new CommandGroupRegistry($this->discoveryRegistry);
|
||||
$this->workflowExecutor = new SimpleWorkflowExecutor($this->container, $this->discoveryRegistry);
|
||||
});
|
||||
|
||||
it('handles terminal compatibility check', function () {
|
||||
$tui = new ConsoleTUI(
|
||||
$this->output,
|
||||
$this->container,
|
||||
$this->discoveryRegistry,
|
||||
$this->state,
|
||||
$this->renderer,
|
||||
$this->commandExecutor,
|
||||
$this->commandHistory,
|
||||
$this->groupRegistry,
|
||||
$this->workflowExecutor
|
||||
);
|
||||
|
||||
// TUI should handle terminal compatibility internally
|
||||
expect($tui)->toBeInstanceOf(ConsoleTUI::class);
|
||||
});
|
||||
});
|
||||
|
||||
158
tests/Framework/Console/Components/InteractiveMenuTest.php
Normal file
158
tests/Framework/Console/Components/InteractiveMenuTest.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user