TenantAtlas/apps/platform/tests/Feature/Governance/DecisionRegisterPageTest.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

178 lines
6.6 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\Governance\DecisionRegister;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\FindingExceptionDecision;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('renders open and recently closed decision rows for visible tenants only', function (): void {
$visibleTenant = ManagedEnvironment::factory()->create([
'status' => 'active',
'name' => 'Visible ManagedEnvironment',
'external_id' => 'visible-tenant',
]);
[$user, $visibleTenant] = createUserWithTenant($visibleTenant, role: 'readonly', workspaceRole: 'readonly');
$hiddenTenant = ManagedEnvironment::factory()->create([
'status' => 'active',
'workspace_id' => (int) $visibleTenant->workspace_id,
'name' => 'Hidden ManagedEnvironment',
'external_id' => 'hidden-tenant',
]);
decisionRegisterPageException(
tenant: $visibleTenant,
actor: $user,
status: FindingException::STATUS_PENDING,
validityState: FindingException::VALIDITY_MISSING_SUPPORT,
decisionType: FindingExceptionDecision::TYPE_REQUESTED,
decisionReason: 'Visible approval request',
exceptionAttributes: [
'requested_at' => now()->subDays(2),
'review_due_at' => now()->addDay(),
],
decisionAttributes: [
'decided_at' => now()->subDays(2),
],
);
decisionRegisterPageException(
tenant: $visibleTenant,
actor: $user,
status: FindingException::STATUS_REJECTED,
validityState: FindingException::VALIDITY_REJECTED,
decisionType: FindingExceptionDecision::TYPE_REJECTED,
decisionReason: 'Recently rejected closure reason',
exceptionAttributes: [
'rejected_at' => now()->subDays(2),
'review_due_at' => now()->subDays(3),
],
decisionAttributes: [
'decided_at' => now()->subDays(2),
],
);
decisionRegisterPageException(
tenant: $hiddenTenant,
actor: $user,
status: FindingException::STATUS_PENDING,
validityState: FindingException::VALIDITY_MISSING_SUPPORT,
decisionType: FindingExceptionDecision::TYPE_REQUESTED,
decisionReason: 'Hidden tenant request',
);
$this->actingAs($user)
->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id])
->get(DecisionRegister::getUrl(panel: 'admin'))
->assertOk()
->assertSee('Decision register')
->assertSee('Visible ManagedEnvironment')
->assertSee('Review approval')
->assertSee('Open decision')
->assertDontSee('Recently rejected closure reason')
->assertDontSee('Hidden tenant request');
$this->actingAs($user)
->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id])
->get(DecisionRegister::getUrl(panel: 'admin').'?register_state=recently_closed')
->assertOk()
->assertSee('Recently rejected closure reason')
->assertDontSee('Visible approval request');
});
it('shows truthful filtered empty states for tenant and register-state filters', function (): void {
$alphaTenant = ManagedEnvironment::factory()->create([
'status' => 'active',
'name' => 'Alpha ManagedEnvironment',
'external_id' => 'alpha-tenant',
]);
[$user, $alphaTenant] = createUserWithTenant($alphaTenant, role: 'owner', workspaceRole: 'owner');
$bravoTenant = ManagedEnvironment::factory()->create([
'status' => 'active',
'workspace_id' => (int) $alphaTenant->workspace_id,
'name' => 'Bravo ManagedEnvironment',
'external_id' => 'bravo-tenant',
]);
$user->tenants()->syncWithoutDetaching([
(int) $bravoTenant->getKey() => ['role' => 'owner'],
]);
decisionRegisterPageException(
tenant: $bravoTenant,
actor: $user,
status: FindingException::STATUS_PENDING,
validityState: FindingException::VALIDITY_MISSING_SUPPORT,
decisionType: FindingExceptionDecision::TYPE_REQUESTED,
decisionReason: 'Bravo tenant request',
);
$this->actingAs($user)
->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id])
->get(DecisionRegister::getUrl(panel: 'admin').'?managed_environment_id='.(string) $alphaTenant->getKey())
->assertOk()
->assertSee('This tenant filter is hiding other visible decision follow-through')
->assertSee('Clear tenant filter');
$this->actingAs($user)
->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id])
->get(DecisionRegister::getUrl(panel: 'admin').'?register_state=recently_closed')
->assertOk()
->assertSee('No recently closed decisions match this filter right now.');
});
/**
* @param array<string, mixed> $exceptionAttributes
* @param array<string, mixed> $decisionAttributes
*/
function decisionRegisterPageException(
ManagedEnvironment $tenant,
User $actor,
string $status,
string $validityState,
string $decisionType,
string $decisionReason,
array $exceptionAttributes = [],
array $decisionAttributes = [],
): FindingException {
$finding = Finding::factory()->for($tenant)->create([
'workspace_id' => (int) $tenant->workspace_id,
]);
$exception = FindingException::query()->create(array_merge([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'finding_id' => (int) $finding->getKey(),
'requested_by_user_id' => (int) $actor->getKey(),
'owner_user_id' => (int) $actor->getKey(),
'status' => $status,
'current_validity_state' => $validityState,
'request_reason' => 'Decision register page test',
'requested_at' => now()->subDay(),
'review_due_at' => now()->addDay(),
'evidence_summary' => ['reference_count' => 0],
], $exceptionAttributes));
$decision = $exception->decisions()->create(array_merge([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'actor_user_id' => (int) $actor->getKey(),
'decision_type' => $decisionType,
'reason' => $decisionReason,
'metadata' => [],
'decided_at' => now()->subDay(),
], $decisionAttributes));
$exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save();
return $exception->fresh(['currentDecision']);
}