TenantAtlas/apps/platform/tests/Feature/System/CustomerHealth/CustomerHealthExplainabilityTest.php
Ahmed Darrazi 324ee45e64
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m3s
feat(customer-health): add detail decision card and update attention widget link (spec 245)
2026-04-27 10:26:00 +02:00

177 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\System\Widgets\CustomerHealthTopWorkspaces;
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\Tenant;
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\System\SystemOperationRunLinks;
use App\Support\SystemConsole\SystemConsoleWindow;
use Carbon\CarbonImmutable;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
uses(RefreshDatabase::class);
beforeEach(function (): void {
Filament::setCurrentPanel('system');
Filament::bootCurrentPanel();
CarbonImmutable::setTestNow(CarbonImmutable::parse('2026-04-27 12:00:00'));
});
afterEach(function (): void {
CarbonImmutable::setTestNow();
});
it('lists the worst workspaces first with dominant reasons and one platform-safe next link per row', function (): void {
actingAsExplainabilitySystemUser();
$opsWorkspace = seedExplainabilityWorkspace('Alpha Operations');
OperationRun::factory()
->forTenant($opsWorkspace['tenant'])
->create([
'workspace_id' => (int) $opsWorkspace['workspace']->getKey(),
'status' => OperationRunStatus::Queued->value,
'outcome' => OperationRunOutcome::Pending->value,
'created_at' => now()->subHours(2),
'started_at' => null,
]);
$providerWorkspace = seedExplainabilityWorkspace('Beta Provider');
ProviderConnection::query()
->where('tenant_id', (int) $providerWorkspace['tenant']->getKey())
->update([
'is_enabled' => true,
'consent_status' => ProviderConsentStatus::Granted->value,
'verification_status' => ProviderVerificationStatus::Blocked->value,
]);
$viewData = customerHealthTopWorkspaceViewData(SystemConsoleWindow::LastWeek);
$rows = collect($viewData['rows'])->take(2)->values();
expect($rows[0]['workspace_label'])->toBe('Alpha Operations')
->and($rows[0]['overall']['label'])->toBe('Critical')
->and(array_column($rows[0]['dominant_dimensions'], 'label'))->toBe(['Operational stability'])
->and($rows[0]['next_link'])->toBe([
'label' => 'Open runs',
'url' => SystemOperationRunLinks::index(),
])
->and($rows[1]['workspace_label'])->toBe('Beta Provider')
->and($rows[1]['overall']['label'])->toBe('Critical')
->and(array_column($rows[1]['dominant_dimensions'], 'label'))->toBe(['Provider connection health'])
->and($rows[1]['next_link'])->toBe([
'label' => 'Review health details',
'url' => SystemDirectoryLinks::tenantDetail($providerWorkspace['tenant']).'?window='.SystemConsoleWindow::LastWeek,
])
->and($rows->every(fn (array $row): bool => count($row['dominant_dimensions']) <= 2))->toBeTrue()
->and($rows->every(fn (array $row): bool => ! str_contains($row['next_link']['url'], '/admin/')))->toBeTrue()
->and(array_key_exists('failed_count', $rows[0]))->toBeFalse();
});
/**
* @return array<string, mixed>
*/
function customerHealthTopWorkspaceViewData(string $window = SystemConsoleWindow::LastDay): array
{
$component = Livewire::withQueryParams([
'window' => $window,
])->test(CustomerHealthTopWorkspaces::class);
$method = new ReflectionMethod(CustomerHealthTopWorkspaces::class, 'getViewData');
$method->setAccessible(true);
return $method->invoke($component->instance());
}
function actingAsExplainabilitySystemUser(): PlatformUser
{
$user = PlatformUser::factory()->create([
'capabilities' => [
PlatformCapabilities::ACCESS_SYSTEM_PANEL,
PlatformCapabilities::CONSOLE_VIEW,
PlatformCapabilities::DIRECTORY_VIEW,
PlatformCapabilities::OPERATIONS_VIEW,
],
'is_active' => true,
]);
test()->actingAs($user, 'platform');
return $user;
}
/**
* @return array{workspace: Workspace, tenant: Tenant}
*/
function seedExplainabilityWorkspace(string $workspaceName): array
{
$workspace = Workspace::factory()->create(['name' => $workspaceName]);
$tenant = Tenant::factory()->for($workspace)->create([
'name' => $workspaceName.' Tenant',
'status' => Tenant::STATUS_ACTIVE,
]);
ProviderConnection::factory()
->for($tenant)
->verifiedHealthy()
->create([
'workspace_id' => (int) $workspace->getKey(),
'is_default' => true,
]);
ReviewPack::factory()
->for($tenant)
->ready()
->create([
'workspace_id' => (int) $workspace->getKey(),
'created_at' => now()->subHour(),
'generated_at' => now()->subHour(),
'expires_at' => now()->addDays(30),
]);
ProductUsageEvent::factory()
->for($tenant)
->forEvent(ProductUsageEventCatalog::ONBOARDING_CHECKPOINT_COMPLETED)
->create([
'workspace_id' => (int) $workspace->getKey(),
'occurred_at' => now()->subMinutes(20),
]);
OperationRun::factory()
->forTenant($tenant)
->create([
'workspace_id' => (int) $workspace->getKey(),
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Succeeded->value,
'created_at' => now()->subMinutes(10),
'started_at' => now()->subMinutes(15),
'completed_at' => now()->subMinutes(5),
]);
Finding::factory()
->for($tenant)
->closed()
->create([
'severity' => Finding::SEVERITY_LOW,
]);
return [
'workspace' => $workspace,
'tenant' => $tenant,
];
}