TenantAtlas/apps/platform/tests/Feature/System/CustomerHealth/CustomerHealthDetailDecisionTest.php
ahmido e64bae9cfc feat: cut over tenant core to managed environments (#335)
## Summary
- replace the legacy Tenant and TenantMembership core models with ManagedEnvironment and ManagedEnvironmentMembership
- propagate the managed environment naming and key changes across Filament resources, pages, controllers, jobs, models, and supporting runtime paths
- add feature 279 spec artifacts and focused managed-environment test coverage for model behavior, route binding, panel context, authorization, and legacy guardrails

## Validation
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentAuthorizationTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentPanelContextTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentRouteBindingTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentContextResolverTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentModelTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

## Notes
- branch pushed from commit `1123b122`
- browser smoke test file was added but not run in this pass

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #335
2026-05-07 06:38:14 +00:00

158 lines
5.7 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\Finding;
use App\Models\OperationRun;
use App\Models\PlatformUser;
use App\Models\ProductUsageEvent;
use App\Models\ProviderConnection;
use App\Models\ReviewPack;
use App\Models\ManagedEnvironment;
use App\Models\Workspace;
use App\Support\Auth\PlatformCapabilities;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\ProductTelemetry\ProductUsageEventCatalog;
use App\Support\Providers\ProviderConsentStatus;
use App\Support\Providers\ProviderVerificationStatus;
use App\Support\System\SystemDirectoryLinks;
use App\Support\SystemConsole\SystemConsoleWindow;
use Carbon\CarbonImmutable;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function (): void {
CarbonImmutable::setTestNow(CarbonImmutable::parse('2026-04-27 12:00:00'));
});
afterEach(function (): void {
CarbonImmutable::setTestNow();
});
it('renders a decision-first customer health card on the tenant detail page before diagnostics', function (): void {
$fixture = createCustomerHealthDecisionFixture('ManagedEnvironment Decision Workspace');
$platformUser = createDirectoryPlatformUser();
$response = $this->actingAs($platformUser, 'platform')
->get(SystemDirectoryLinks::tenantDetail($fixture['tenant']).'?window='.SystemConsoleWindow::LastWeek)
->assertSuccessful()
->assertSee('Customer health decision')
->assertSee('Overall health')
->assertSee('Reason')
->assertSee('Impact')
->assertSee('Recommended next action')
->assertSee('Top driver: Provider connection health')
->assertSee('Default provider consent or verification is blocking reliable tenant management.')
->assertSee('Review connectivity signals below and confirm the default provider consent and verification state.')
->assertSee('Last 7 days');
$html = $response->getContent();
$decisionPosition = strpos($html, 'Customer health decision');
$diagnosticsPosition = strpos($html, 'Connectivity signals');
expect($decisionPosition)->not->toBeFalse()
->and($diagnosticsPosition)->not->toBeFalse()
->and($decisionPosition)->toBeLessThan($diagnosticsPosition);
});
it('renders a decision-first customer health card on the workspace detail page before tenant diagnostics', function (): void {
$fixture = createCustomerHealthDecisionFixture('Workspace Decision Workspace');
$platformUser = createDirectoryPlatformUser();
$response = $this->actingAs($platformUser, 'platform')
->get(SystemDirectoryLinks::workspaceDetail($fixture['workspace']).'?window='.SystemConsoleWindow::LastWeek)
->assertSuccessful()
->assertSee('Customer health decision')
->assertSee('Overall health')
->assertSee('Reason')
->assertSee('Impact')
->assertSee('Recommended next action')
->assertSee('Top driver: Provider connection health')
->assertSee('Default provider consent or verification is blocking reliable tenant management.')
->assertSee('Open the affected tenant below and review the default provider connection state.')
->assertSee('Last 7 days');
$html = $response->getContent();
$decisionPosition = strpos($html, 'Customer health decision');
$diagnosticsPosition = strpos($html, 'Tenants summary');
expect($decisionPosition)->not->toBeFalse()
->and($diagnosticsPosition)->not->toBeFalse()
->and($decisionPosition)->toBeLessThan($diagnosticsPosition);
});
function createDirectoryPlatformUser(): PlatformUser
{
return PlatformUser::factory()->create([
'capabilities' => [
PlatformCapabilities::ACCESS_SYSTEM_PANEL,
PlatformCapabilities::DIRECTORY_VIEW,
],
'is_active' => true,
]);
}
/**
* @return array{workspace: Workspace, tenant: ManagedEnvironment}
*/
function createCustomerHealthDecisionFixture(string $workspaceName): array
{
$workspace = Workspace::factory()->create(['name' => $workspaceName]);
$tenant = ManagedEnvironment::factory()->for($workspace)->create([
'name' => $workspaceName.' ManagedEnvironment',
'status' => ManagedEnvironment::STATUS_ACTIVE,
]);
ProviderConnection::factory()
->for($tenant)
->create([
'workspace_id' => (int) $workspace->getKey(),
'is_default' => true,
'is_enabled' => true,
'consent_status' => ProviderConsentStatus::Granted->value,
'verification_status' => ProviderVerificationStatus::Blocked->value,
]);
ReviewPack::factory()
->for($tenant)
->ready()
->create([
'workspace_id' => (int) $workspace->getKey(),
'created_at' => now()->subDays(3),
'generated_at' => now()->subDays(3),
'expires_at' => now()->addDays(30),
]);
ProductUsageEvent::factory()
->for($tenant)
->forEvent(ProductUsageEventCatalog::ONBOARDING_CHECKPOINT_COMPLETED)
->create([
'workspace_id' => (int) $workspace->getKey(),
'occurred_at' => now()->subDays(3),
]);
OperationRun::factory()
->forTenant($tenant)
->create([
'workspace_id' => (int) $workspace->getKey(),
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Succeeded->value,
'created_at' => now()->subDays(3),
'started_at' => now()->subDays(3)->subMinutes(5),
'completed_at' => now()->subDays(3),
]);
Finding::factory()
->for($tenant)
->closed()
->create([
'severity' => Finding::SEVERITY_LOW,
]);
return [
'workspace' => $workspace,
'tenant' => $tenant,
];
}