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:
167
tests/Framework/Console/InteractivePrompterTest.php
Normal file
167
tests/Framework/Console/InteractivePrompterTest.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Console;
|
||||
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\Console\InteractivePrompter;
|
||||
use App\Framework\Console\TextWriter;
|
||||
use App\Framework\Console\ValueObjects\ChoiceOptions;
|
||||
use App\Framework\Console\ValueObjects\MenuOptions;
|
||||
use Tests\Framework\Console\Helpers\TestConsoleOutput;
|
||||
|
||||
describe('InteractivePrompter', function () {
|
||||
beforeEach(function () {
|
||||
$this->output = new TestConsoleOutput();
|
||||
$textWriter = new TextWriter(
|
||||
new \App\Framework\Console\Ansi\AnsiSequenceGenerator(),
|
||||
new \App\Framework\Console\Terminal\TerminalCapabilities()
|
||||
);
|
||||
$this->prompter = new InteractivePrompter($this->output, $textWriter);
|
||||
});
|
||||
|
||||
it('can be instantiated', function () {
|
||||
expect($this->prompter)->toBeInstanceOf(InteractivePrompter::class);
|
||||
});
|
||||
|
||||
it('has askQuestion method', function () {
|
||||
expect(method_exists($this->prompter, 'askQuestion'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has askPassword method', function () {
|
||||
expect(method_exists($this->prompter, 'askPassword'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has confirm method', function () {
|
||||
expect(method_exists($this->prompter, 'confirm'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has choice method', function () {
|
||||
expect(method_exists($this->prompter, 'choice'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has choiceFromOptions method', function () {
|
||||
expect(method_exists($this->prompter, 'choiceFromOptions'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has menu method', function () {
|
||||
expect(method_exists($this->prompter, 'menu'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has menuFromOptions method', function () {
|
||||
expect(method_exists($this->prompter, 'menuFromOptions'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has multiSelect method', function () {
|
||||
expect(method_exists($this->prompter, 'multiSelect'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('has multiSelectFromOptions method', function () {
|
||||
expect(method_exists($this->prompter, 'multiSelectFromOptions'))->toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe('InteractivePrompter Choice Methods', function () {
|
||||
beforeEach(function () {
|
||||
$this->output = new TestConsoleOutput();
|
||||
$textWriter = new TextWriter(
|
||||
new \App\Framework\Console\Ansi\AnsiSequenceGenerator(),
|
||||
new \App\Framework\Console\Terminal\TerminalCapabilities()
|
||||
);
|
||||
$this->prompter = new InteractivePrompter($this->output, $textWriter);
|
||||
});
|
||||
|
||||
it('delegates choice to choiceFromOptions', function () {
|
||||
$choices = ['option1' => 'Option 1', 'option2' => 'Option 2'];
|
||||
|
||||
// This will call InteractiveMenu which requires STDIN, so we just verify the method exists
|
||||
expect(method_exists($this->prompter, 'choice'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('delegates choiceFromOptions to InteractiveMenu', function () {
|
||||
$options = MenuOptions::create()
|
||||
->addOption('opt1', 'Option 1')
|
||||
->addOption('opt2', 'Option 2');
|
||||
|
||||
// This will call InteractiveMenu which requires STDIN
|
||||
// We verify the method exists and can be called
|
||||
expect(method_exists($this->prompter, 'choiceFromOptions'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('handles MenuOptions with separators', function () {
|
||||
$options = MenuOptions::create()
|
||||
->addOption('opt1', 'Option 1')
|
||||
->addSeparator()
|
||||
->addOption('opt2', 'Option 2');
|
||||
|
||||
// Verify structure
|
||||
expect($options->count())->toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('InteractivePrompter Menu Methods', function () {
|
||||
beforeEach(function () {
|
||||
$this->output = new TestConsoleOutput();
|
||||
$textWriter = new TextWriter(
|
||||
new \App\Framework\Console\Ansi\AnsiSequenceGenerator(),
|
||||
new \App\Framework\Console\Terminal\TerminalCapabilities()
|
||||
);
|
||||
$this->prompter = new InteractivePrompter($this->output, $textWriter);
|
||||
});
|
||||
|
||||
it('delegates menu to menuFromOptions', function () {
|
||||
$items = ['item1' => 'Item 1', 'item2' => 'Item 2'];
|
||||
|
||||
// This will call InteractiveMenu which requires STDIN
|
||||
expect(method_exists($this->prompter, 'menu'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('delegates menuFromOptions to InteractiveMenu', function () {
|
||||
$options = MenuOptions::create()
|
||||
->addOption('item1', 'Item 1')
|
||||
->addOption('item2', 'Item 2');
|
||||
|
||||
// This will call InteractiveMenu which requires STDIN
|
||||
expect(method_exists($this->prompter, 'menuFromOptions'))->toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe('InteractivePrompter MultiSelect Methods', function () {
|
||||
beforeEach(function () {
|
||||
$this->output = new TestConsoleOutput();
|
||||
$textWriter = new TextWriter(
|
||||
new \App\Framework\Console\Ansi\AnsiSequenceGenerator(),
|
||||
new \App\Framework\Console\Terminal\TerminalCapabilities()
|
||||
);
|
||||
$this->prompter = new InteractivePrompter($this->output, $textWriter);
|
||||
});
|
||||
|
||||
it('delegates multiSelect to multiSelectFromOptions', function () {
|
||||
$options = ['opt1' => 'Option 1', 'opt2' => 'Option 2'];
|
||||
|
||||
// This will require STDIN input
|
||||
expect(method_exists($this->prompter, 'multiSelect'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('delegates multiSelectFromOptions and returns ChoiceOptions', function () {
|
||||
$options = ChoiceOptions::create()
|
||||
->addChoice('val1', 'Value 1')
|
||||
->addChoice('val2', 'Value 2');
|
||||
|
||||
// This will require STDIN input
|
||||
expect(method_exists($this->prompter, 'multiSelectFromOptions'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('displays multiSelect options correctly', function () {
|
||||
$options = ChoiceOptions::create()
|
||||
->addChoice('val1', 'Value 1')
|
||||
->addChoice('val2', 'Value 2')
|
||||
->addChoice('val3', 'Value 3');
|
||||
|
||||
// Verify structure
|
||||
expect($options->count())->toBe(3);
|
||||
expect($options->toArray())->toHaveCount(3);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user