@@ -474,6 +474,10 @@ public function execute(): int
474474
475475## Testing Your Commands
476476
477+ The CLI component provides comprehensive testing support, including the ability to test commands that require user input.
478+
479+ ### Testing Commands Without User Input
480+
477481``` php
478482use PHPUnit\Framework\TestCase;
479483use Neuron\Cli\Console\Input;
@@ -484,23 +488,155 @@ class MakeControllerCommandTest extends TestCase
484488 public function testExecute(): void
485489 {
486490 $command = new MakeControllerCommand();
487-
491+
488492 // Mock input
489493 $input = new Input(['UserController', '--resource']);
490494 $output = new Output(false); // No colors for testing
491-
495+
492496 $command->setInput($input);
493497 $command->setOutput($output);
494498 $command->configure();
495499 $input->parse($command);
496-
500+
497501 $exitCode = $command->execute();
498-
502+
499503 $this->assertEquals(0, $exitCode);
500504 }
501505}
502506```
503507
508+ ### Testing Commands With User Input
509+
510+ Commands that use ` prompt() ` , ` confirm() ` , ` secret() ` , or ` choice() ` can be tested using the ` TestInputReader ` :
511+
512+ ``` php
513+ use PHPUnit\Framework\TestCase;
514+ use Neuron\Cli\Console\Input;
515+ use Neuron\Cli\Console\Output;
516+ use Neuron\Cli\IO\TestInputReader;
517+
518+ class SetupCommandTest extends TestCase
519+ {
520+ public function testInteractiveSetup(): void
521+ {
522+ $command = new SetupCommand();
523+
524+ // Create test input reader with pre-programmed responses
525+ $inputReader = new TestInputReader();
526+ $inputReader->addResponse('my-project'); // Project name
527+ $inputReader->addResponse('John Doe'); // Author name
528+ $inputReader->addResponse('john@example.com'); // Email
529+ $inputReader->addResponse('yes'); // Confirmation
530+
531+ // Configure command
532+ $input = new Input([]);
533+ $output = new Output(false);
534+
535+ $command->setInput($input);
536+ $command->setOutput($output);
537+ $command->setInputReader($inputReader);
538+
539+ // Execute command
540+ $exitCode = $command->execute();
541+
542+ // Assertions
543+ $this->assertEquals(0, $exitCode);
544+
545+ // Verify the prompts that were shown
546+ $prompts = $inputReader->getPromptHistory();
547+ $this->assertCount(4, $prompts);
548+ $this->assertStringContainsString('Project name', $prompts[0]);
549+ $this->assertStringContainsString('Author name', $prompts[1]);
550+ }
551+
552+ public function testUserCancelsSetup(): void
553+ {
554+ $command = new SetupCommand();
555+
556+ // User will cancel the setup
557+ $inputReader = new TestInputReader();
558+ $inputReader->addResponses([
559+ 'test-project',
560+ 'Test User',
561+ 'test@example.com',
562+ 'no' // Cancel confirmation
563+ ]);
564+
565+ $input = new Input([]);
566+ $output = new Output(false);
567+
568+ $command->setInput($input);
569+ $command->setOutput($output);
570+ $command->setInputReader($inputReader);
571+
572+ $exitCode = $command->execute();
573+
574+ // Should return non-zero exit code when cancelled
575+ $this->assertNotEquals(0, $exitCode);
576+ }
577+ }
578+ ```
579+
580+ ### Using Input Reader in Commands
581+
582+ To make your commands testable, use the convenience methods provided by the ` Command ` base class:
583+
584+ ``` php
585+ class SetupCommand extends Command
586+ {
587+ public function execute(): int
588+ {
589+ // Use built-in convenience methods instead of reading STDIN directly
590+ $name = $this->prompt('Enter project name: ');
591+
592+ if ($this->confirm('Enable caching?', true)) {
593+ // User confirmed
594+ }
595+
596+ $password = $this->secret('Enter password: ');
597+
598+ $env = $this->choice(
599+ 'Select environment:',
600+ ['development', 'staging', 'production'],
601+ 'development'
602+ );
603+
604+ return 0;
605+ }
606+ }
607+ ```
608+
609+ These convenience methods automatically use the injected ` IInputReader ` , making your commands fully testable without requiring actual user input.
610+
611+ ### TestInputReader Features
612+
613+ The ` TestInputReader ` class provides:
614+
615+ - ** Response Queue** : Pre-program multiple responses with ` addResponse() ` or ` addResponses() `
616+ - ** Prompt History** : Track all prompts shown with ` getPromptHistory() `
617+ - ** Automatic Validation** : Throws exceptions if responses run out, helping catch test bugs
618+ - ** Fluent Interface** : Chain ` addResponse() ` calls for cleaner test setup
619+ - ** Full Interface Support** : Implements all ` IInputReader ` methods (prompt, confirm, secret, choice)
620+
621+ ``` php
622+ $reader = new TestInputReader();
623+ $reader
624+ ->addResponse('value1')
625+ ->addResponse('value2')
626+ ->addResponse('yes');
627+
628+ // Check if there are responses remaining
629+ if ($reader->hasMoreResponses()) {
630+ $count = $reader->getRemainingResponseCount();
631+ }
632+
633+ // Get history of prompts
634+ $prompts = $reader->getPromptHistory();
635+
636+ // Reset for reuse
637+ $reader->reset();
638+ ```
639+
504640## Contributing
505641
506642When adding new features to the CLI component:
0 commit comments