Skip to content

Commit 91c77e9

Browse files
committed
fix: Refactor promptAction method visibility and enhance interactive command tests
1 parent edd5076 commit 91c77e9

2 files changed

Lines changed: 87 additions & 2 deletions

File tree

src/Console/Command/Dev/InspectorCommand.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ protected function executeCommand(InputInterface $input, OutputInterface $output
132132
*
133133
* @return string|null The selected action (enable, disable, status), or null if cancelled/failed
134134
*/
135-
private function promptAction(): ?string
135+
protected function promptAction(): ?string
136136
{
137137
$currentStatus = $this->isInspectorEnabled() ? 'enabled' : 'disabled';
138138

@@ -147,13 +147,18 @@ private function promptAction(): ?string
147147
hint: 'Arrow keys to navigate, Enter to confirm',
148148
);
149149

150+
// Set environment variables for Laravel Prompts (Docker/DDEV compatibility)
151+
$this->setPromptEnvironment();
152+
150153
try {
151154
$selection = $prompt->prompt();
152-
\Laravel\Prompts\Prompt::terminal()->restoreTty();
153155
return is_string($selection) ? $selection : null;
154156
} catch (\Exception $e) {
155157
$this->io->error('Selection failed: ' . $e->getMessage());
156158
return null;
159+
} finally {
160+
\Laravel\Prompts\Prompt::terminal()->restoreTty();
161+
$this->resetPromptEnvironment();
157162
}
158163
}
159164

tests/Unit/Console/Command/Dev/InspectorCommandTest.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use OpenForgeProject\MageForge\Model\Config\Inspector as InspectorConfig;
1414
use PHPUnit\Framework\MockObject\MockObject;
1515
use PHPUnit\Framework\TestCase;
16+
use Symfony\Component\Console\Output\OutputInterface;
1617
use Symfony\Component\Console\Tester\CommandTester;
1718

1819
class InspectorCommandTest extends TestCase
@@ -229,4 +230,83 @@ public function testStatusUppercasesActionArgument(): void
229230
$this->assertSame(Cli::RETURN_SUCCESS, $exitCode);
230231
$this->assertStringContainsString('MageForge Inspector Status', $tester->getDisplay());
231232
}
233+
234+
// -------------------------------------------------------------------------
235+
// No-argument execution path (interactive menu / non-interactive fallback)
236+
// -------------------------------------------------------------------------
237+
238+
public function testNoActionFallsBackToStatusInNonInteractiveMode(): void
239+
{
240+
$this->state->method('getMode')->willReturn(State::MODE_DEVELOPER);
241+
$this->scopeConfig->method('isSetFlag')->willReturn(true);
242+
$this->configWriter->expects($this->never())->method('save');
243+
244+
$tester = new CommandTester($this->command);
245+
$exitCode = $tester->execute([]);
246+
247+
$this->assertSame(Cli::RETURN_SUCCESS, $exitCode);
248+
$this->assertStringContainsString('MageForge Inspector Status', $tester->getDisplay());
249+
}
250+
251+
public function testNoActionUsesSelectedActionFromInteractiveMenu(): void
252+
{
253+
$this->state->method('getMode')->willReturn(State::MODE_DEVELOPER);
254+
$this->configWriter->expects($this->once())
255+
->method('save')
256+
->with(InspectorConfig::XML_PATH_ENABLED, '0');
257+
258+
$tester = new CommandTester($this->createInteractiveCommand('disable'));
259+
$exitCode = $tester->execute([]);
260+
261+
$this->assertSame(Cli::RETURN_SUCCESS, $exitCode);
262+
$this->assertStringContainsString('has been disabled', $tester->getDisplay());
263+
}
264+
265+
public function testNoActionFailsWhenInteractiveMenuIsCancelled(): void
266+
{
267+
$this->configWriter->expects($this->never())->method('save');
268+
269+
$tester = new CommandTester($this->createInteractiveCommand(null));
270+
$exitCode = $tester->execute([]);
271+
272+
$this->assertSame(Cli::RETURN_FAILURE, $exitCode);
273+
}
274+
275+
/**
276+
* Create a command double that always takes the interactive path and returns
277+
* the given selection from the menu instead of rendering a real prompt
278+
*
279+
* @param string|null $selection
280+
* @return InspectorCommand
281+
*/
282+
private function createInteractiveCommand(?string $selection): InspectorCommand
283+
{
284+
return new class(
285+
$this->configWriter,
286+
$this->state,
287+
$this->cacheManager,
288+
$this->scopeConfig,
289+
$selection,
290+
) extends InspectorCommand {
291+
public function __construct(
292+
WriterInterface $configWriter,
293+
State $state,
294+
CacheManager $cacheManager,
295+
ScopeConfigInterface $scopeConfig,
296+
private readonly ?string $selection,
297+
) {
298+
parent::__construct($configWriter, $state, $cacheManager, $scopeConfig);
299+
}
300+
301+
protected function isInteractiveTerminal(OutputInterface $output): bool
302+
{
303+
return true;
304+
}
305+
306+
protected function promptAction(): ?string
307+
{
308+
return $this->selection;
309+
}
310+
};
311+
}
232312
}

0 commit comments

Comments
 (0)