Created
March 27, 2020 16:48
-
-
Save nuernbergerA/f2a45317ea32d714ea1413625ba0d1ff to your computer and use it in GitHub Desktop.
expectsQuestionWithAutocomplete
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$this->artisan('make:factory-reloaded') | |
->expectsQuestionWithAutocomplete('Please pick a model', | |
'<href=file://'.__DIR__.'/Models/Group.php>Christophrumpel\LaravelFactoriesReloaded\Tests\Models\Group</>', | |
[ | |
'All', | |
'<href=file://'.__DIR__.'/Models/Recipe.php>Christophrumpel\LaravelFactoriesReloaded\Tests\Models\Recipe</>', | |
'<href=file://'.__DIR__.'/Models/Group.php>Christophrumpel\LaravelFactoriesReloaded\Tests\Models\Group</>', | |
'<href=file://'.__DIR__.'/Models/Ingredient.php>Christophrumpel\LaravelFactoriesReloaded\Tests\Models\Ingredient</>', | |
] | |
) | |
->assertExitCode(0); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Illuminate\Foundation\Testing\Concerns; | |
use Illuminate\Console\OutputStyle; | |
use Illuminate\Contracts\Console\Kernel; | |
use Illuminate\Support\Arr; | |
use Illuminate\Testing\PendingCommand; | |
trait InteractsWithConsole | |
{ | |
/** | |
* Indicates if the console output should be mocked. | |
* | |
* @var bool | |
*/ | |
public $mockConsoleOutput = true; | |
/** | |
* All of the expected output lines. | |
* | |
* @var array | |
*/ | |
public $expectedOutput = []; | |
/** | |
* All of the expected questions. | |
* | |
* @var array | |
*/ | |
public $expectedQuestions = []; | |
/** | |
* All of the expected Answers. | |
* | |
* @var array | |
*/ | |
public $expectedAutocomplete = []; | |
/** | |
* Call artisan command and return code. | |
* | |
* @param string $command | |
* @param array $parameters | |
* @return \Illuminate\Testing\PendingCommand|int | |
*/ | |
public function artisan($command, $parameters = []) | |
{ | |
if (! $this->mockConsoleOutput) { | |
return $this->app[Kernel::class]->call($command, $parameters); | |
} | |
$this->beforeApplicationDestroyed(function () { | |
if (count($this->expectedQuestions)) { | |
$this->fail('Question "'.Arr::first($this->expectedQuestions)[0].'" was not asked.'); | |
} | |
if (count($this->expectedAutocomplete)) { | |
foreach($this->expectedAutocomplete as $question => $values) | |
{ | |
$this->assertEqualsCanonicalizing($values['expected'], $values['actual'], 'Question "'.$question.'" has different options.'); | |
} | |
} | |
if (count($this->expectedOutput)) { | |
$this->fail('Output "'.Arr::first($this->expectedOutput).'" was not printed.'); | |
} | |
}); | |
return new PendingCommand($this, $this->app, $command, $parameters); | |
} | |
/** | |
* Disable mocking the console output. | |
* | |
* @return $this | |
*/ | |
protected function withoutMockingConsoleOutput() | |
{ | |
$this->mockConsoleOutput = false; | |
$this->app->offsetUnset(OutputStyle::class); | |
return $this; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Illuminate\Testing; | |
use Illuminate\Console\OutputStyle; | |
use Illuminate\Contracts\Console\Kernel; | |
use Illuminate\Contracts\Container\Container; | |
use Mockery; | |
use Mockery\Exception\NoMatchingExpectationException; | |
use PHPUnit\Framework\TestCase as PHPUnitTestCase; | |
use Symfony\Component\Console\Input\ArrayInput; | |
use Symfony\Component\Console\Output\BufferedOutput; | |
class PendingCommand | |
{ | |
/** | |
* The test being run. | |
* | |
* @var \Illuminate\Foundation\Testing\TestCase | |
*/ | |
public $test; | |
/** | |
* The application instance. | |
* | |
* @var \Illuminate\Contracts\Container\Container | |
*/ | |
protected $app; | |
/** | |
* The command to run. | |
* | |
* @var string | |
*/ | |
protected $command; | |
/** | |
* The parameters to pass to the command. | |
* | |
* @var array | |
*/ | |
protected $parameters; | |
/** | |
* The expected exit code. | |
* | |
* @var int | |
*/ | |
protected $expectedExitCode; | |
/** | |
* Determine if command has executed. | |
* | |
* @var bool | |
*/ | |
protected $hasExecuted = false; | |
/** | |
* Create a new pending console command run. | |
* | |
* @param \PHPUnit\Framework\TestCase $test | |
* @param \Illuminate\Contracts\Container\Container $app | |
* @param string $command | |
* @param array $parameters | |
* @return void | |
*/ | |
public function __construct(PHPUnitTestCase $test, Container $app, $command, $parameters) | |
{ | |
$this->app = $app; | |
$this->test = $test; | |
$this->command = $command; | |
$this->parameters = $parameters; | |
} | |
/** | |
* Specify an expected question that will be asked when the command runs. | |
* | |
* @param string $question | |
* @param string|bool $answer | |
* @return $this | |
*/ | |
public function expectsQuestion($question, $answer) | |
{ | |
$this->test->expectedQuestions[] = [$question, $answer]; | |
return $this; | |
} | |
/** | |
* Specify an expected confirmation question that will be asked when the command runs. | |
* | |
* @param string $question | |
* @param string $answer | |
* @param string[] $answers | |
* @return $this | |
*/ | |
public function expectsQuestionWithAutocomplete($question, $answer, $answers) | |
{ | |
$this->test->expectedAutocomplete[$question]['expected'] = $answers; | |
return $this->expectsQuestion($question, $answer); | |
} | |
/** | |
* Specify an expected confirmation question that will be asked when the command runs. | |
* | |
* @param string $question | |
* @param string $answer | |
* @return $this | |
*/ | |
public function expectsConfirmation($question, $answer = 'no') | |
{ | |
return $this->expectsQuestion($question, strtolower($answer) === 'yes'); | |
} | |
/** | |
* Specify output that should be printed when the command runs. | |
* | |
* @param string $output | |
* @return $this | |
*/ | |
public function expectsOutput($output) | |
{ | |
$this->test->expectedOutput[] = $output; | |
return $this; | |
} | |
/** | |
* Assert that the command has the given exit code. | |
* | |
* @param int $exitCode | |
* @return $this | |
*/ | |
public function assertExitCode($exitCode) | |
{ | |
$this->expectedExitCode = $exitCode; | |
return $this; | |
} | |
/** | |
* Execute the command. | |
* | |
* @return int | |
*/ | |
public function execute() | |
{ | |
return $this->run(); | |
} | |
/** | |
* Execute the command. | |
* | |
* @return int | |
*/ | |
public function run() | |
{ | |
$this->hasExecuted = true; | |
$this->mockConsoleOutput(); | |
try { | |
$exitCode = $this->app->make(Kernel::class)->call($this->command, $this->parameters); | |
} catch (NoMatchingExpectationException $e) { | |
if ($e->getMethodName() === 'askQuestion') { | |
$this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked.'); | |
} | |
throw $e; | |
} | |
if ($this->expectedExitCode !== null) { | |
$this->test->assertEquals( | |
$this->expectedExitCode, $exitCode, | |
"Expected status code {$this->expectedExitCode} but received {$exitCode}." | |
); | |
} | |
return $exitCode; | |
} | |
/** | |
* Mock the application's console output. | |
* | |
* @return void | |
*/ | |
protected function mockConsoleOutput() | |
{ | |
$mock = Mockery::mock(OutputStyle::class.'[askQuestion]', [ | |
(new ArrayInput($this->parameters)), $this->createABufferedOutputMock(), | |
]); | |
foreach ($this->test->expectedQuestions as $i => $question) { | |
$mock->shouldReceive('askQuestion') | |
->once() | |
->ordered() | |
->with(Mockery::on(function ($argument) use ($question) { | |
if (isset($this->test->expectedAutocomplete[$question[0]])) { | |
$this->test->expectedAutocomplete[$question[0]]['actual'] = $argument->getAutocompleterValues(); | |
} | |
return $argument->getQuestion() == $question[0]; | |
})) | |
->andReturnUsing(function () use ($question, $i) { | |
unset($this->test->expectedQuestions[$i]); | |
return $question[1]; | |
}); | |
} | |
$this->app->bind(OutputStyle::class, function () use ($mock) { | |
return $mock; | |
}); | |
} | |
/** | |
* Create a mock for the buffered output. | |
* | |
* @return \Mockery\MockInterface | |
*/ | |
private function createABufferedOutputMock() | |
{ | |
$mock = Mockery::mock(BufferedOutput::class.'[doWrite]') | |
->shouldAllowMockingProtectedMethods() | |
->shouldIgnoreMissing(); | |
foreach ($this->test->expectedOutput as $i => $output) { | |
$mock->shouldReceive('doWrite') | |
->once() | |
->ordered() | |
->with($output, Mockery::any()) | |
->andReturnUsing(function () use ($i) { | |
unset($this->test->expectedOutput[$i]); | |
}); | |
} | |
return $mock; | |
} | |
/** | |
* Handle the object's destruction. | |
* | |
* @return void | |
*/ | |
public function __destruct() | |
{ | |
if ($this->hasExecuted) { | |
return; | |
} | |
$this->run(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment