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:
149
tests/Framework/Console/Helpers/TestConsoleOutput.php
Normal file
149
tests/Framework/Console/Helpers/TestConsoleOutput.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Console\Helpers;
|
||||
|
||||
use App\Framework\Console\ConsoleColor;
|
||||
use App\Framework\Console\ConsoleOutputInterface;
|
||||
use App\Framework\Console\ConsoleStyle;
|
||||
|
||||
/**
|
||||
* Enhanced test console output that captures all output for assertions
|
||||
*/
|
||||
final class TestConsoleOutput implements ConsoleOutputInterface
|
||||
{
|
||||
public array $capturedLines = [];
|
||||
|
||||
public array $capturedWrites = [];
|
||||
|
||||
public array $capturedErrors = [];
|
||||
|
||||
public array $capturedSuccesses = [];
|
||||
|
||||
public array $capturedWarnings = [];
|
||||
|
||||
public array $capturedInfos = [];
|
||||
|
||||
public int $newLineCount = 0;
|
||||
|
||||
public array $windowTitles = [];
|
||||
|
||||
public function write(string $message, ConsoleStyle|ConsoleColor|null $style = null): void
|
||||
{
|
||||
$this->capturedWrites[] = ['message' => $message, 'style' => $style];
|
||||
}
|
||||
|
||||
public function writeLine(string $message = '', ?ConsoleColor $color = null): void
|
||||
{
|
||||
$this->capturedLines[] = ['message' => $message, 'color' => $color];
|
||||
}
|
||||
|
||||
public function writeError(string $message): void
|
||||
{
|
||||
$this->capturedErrors[] = $message;
|
||||
$this->capturedLines[] = ['message' => $message, 'type' => 'error'];
|
||||
}
|
||||
|
||||
public function writeSuccess(string $message): void
|
||||
{
|
||||
$this->capturedSuccesses[] = $message;
|
||||
$this->capturedLines[] = ['message' => $message, 'type' => 'success'];
|
||||
}
|
||||
|
||||
public function writeWarning(string $message): void
|
||||
{
|
||||
$this->capturedWarnings[] = $message;
|
||||
$this->capturedLines[] = ['message' => $message, 'type' => 'warning'];
|
||||
}
|
||||
|
||||
public function writeInfo(string $message): void
|
||||
{
|
||||
$this->capturedInfos[] = $message;
|
||||
$this->capturedLines[] = ['message' => $message, 'type' => 'info'];
|
||||
}
|
||||
|
||||
public function newLine(int $count = 1): void
|
||||
{
|
||||
$this->newLineCount += $count;
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$this->capturedLines[] = ['message' => '', 'type' => 'newline'];
|
||||
}
|
||||
}
|
||||
|
||||
public function askQuestion(string $question, ?string $default = null): string
|
||||
{
|
||||
$this->capturedLines[] = ['message' => $question, 'type' => 'question', 'default' => $default];
|
||||
return $default ?? '';
|
||||
}
|
||||
|
||||
public function confirm(string $question, bool $default = false): bool
|
||||
{
|
||||
$this->capturedLines[] = ['message' => $question, 'type' => 'confirm', 'default' => $default];
|
||||
return $default;
|
||||
}
|
||||
|
||||
public function writeWindowTitle(string $title, int $mode = 0): void
|
||||
{
|
||||
$this->windowTitles[] = ['title' => $title, 'mode' => $mode];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all captured output as plain text
|
||||
*/
|
||||
public function getOutput(): string
|
||||
{
|
||||
$output = [];
|
||||
foreach ($this->capturedLines as $line) {
|
||||
$output[] = $line['message'] ?? '';
|
||||
}
|
||||
|
||||
return implode("\n", $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all captured writes
|
||||
*/
|
||||
public function getWrites(): array
|
||||
{
|
||||
return $this->capturedWrites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all captured output
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$this->capturedLines = [];
|
||||
$this->capturedWrites = [];
|
||||
$this->capturedErrors = [];
|
||||
$this->capturedSuccesses = [];
|
||||
$this->capturedWarnings = [];
|
||||
$this->capturedInfos = [];
|
||||
$this->newLineCount = 0;
|
||||
$this->windowTitles = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if output contains a specific string
|
||||
*/
|
||||
public function contains(string $search): bool
|
||||
{
|
||||
$output = $this->getOutput();
|
||||
return str_contains($output, $search);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last captured line
|
||||
*/
|
||||
public function getLastLine(): ?string
|
||||
{
|
||||
if (empty($this->capturedLines)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$last = end($this->capturedLines);
|
||||
return $last['message'] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user