feat(console): migrate interactive console commands to Laravel Prompts
This commit is contained in:
parent
7f57f16425
commit
341b57c3bf
7 changed files with 175 additions and 160 deletions
|
|
@ -15,6 +15,9 @@ use Presentation\Console\Presenters\Clients\CreateClientView;
|
|||
use Shared\DDD\Usecase\Builder\UsecaseBuilder;
|
||||
use Shared\DDD\Usecase\Builder\UsecaseExecutor;
|
||||
|
||||
use function Laravel\Prompts\confirm;
|
||||
use function Laravel\Prompts\text;
|
||||
|
||||
final class CreateClientCommand extends Command
|
||||
{
|
||||
/**
|
||||
|
|
@ -39,10 +42,6 @@ final class CreateClientCommand extends Command
|
|||
): int {
|
||||
$clientName = $this->askForClientName();
|
||||
|
||||
if ($clientName === null) {
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (! $this->confirmCreation($clientName)) {
|
||||
$this->warn('Client creation cancelled.');
|
||||
|
||||
|
|
@ -65,41 +64,34 @@ final class CreateClientCommand extends Command
|
|||
return new Input($clientName);
|
||||
}
|
||||
|
||||
private function askForClientName(): ?ClientName
|
||||
private function askForClientName(): ClientName
|
||||
{
|
||||
$maxAttempts = 3;
|
||||
$rawName = text(
|
||||
label: 'Client name (e.g. "Ones Branding website")',
|
||||
placeholder: 'E.g. Ones Branding website',
|
||||
required: 'Client name cannot be empty.',
|
||||
validate: function (string $value): ?string {
|
||||
$trimmed = trim($value);
|
||||
|
||||
for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
|
||||
/** @var string|null $nameInput */
|
||||
$nameInput = $this->ask('Client name (e.g. "Ones Branding website")');
|
||||
$nameInput = $nameInput !== null ? trim($nameInput) : '';
|
||||
|
||||
if ($nameInput === '') {
|
||||
$this->error('Client name cannot be empty.');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$clientName = new ClientName($nameInput);
|
||||
|
||||
if ($this->clientRepository->existsByName($clientName)) {
|
||||
throw ClientNameAlreadyExistsException::forName($clientName->value);
|
||||
if ($trimmed === '') {
|
||||
return 'Client name cannot be empty.';
|
||||
}
|
||||
|
||||
return $clientName;
|
||||
} catch (\InvalidArgumentException | ClientNameAlreadyExistsException $e) {
|
||||
$this->error($e->getMessage());
|
||||
try {
|
||||
$clientName = new ClientName($trimmed);
|
||||
|
||||
if ($attempt < $maxAttempts) {
|
||||
$this->warn(sprintf('You have %d attempt(s) remaining.', $maxAttempts - $attempt));
|
||||
if ($this->clientRepository->existsByName($clientName)) {
|
||||
return ClientNameAlreadyExistsException::forName($trimmed)->getMessage();
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->error('Maximum number of attempts reached. Aborting.');
|
||||
return null;
|
||||
},
|
||||
);
|
||||
|
||||
return null;
|
||||
return new ClientName(trim($rawName));
|
||||
}
|
||||
|
||||
private function confirmCreation(ClientName $name): bool
|
||||
|
|
@ -116,7 +108,10 @@ final class CreateClientCommand extends Command
|
|||
],
|
||||
);
|
||||
|
||||
return $this->confirm('Create this API client?', false);
|
||||
return confirm(
|
||||
label: 'Create this API client?',
|
||||
default: false,
|
||||
);
|
||||
}
|
||||
|
||||
private function displayCredentials(CreateClientView $view): void
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Application\Security\Models\ValueObjects\ClientIdentifier;
|
|||
use Application\Security\Usecases\RegenerateClientSecret\Input;
|
||||
use Application\Security\Usecases\RegenerateClientSecret\RegenerateClientSecret;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\PromptsForMissingInput;
|
||||
use Presentation\Console\Presenters\Clients\RegenerateClientSecretPresenter;
|
||||
use Presentation\Console\Presenters\Clients\RegenerateClientSecretView;
|
||||
use Presentation\Console\Services\ClientConsoleResolver;
|
||||
|
|
@ -18,13 +19,16 @@ use Shared\DDD\Usecase\Builder\UsecaseExecutor;
|
|||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
|
||||
final class RegenerateClientSecretCommand extends Command
|
||||
use function Laravel\Prompts\confirm;
|
||||
use function Laravel\Prompts\search;
|
||||
|
||||
final class RegenerateClientSecretCommand extends Command implements PromptsForMissingInput
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'client:regenerate-secret
|
||||
{identifier? : The identifier of the client}';
|
||||
{identifier : The identifier of the client}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
|
@ -37,6 +41,22 @@ final class RegenerateClientSecretCommand extends Command
|
|||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, \Closure(): (int|string)>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function promptForMissingArgumentsUsing(): array
|
||||
{
|
||||
return [
|
||||
'identifier' => fn (): int | string => search(
|
||||
label: 'Search client (by name, ID, identifier, or slug):',
|
||||
placeholder: 'Type client name, identifier or slug...',
|
||||
options: fn (string $value): array => $this->clientResolver->searchOptions($value),
|
||||
scroll: 10,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
|
|
@ -89,33 +109,29 @@ final class RegenerateClientSecretCommand extends Command
|
|||
|
||||
private function resolveClient(): ?Client
|
||||
{
|
||||
$raw = $this->argument('identifier');
|
||||
$rawString = is_string($raw) ? $raw : $this->anticipate(
|
||||
'Search client (by name, ID, identifier, or slug):',
|
||||
fn (string $input): array => $this->clientResolver->searchSuggestions($input),
|
||||
);
|
||||
$raw = $this->argument('identifier');
|
||||
|
||||
if (! is_string($rawString) || trim($rawString) === '') {
|
||||
if (! is_string($raw) || trim($raw) === '') {
|
||||
$this->error('No client specified.');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$inputString = trim($rawString);
|
||||
$inputString = trim($raw);
|
||||
$client = $this->clientResolver->find($inputString);
|
||||
|
||||
if ($client === null) {
|
||||
try {
|
||||
new ClientIdentifier($inputString);
|
||||
$this->error("Client '{$inputString}' not found.");
|
||||
} catch (\InvalidArgumentException) {
|
||||
$this->error("Invalid client identifier '{$inputString}'. Expected a valid client identifier.");
|
||||
}
|
||||
|
||||
return null;
|
||||
if ($client !== null) {
|
||||
return $client;
|
||||
}
|
||||
|
||||
return $client;
|
||||
try {
|
||||
new ClientIdentifier($inputString);
|
||||
$this->error("Client '{$inputString}' not found.");
|
||||
} catch (\InvalidArgumentException) {
|
||||
$this->error("Invalid client identifier '{$inputString}'. Expected a valid client identifier.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function confirmRegeneration(Client $client): bool
|
||||
|
|
@ -123,7 +139,10 @@ final class RegenerateClientSecretCommand extends Command
|
|||
$this->newLine();
|
||||
$this->warn(sprintf("Regenerating the secret will immediately invalidate the existing secret for client '%s'.", $client->name->value));
|
||||
|
||||
return $this->confirm('Do you want to proceed?', false);
|
||||
return confirm(
|
||||
label: 'Do you want to proceed?',
|
||||
default: false,
|
||||
);
|
||||
}
|
||||
|
||||
private function displayResult(Client $client, RegenerateClientSecretView $view): void
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Application\Security\Models\ValueObjects\ClientIdentifier;
|
|||
use Application\Security\Usecases\ToggleClientStatus\Input;
|
||||
use Application\Security\Usecases\ToggleClientStatus\SetClientStatus;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\PromptsForMissingInput;
|
||||
use Presentation\Console\Presenters\Clients\SetClientStatusPresenter;
|
||||
use Presentation\Console\Services\ClientConsoleResolver;
|
||||
use Shared\DDD\Usecase\Builder\UsecaseBuilder;
|
||||
|
|
@ -18,13 +19,15 @@ use Symfony\Component\Console\Completion\CompletionInput;
|
|||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Completion\Suggestion;
|
||||
|
||||
final class ToggleClientStatusCommand extends Command
|
||||
use function Laravel\Prompts\search;
|
||||
|
||||
final class ToggleClientStatusCommand extends Command implements PromptsForMissingInput
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'client:toggle-status
|
||||
{identifier? : The identifier of the client}
|
||||
{identifier : The identifier of the client}
|
||||
{status? : The desired status of the client (activate|deactivate)}';
|
||||
|
||||
/**
|
||||
|
|
@ -38,6 +41,22 @@ final class ToggleClientStatusCommand extends Command
|
|||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, \Closure(): (int|string)>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function promptForMissingArgumentsUsing(): array
|
||||
{
|
||||
return [
|
||||
'identifier' => fn (): int | string => search(
|
||||
label: 'Search client (by name, ID, identifier, or slug):',
|
||||
placeholder: 'Type client name, identifier or slug...',
|
||||
options: fn (string $value): array => $this->clientResolver->searchOptions($value),
|
||||
scroll: 10,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
|
|
@ -103,33 +122,29 @@ final class ToggleClientStatusCommand extends Command
|
|||
|
||||
private function resolveClient(): ?Client
|
||||
{
|
||||
$raw = $this->argument('identifier');
|
||||
$rawString = is_string($raw) ? $raw : $this->anticipate(
|
||||
'Search client (by name, ID, identifier, or slug):',
|
||||
fn (string $input): array => $this->clientResolver->searchSuggestions($input),
|
||||
);
|
||||
$raw = $this->argument('identifier');
|
||||
|
||||
if (! is_string($rawString) || trim($rawString) === '') {
|
||||
if (! is_string($raw) || trim($raw) === '') {
|
||||
$this->error('No client specified.');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$inputString = trim($rawString);
|
||||
$inputString = trim($raw);
|
||||
$client = $this->clientResolver->find($inputString);
|
||||
|
||||
if ($client === null) {
|
||||
try {
|
||||
new ClientIdentifier($inputString);
|
||||
$this->error("Client '{$inputString}' not found.");
|
||||
} catch (\InvalidArgumentException) {
|
||||
$this->error("Invalid client identifier '{$inputString}'. Expected a valid client identifier.");
|
||||
}
|
||||
|
||||
return null;
|
||||
if ($client !== null) {
|
||||
return $client;
|
||||
}
|
||||
|
||||
return $client;
|
||||
try {
|
||||
new ClientIdentifier($inputString);
|
||||
$this->error("Client '{$inputString}' not found.");
|
||||
} catch (\InvalidArgumentException) {
|
||||
$this->error("Invalid client identifier '{$inputString}'. Expected a valid client identifier.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function resolveDesiredStatus(Client $client): bool
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ namespace Presentation\Console\Services;
|
|||
|
||||
use Application\Security\Models\Entities\Client;
|
||||
use Application\Security\Models\ValueObjects\ClientIdentifier;
|
||||
use Application\Security\Models\ValueObjects\Entities\ClientId;
|
||||
use Application\Security\Ports\Repositories\ClientRepository;
|
||||
use Application\Security\Usecases\FindClient\FindClient;
|
||||
use Application\Security\Usecases\FindClient\Input as FindClientInput;
|
||||
use Presentation\Console\Presenters\Clients\FindClientPresenter;
|
||||
use Presentation\Console\Presenters\Clients\FoundClientItem;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Shared\DDD\Usecase\Builder\UsecaseBuilder;
|
||||
use Shared\DDD\Usecase\Builder\UsecaseExecutor;
|
||||
use Shared\Pagination;
|
||||
|
|
@ -46,16 +47,27 @@ final readonly class ClientConsoleResolver
|
|||
}
|
||||
|
||||
/**
|
||||
* Provide suggestions for console anticipate() prompt.
|
||||
* Provide options for Laravel Prompts search() dropdown.
|
||||
*
|
||||
* @return list<string>
|
||||
* @return array<string, string> Key: identifier, Value: display label
|
||||
*/
|
||||
public function searchSuggestions(string $input): array
|
||||
public function searchOptions(string $value): array
|
||||
{
|
||||
$trimmed = trim($input);
|
||||
$trimmed = trim($value);
|
||||
|
||||
if ($trimmed === '') {
|
||||
return [];
|
||||
$clients = $this->clientRepository->findAll(Pagination::ofOffsetAndLimit(0, 10));
|
||||
$options = [];
|
||||
foreach ($clients->getItems() as $client) {
|
||||
$options[$client->identifier->value] = sprintf(
|
||||
'%s (%s) - %s',
|
||||
$client->name->value,
|
||||
$client->isActive ? 'Active' : 'Inactive',
|
||||
$client->identifier->value,
|
||||
);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -66,17 +78,19 @@ final readonly class ClientConsoleResolver
|
|||
->with(new FindClientPresenter())
|
||||
->run();
|
||||
|
||||
return array_map(
|
||||
static fn (FoundClientItem $item): string => $item->identifier,
|
||||
$view->clients,
|
||||
);
|
||||
$options = [];
|
||||
foreach ($view->clients as $item) {
|
||||
$options[$item->identifier] = $item->display;
|
||||
}
|
||||
|
||||
return $options;
|
||||
} catch (\Throwable) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a Client by identifier, or by searching matching name, slug, or ID.
|
||||
* Find a Client by identifier, display string, name, slug, or ID.
|
||||
*/
|
||||
public function find(string $input): ?Client
|
||||
{
|
||||
|
|
@ -86,20 +100,36 @@ final readonly class ClientConsoleResolver
|
|||
return null;
|
||||
}
|
||||
|
||||
// 1. Direct lookup by exact ClientIdentifier format
|
||||
try {
|
||||
$identifier = new ClientIdentifier($trimmed);
|
||||
$client = $this->clientRepository->findByIdentifier($identifier);
|
||||
|
||||
if (preg_match('/arcadia_id_[a-f0-9]{32}/i', $trimmed, $matches) === 1) {
|
||||
$client = $this->findByIdentifier($matches[0]);
|
||||
if ($client !== null) {
|
||||
return $client;
|
||||
}
|
||||
} catch (\InvalidArgumentException) {
|
||||
// Not a valid ClientIdentifier format, fallback to search via FindClient
|
||||
$isExactIdentifier = false;
|
||||
}
|
||||
|
||||
// 2. Search via FindClient use case
|
||||
$byUuid = $this->findByUuid($trimmed);
|
||||
if ($byUuid !== null) {
|
||||
return $byUuid;
|
||||
}
|
||||
|
||||
return $this->findBySearch($trimmed);
|
||||
}
|
||||
|
||||
private function findByUuid(string $trimmed): ?Client
|
||||
{
|
||||
try {
|
||||
if (! Uuid::isValid($trimmed)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->clientRepository->find(new ClientId(Uuid::fromString($trimmed)));
|
||||
} catch (\Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function findBySearch(string $trimmed): ?Client
|
||||
{
|
||||
try {
|
||||
/** @var \Presentation\Console\Presenters\Clients\FindClientView $view */
|
||||
$view = UsecaseBuilder::using($this->executor)
|
||||
|
|
@ -109,9 +139,7 @@ final readonly class ClientConsoleResolver
|
|||
->run();
|
||||
|
||||
if (count($view->clients) === 1) {
|
||||
$identifier = new ClientIdentifier($view->clients[0]->identifier);
|
||||
|
||||
return $this->clientRepository->findByIdentifier($identifier);
|
||||
return $this->findByIdentifier($view->clients[0]->identifier);
|
||||
}
|
||||
|
||||
if (count($view->clients) > 1) {
|
||||
|
|
@ -119,17 +147,25 @@ final readonly class ClientConsoleResolver
|
|||
if (
|
||||
strcasecmp($found->name, $trimmed) === 0 || strcasecmp($found->id, $trimmed) === 0
|
||||
) {
|
||||
$identifier = new ClientIdentifier($found->identifier);
|
||||
|
||||
return $this->clientRepository->findByIdentifier($identifier);
|
||||
return $this->findByIdentifier($found->identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// Search error fallback
|
||||
$searchFailed = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function findByIdentifier(string | ClientIdentifier $input): ?Client
|
||||
{
|
||||
try {
|
||||
$identifier = $input instanceof ClientIdentifier ? $input : new ClientIdentifier($input);
|
||||
|
||||
return $this->clientRepository->findByIdentifier($identifier);
|
||||
} catch (\InvalidArgumentException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ describe('CreateClientCommand', function (): void {
|
|||
|
||||
// WHEN
|
||||
$this->artisan('client:create')
|
||||
|
||||
// THEN
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', $clientName)
|
||||
->expectsConfirmation('Create this API client?', 'yes')
|
||||
|
|
@ -40,7 +39,6 @@ describe('CreateClientCommand', function (): void {
|
|||
|
||||
// WHEN
|
||||
$this->artisan('client:create')
|
||||
|
||||
// THEN
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', $clientName)
|
||||
->expectsConfirmation('Create this API client?', 'no')
|
||||
|
|
@ -51,44 +49,14 @@ describe('CreateClientCommand', function (): void {
|
|||
expect($client)->toBeNull();
|
||||
});
|
||||
|
||||
it('retries when an empty name is provided', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $this */
|
||||
it('fails when an empty name is provided', function (): void {
|
||||
// GIVEN & WHEN & THEN
|
||||
$this->artisan('client:create')
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', '')
|
||||
->expectsOutput('Client name cannot be empty.')
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', 'Valid Gateway')
|
||||
|
||||
// WHEN
|
||||
->expectsConfirmation('Create this API client?', 'yes')
|
||||
->expectsOutputToContain("API client 'Valid Gateway' created successfully.")
|
||||
|
||||
// THEN
|
||||
->assertSuccessful();
|
||||
|
||||
$client = ApiClient::query()
|
||||
->where('name', 'Valid Gateway')
|
||||
->first();
|
||||
expect($client)->not->toBeNull();
|
||||
});
|
||||
|
||||
it('fails after maximum retries with invalid names', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $this */
|
||||
$this->artisan('client:create')
|
||||
|
||||
// WHEN
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', '')
|
||||
->expectsOutput('Client name cannot be empty.')
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', '')
|
||||
->expectsOutput('Client name cannot be empty.')
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', '')
|
||||
->expectsOutput('Client name cannot be empty.')
|
||||
->expectsOutput('Maximum number of attempts reached. Aborting.')
|
||||
->assertFailed();
|
||||
});
|
||||
|
||||
it('retries when the client name already exists', function (): void {
|
||||
it('fails when the client name already exists', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $this */
|
||||
ApiClient::factory()->create([
|
||||
|
|
@ -96,18 +64,9 @@ describe('CreateClientCommand', function (): void {
|
|||
'slug' => 'existing-gateway',
|
||||
]);
|
||||
|
||||
// WHEN
|
||||
// WHEN & THEN
|
||||
$this->artisan('client:create')
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', 'Existing Gateway')
|
||||
->expectsOutput("A client with the name 'Existing Gateway' (or similar) already exists.")
|
||||
->expectsQuestion('Client name (e.g. "Ones Branding website")', 'New Gateway')
|
||||
->expectsConfirmation('Create this API client?', 'yes')
|
||||
|
||||
// THEN
|
||||
->expectsOutputToContain("API client 'New Gateway' created successfully.")
|
||||
->assertSuccessful();
|
||||
|
||||
$client = ApiClient::query()->where('name', 'New Gateway')->first();
|
||||
expect($client)->not->toBeNull();
|
||||
->assertFailed();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ describe('RegenerateClientSecretCommand', function (): void {
|
|||
|
||||
// WHEN
|
||||
$this->artisan('client:regenerate-secret', ['identifier' => $invalidIdentifier])
|
||||
|
||||
// THEN
|
||||
->expectsOutput("Invalid client identifier '{$invalidIdentifier}'. Expected a valid client identifier.")
|
||||
->assertFailed();
|
||||
|
|
@ -32,7 +31,6 @@ describe('RegenerateClientSecretCommand', function (): void {
|
|||
|
||||
// WHEN
|
||||
$this->artisan('client:regenerate-secret', ['identifier' => $nonExistentIdentifier])
|
||||
|
||||
// THEN
|
||||
->expectsOutput("Client '{$nonExistentIdentifier}' not found.")
|
||||
->assertFailed();
|
||||
|
|
@ -55,7 +53,6 @@ describe('RegenerateClientSecretCommand', function (): void {
|
|||
|
||||
// WHEN
|
||||
$this->artisan('client:regenerate-secret', ['identifier' => $identifier])
|
||||
|
||||
// THEN
|
||||
->expectsConfirmation('Do you want to proceed?', 'yes')
|
||||
->expectsOutputToContain("Secret for client '{$identifier}' regenerated successfully.")
|
||||
|
|
@ -84,7 +81,6 @@ describe('RegenerateClientSecretCommand', function (): void {
|
|||
|
||||
// WHEN
|
||||
$this->artisan('client:regenerate-secret', ['identifier' => $identifier])
|
||||
|
||||
// THEN
|
||||
->expectsConfirmation('Do you want to proceed?', 'no')
|
||||
->expectsOutput('Secret regeneration cancelled.')
|
||||
|
|
@ -111,9 +107,11 @@ describe('RegenerateClientSecretCommand', function (): void {
|
|||
|
||||
// WHEN
|
||||
$this->artisan('client:regenerate-secret')
|
||||
|
||||
// THEN
|
||||
->expectsQuestion('Search client (by name, ID, identifier, or slug):', $identifier)
|
||||
->expectsChoice('Search client (by name, ID, identifier, or slug):', $identifier, [
|
||||
$identifier => "Searchable Client (Active) - {$identifier}",
|
||||
])
|
||||
->expectsConfirmation('Do you want to proceed?', 'yes')
|
||||
->expectsOutputToContain("Secret for client '{$identifier}' regenerated successfully.")
|
||||
->assertSuccessful();
|
||||
|
|
@ -122,16 +120,6 @@ describe('RegenerateClientSecretCommand', function (): void {
|
|||
expect($client->secret->value)->not->toBe($oldSecret);
|
||||
});
|
||||
|
||||
it('outputs an error when no input provided during interactive prompt', function (): void {
|
||||
// GIVEN & WHEN
|
||||
$this->artisan('client:regenerate-secret')
|
||||
|
||||
// THEN
|
||||
->expectsQuestion('Search client (by name, ID, identifier, or slug):', '')
|
||||
->expectsOutput('No client specified.')
|
||||
->assertFailed();
|
||||
});
|
||||
|
||||
it('provides autocompletion suggestions for identifier', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $this */
|
||||
|
|
|
|||
|
|
@ -161,6 +161,9 @@ describe('ToggleClientStatusCommand', function (): void {
|
|||
$this->artisan('client:toggle-status')
|
||||
// THEN
|
||||
->expectsQuestion('Search client (by name, ID, identifier, or slug):', $identifier)
|
||||
->expectsChoice('Search client (by name, ID, identifier, or slug):', $identifier, [
|
||||
$identifier => "Interactive Gateway (Active) - {$identifier}",
|
||||
])
|
||||
->expectsOutput("Client 'Interactive Gateway' (ID: {$client->id}) is now Inactive.")
|
||||
->assertSuccessful();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue