TenantAtlas/apps/platform/tests/Feature/System/CustomerHealth/CustomerHealthDetailDecisionTest.php
ahmido 86505483bf
Some checks failed
Main Confidence / confidence (push) Failing after 52s
feat(customer-health): add decision card to tenant/workspace detail (spec 245) (#283)
Add Customer Health decision card to tenant & workspace detail pages (spec 245).

What I changed:
- Render a decision-first Customer Health card on tenant and workspace detail pages.
- Reuse `WorkspaceHealthSummaryQuery` and preserve `window` query param.
- Update attention widget link text to "Review health details" and include `?window=`.
- Add/adjust tests to cover new behavior and explainability.
- Run Pint formatting.

Compare URL: https://git.cloudarix.de/ahmido/TenantAtlas/compare/dev...245-customer-health-score

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #283
2026-04-27 08:30:01 +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\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\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('Tenant 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: Tenant}
*/
function createCustomerHealthDecisionFixture(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)
->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,
];
}