diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index 607cfaa07dbd..5ecef1b8679d 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -8,6 +8,7 @@ use Symfony\Component\Console\Command\Command as SymfonyCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Throwable; @@ -172,7 +173,15 @@ public function run(InputInterface $input, OutputInterface $output): int OutputStyle::class, ['input' => $input, 'output' => $output] ); - $this->components = $this->laravel->make(Factory::class, ['output' => $this->output]); + $componentsOutput = $this->output; + + if ($output instanceof ConsoleOutputInterface) { + $componentsOutput = $this->laravel->make( + OutputStyle::class, ['input' => $input, 'output' => $output->getErrorOutput()] + ); + } + + $this->components = $this->laravel->make(Factory::class, ['output' => $componentsOutput]); $this->configurePrompts($input); diff --git a/src/Illuminate/Console/Concerns/ConfiguresPrompts.php b/src/Illuminate/Console/Concerns/ConfiguresPrompts.php index d49e27273ecd..09ad5acba092 100644 --- a/src/Illuminate/Console/Concerns/ConfiguresPrompts.php +++ b/src/Illuminate/Console/Concerns/ConfiguresPrompts.php @@ -29,11 +29,11 @@ protected function configurePrompts(InputInterface $input) { Prompt::setOutput($this->output); - Prompt::interactive(($input->isInteractive() && defined('STDIN') && stream_isatty(STDIN)) || $this->laravel->runningUnitTests()); + Prompt::interactive(($input->isInteractive() && defined('STDIN') && stream_isatty(STDIN)) || (method_exists($this->laravel, 'runningUnitTests') && $this->laravel->runningUnitTests())); Prompt::validateUsing(fn (Prompt $prompt) => $this->validatePrompt($prompt->value(), $prompt->validate)); - Prompt::fallbackWhen(windows_os() || $this->laravel->runningUnitTests()); + Prompt::fallbackWhen(windows_os() || (method_exists($this->laravel, 'runningUnitTests') && $this->laravel->runningUnitTests())); TextPrompt::fallbackUsing(fn (TextPrompt $prompt) => $this->promptUntilValid( fn () => $this->components->ask($prompt->label, $prompt->default ?: null) ?? '', diff --git a/tests/Console/CommandTest.php b/tests/Console/CommandTest.php index 44abadbf3073..28c80c4d2802 100644 --- a/tests/Console/CommandTest.php +++ b/tests/Console/CommandTest.php @@ -12,6 +12,7 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Question\ChoiceQuestion; @@ -215,4 +216,118 @@ public function testChoiceWithMultiselect() $command->choice('Select all that apply.', ['option-1', 'option-2', 'option-3'], null, null, true); } + + public function testConsoleComponentsUseErrorOutputWhenConsoleOutputInterfaceIsAvailable() + { + $command = new class extends Command + { + public function handle() + { + $this->components->task('Test task', fn () => true); + } + }; + + $application = m::mock(Application::class); + $command->setLaravel($application); + + $input = new ArrayInput([]); + $output = new ConsoleOutput; + + $mainOutputStyle = m::mock(OutputStyle::class); + $application->shouldReceive('make') + ->with(OutputStyle::class, ['input' => $input, 'output' => $output]) + ->andReturn($mainOutputStyle); + + $errorOutputStyle = m::mock(OutputStyle::class); + $application->shouldReceive('make') + ->with(OutputStyle::class, ['input' => $input, 'output' => $output->getErrorOutput()]) + ->andReturn($errorOutputStyle); + + $factory = m::mock(Factory::class); + $application->shouldReceive('make') + ->with(Factory::class, ['output' => $errorOutputStyle]) + ->andReturn($factory); + + $factory->shouldReceive('task') + ->with('Test task', m::type('callable')) + ->once(); + + $application->shouldReceive('call')->with([$command, 'handle'])->andReturnUsing(function () use ($command) { + $command->handle(); + }); + $application->shouldReceive('runningUnitTests')->andReturn(true); + + $command->run($input, $output); + } + + public function testConsoleComponentsUseMainOutputWhenConsoleOutputInterfaceIsNotAvailable() + { + $command = new class extends Command + { + public function handle() + { + $this->components->task('Test task', fn () => true); + } + }; + + $application = m::mock(Application::class); + $command->setLaravel($application); + + $input = new ArrayInput([]); + $output = new NullOutput; + + $mainOutputStyle = m::mock(OutputStyle::class); + $application->shouldReceive('make') + ->with(OutputStyle::class, ['input' => $input, 'output' => $output]) + ->andReturn($mainOutputStyle); + + $factory = m::mock(Factory::class); + $application->shouldReceive('make') + ->with(Factory::class, ['output' => $mainOutputStyle]) + ->andReturn($factory); + + $factory->shouldReceive('task') + ->with('Test task', m::type('callable')) + ->once(); + + $application->shouldReceive('call')->with([$command, 'handle'])->andReturnUsing(function () use ($command) { + $command->handle(); + }); + $application->shouldReceive('runningUnitTests')->andReturn(true); + + $command->run($input, $output); + } + + public function testConsoleComponentsUseMainOutputWhenOutputIsAlreadyOutputStyle() + { + $command = new class extends Command + { + public function handle() + { + $this->components->task('Test task', fn () => true); + } + }; + + $application = m::mock(Application::class); + $command->setLaravel($application); + + $input = new ArrayInput([]); + $existingOutputStyle = m::mock(OutputStyle::class); + + $factory = m::mock(Factory::class); + $application->shouldReceive('make') + ->with(Factory::class, ['output' => $existingOutputStyle]) + ->andReturn($factory); + + $factory->shouldReceive('task') + ->with('Test task', m::type('callable')) + ->once(); + + $application->shouldReceive('call')->with([$command, 'handle'])->andReturnUsing(function () use ($command) { + $command->handle(); + }); + $application->shouldReceive('runningUnitTests')->andReturn(true); + + $command->run($input, $existingOutputStyle); + } }