From 6a909a1f0cfdf674c9804aef0fb8e98b2c8b5cb8 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Thu, 21 Mar 2024 15:39:36 +0000 Subject: [PATCH 1/3] Allows to test for no output console output --- .../Testing/Concerns/InteractsWithConsole.php | 7 ++ src/Illuminate/Testing/PendingCommand.php | 32 ++++- .../Testing/ArtisanCommandTest.php | 117 ++++++++++++++++++ 3 files changed, 152 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index c5d4e1aae60c..5beb3235612c 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -15,6 +15,13 @@ trait InteractsWithConsole */ public $mockConsoleOutput = true; + /** + * Indicates if the command is expected to output anything or not. + * + * @var bool|null + */ + public $expectsOutput; + /** * All of the expected output lines. * diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index d2f75737e510..bf6a3edd5ad2 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -132,11 +132,17 @@ public function expectsChoice($question, $answer, $answers, $strict = false) /** * Specify output that should be printed when the command runs. * - * @param string $output + * @param string|null $output * @return $this */ - public function expectsOutput($output) + public function expectsOutput($output = null) { + if ($output === null) { + $this->test->expectsOutput = true; + + return $this; + } + $this->test->expectedOutput[] = $output; return $this; @@ -145,11 +151,17 @@ public function expectsOutput($output) /** * Specify output that should never be printed when the command runs. * - * @param string $output + * @param string|null $output * @return $this */ - public function doesntExpectOutput($output) + public function doesntExpectOutput($output = null) { + if ($output === null) { + $this->test->expectsOutput = false; + + return $this; + } + $this->test->unexpectedOutput[$output] = false; return $this; @@ -410,6 +422,18 @@ private function createABufferedOutputMock() ->shouldAllowMockingProtectedMethods() ->shouldIgnoreMissing(); + if ($this->test->expectsOutput === false) { + $mock->shouldReceive('doWrite')->never(); + + return $mock; + } + + if ($this->test->expectsOutput === true + && count($this->test->expectedOutput) === 0 + && count($this->test->expectedOutputSubstrings) === 0) { + $mock->shouldReceive('doWrite')->atLeast()->once(); + } + foreach ($this->test->expectedOutput as $i => $output) { $mock->shouldReceive('doWrite') ->once() diff --git a/tests/Integration/Testing/ArtisanCommandTest.php b/tests/Integration/Testing/ArtisanCommandTest.php index 1592d63dfea8..ab2286652e15 100644 --- a/tests/Integration/Testing/ArtisanCommandTest.php +++ b/tests/Integration/Testing/ArtisanCommandTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Testing; +use Illuminate\Console\Command; use Illuminate\Support\Facades\Artisan; use Mockery as m; use Mockery\Exception\InvalidCountException; @@ -33,6 +34,22 @@ protected function setUp(): void $this->line($this->ask('Huh?')); }); + Artisan::command('interactions', function () { + /** @var Command $this */ + $this->ask('What is your name?'); + $this->choice('Which language do you prefer?', [ + 'PHP', + 'PHP', + 'PHP', + ]); + + $this->table(['Name', 'Email'], [ + ['Taylor Otwell', 'taylor@laravel.com',] + ]); + + $this->confirm('Do you want to continue?', true); + }); + Artisan::command('exit {code}', fn () => (int) $this->argument('code')); Artisan::command('contains', function () { @@ -146,6 +163,106 @@ public function test_console_command_that_passes_if_the_output_contains() ->assertExitCode(0); } + public function test_console_command_that_passes_if_outputs_something() + { + $this->artisan('contains') + ->expectsOutput() + ->assertExitCode(0); + } + + public function test_console_command_that_passes_if_outputs_is_something_and_is_the_expected_output() + { + $this->artisan('contains') + ->expectsOutput() + ->expectsOutput('My name is Taylor Otwell') + ->assertExitCode(0); + } + + public function test_console_command_that_fail_if_doesnt_output_something() + { + $this->expectException(InvalidCountException::class); + + $this->artisan('exit', ['code' => 0]) + ->expectsOutput() + ->assertExitCode(0); + + m::close(); + } + + public function test_console_command_that_fail_if_doesnt_output_something_and_is_not_the_expected_output() + { + $this->expectException(AssertionFailedError::class); + + $this->ignoringMockOnceExceptions(function () { + $this->artisan('exit', ['code' => 0]) + ->expectsOutput() + ->expectsOutput('My name is Taylor Otwell') + ->assertExitCode(0); + }); + } + + public function test_console_command_that_passes_if_does_not_output_anything() + { + $this->artisan('exit', ['code' => 0]) + ->doesntExpectOutput() + ->assertExitCode(0); + } + + public function test_console_command_that_passes_if_does_not_output_anything_and_is_not_the_expected_output() + { + $this->artisan('exit', ['code' => 0]) + ->doesntExpectOutput() + ->doesntExpectOutput('My name is Taylor Otwell') + ->assertExitCode(0); + } + + public function test_console_command_that_passes_if_expects_output_and_there_is_interactions() + { + $this->artisan('interactions', ['--no-interaction' => true]) + ->expectsOutput() + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsChoice('Which language do you prefer?', 'PHP', ['PHP', 'PHP', 'PHP']) + ->expectsConfirmation('Do you want to continue?', true) + ->assertExitCode(0); + } + + public function test_console_command_that_fails_if_doesnt_expect_output_but__there_is_interactions() + { + $this->expectException(InvalidCountException::class); + + $this->artisan('interactions', ['--no-interaction' => true]) + ->doesntExpectOutput() + ->expectsQuestion('What is your name?', 'Taylor Otwell') + ->expectsChoice('Which language do you prefer?', 'PHP', ['PHP', 'PHP', 'PHP']) + ->expectsConfirmation('Do you want to continue?', true) + ->assertExitCode(0); + + m::close(); + } + + public function test_console_command_that_fails_if_doesnt_expect_output_but_outputs_something() + { + $this->expectException(InvalidCountException::class); + + $this->artisan('contains') + ->doesntExpectOutput() + ->assertExitCode(0); + + m::close(); + } + + public function test_console_command_that_fails_if_doesnt_expect_output_and_does_expect_output() + { + $this->expectException(InvalidCountException::class); + + $this->artisan('contains') + ->doesntExpectOutput() + ->doesntExpectOutput('My name is Taylor Otwell') + ->assertExitCode(0); + + m::close(); + } + public function test_console_command_that_fails_if_the_output_does_not_contain() { $this->expectException(AssertionFailedError::class); From 72392e2699af8c2658fb93bf4bd5028e1a0d6264 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Thu, 21 Mar 2024 15:40:14 +0000 Subject: [PATCH 2/3] Apply fixes from StyleCI --- tests/Integration/Testing/ArtisanCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Testing/ArtisanCommandTest.php b/tests/Integration/Testing/ArtisanCommandTest.php index ab2286652e15..08cd327e0582 100644 --- a/tests/Integration/Testing/ArtisanCommandTest.php +++ b/tests/Integration/Testing/ArtisanCommandTest.php @@ -44,7 +44,7 @@ protected function setUp(): void ]); $this->table(['Name', 'Email'], [ - ['Taylor Otwell', 'taylor@laravel.com',] + ['Taylor Otwell', 'taylor@laravel.com'], ]); $this->confirm('Do you want to continue?', true); From 619ffeb66690cd33b3e57dd49ffb204c62cb0eeb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 27 Mar 2024 14:55:19 -0500 Subject: [PATCH 3/3] Update InteractsWithConsole.php --- .../Foundation/Testing/Concerns/InteractsWithConsole.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index 5beb3235612c..9c5060b3db54 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -16,7 +16,7 @@ trait InteractsWithConsole public $mockConsoleOutput = true; /** - * Indicates if the command is expected to output anything or not. + * Indicates if the command is expected to output anything. * * @var bool|null */