makePartial(); $server->shouldReceive('validatePrerequisites') ->andReturn([ 'success' => false, 'missing' => ['git'], 'found' => ['curl', 'jq'], ]); $activity = Mockery::mock(Activity::class); $activity->id = 'test-activity-123'; $server->shouldReceive('installPrerequisites') ->once() ->andReturn($activity); $component = Mockery::mock(Index::class)->makePartial(); $component->createdServer = $server; $component->prerequisiteInstallAttempts = 0; $component->maxPrerequisiteInstallAttempts = 3; // Key assertion: verify activityMonitor event is dispatched with correct params $component->shouldReceive('dispatch') ->once() ->with('activityMonitor', 'test-activity-123', 'prerequisitesInstalled') ->andReturnSelf(); // Invoke the prerequisite check logic (simulating what validateServer does) $validationResult = $component->createdServer->validatePrerequisites(); if (! $validationResult['success']) { if ($component->prerequisiteInstallAttempts >= $component->maxPrerequisiteInstallAttempts) { throw new Exception('Max attempts exceeded'); } $activity = $component->createdServer->installPrerequisites(); $component->prerequisiteInstallAttempts++; $component->dispatch('activityMonitor', $activity->id, 'prerequisitesInstalled'); } expect($component->prerequisiteInstallAttempts)->toBe(1); }); it('does not retry when prerequisites install successfully', function () { // This test verifies the callback behavior when installation succeeds. $server = Mockery::mock(Server::class)->makePartial(); $server->shouldReceive('validatePrerequisites') ->andReturn([ 'success' => true, 'missing' => [], 'found' => ['git', 'curl', 'jq'], ]); // installPrerequisites should NOT be called again $server->shouldNotReceive('installPrerequisites'); $component = Mockery::mock(Index::class)->makePartial(); $component->createdServer = $server; $component->prerequisiteInstallAttempts = 1; $component->maxPrerequisiteInstallAttempts = 3; // Simulate the callback logic $validationResult = $component->createdServer->validatePrerequisites(); if ($validationResult['success']) { // Prerequisites are now valid, we'd call continueValidation() // For the test, just verify we don't try to install again expect($validationResult['success'])->toBeTrue(); } }); it('retries when prerequisites still missing after callback', function () { // This test verifies retry logic in the callback. $server = Mockery::mock(Server::class)->makePartial(); $server->shouldReceive('validatePrerequisites') ->andReturn([ 'success' => false, 'missing' => ['git'], 'found' => ['curl', 'jq'], ]); $activity = Mockery::mock(Activity::class); $activity->id = 'retry-activity-456'; $server->shouldReceive('installPrerequisites') ->once() ->andReturn($activity); $component = Mockery::mock(Index::class)->makePartial(); $component->createdServer = $server; $component->prerequisiteInstallAttempts = 1; // Already tried once $component->maxPrerequisiteInstallAttempts = 3; $component->shouldReceive('dispatch') ->once() ->with('activityMonitor', 'retry-activity-456', 'prerequisitesInstalled') ->andReturnSelf(); // Simulate callback logic $validationResult = $component->createdServer->validatePrerequisites(); if (! $validationResult['success']) { if ($component->prerequisiteInstallAttempts < $component->maxPrerequisiteInstallAttempts) { $activity = $component->createdServer->installPrerequisites(); $component->prerequisiteInstallAttempts++; $component->dispatch('activityMonitor', $activity->id, 'prerequisitesInstalled'); } } expect($component->prerequisiteInstallAttempts)->toBe(2); }); it('throws exception when max attempts exceeded', function () { // This test verifies that we stop retrying after max attempts. $server = Mockery::mock(Server::class)->makePartial(); $server->shouldReceive('validatePrerequisites') ->andReturn([ 'success' => false, 'missing' => ['git', 'curl'], 'found' => ['jq'], ]); // installPrerequisites should NOT be called when at max attempts $server->shouldNotReceive('installPrerequisites'); $component = Mockery::mock(Index::class)->makePartial(); $component->createdServer = $server; $component->prerequisiteInstallAttempts = 3; // Already at max $component->maxPrerequisiteInstallAttempts = 3; // Simulate callback logic - should throw exception $validationResult = $component->createdServer->validatePrerequisites(); if (! $validationResult['success']) { if ($component->prerequisiteInstallAttempts >= $component->maxPrerequisiteInstallAttempts) { $missingCommands = implode(', ', $validationResult['missing']); throw new Exception("Prerequisites ({$missingCommands}) could not be installed after {$component->maxPrerequisiteInstallAttempts} attempts."); } } })->throws(Exception::class, 'Prerequisites (git, curl) could not be installed after 3 attempts'); it('does not install when prerequisites already present', function () { // This test verifies we skip installation when everything is already installed. $server = Mockery::mock(Server::class)->makePartial(); $server->shouldReceive('validatePrerequisites') ->andReturn([ 'success' => true, 'missing' => [], 'found' => ['git', 'curl', 'jq'], ]); // installPrerequisites should NOT be called $server->shouldNotReceive('installPrerequisites'); $component = Mockery::mock(Index::class)->makePartial(); $component->createdServer = $server; $component->prerequisiteInstallAttempts = 0; $component->maxPrerequisiteInstallAttempts = 3; // Simulate validation logic $validationResult = $component->createdServer->validatePrerequisites(); if (! $validationResult['success']) { // Should not reach here $component->prerequisiteInstallAttempts++; } // Attempts should remain 0 expect($component->prerequisiteInstallAttempts)->toBe(0); expect($validationResult['success'])->toBeTrue(); });