TenantAtlas/apps/platform/tests/Browser/Spec194GovernanceFrictionSmokeTest.php
2026-04-12 23:14:50 +02:00

275 lines
9.8 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\Monitoring\FindingExceptionsQueue;
use App\Filament\Resources\EvidenceSnapshotResource;
use App\Filament\Resources\FindingExceptionResource;
use App\Filament\Resources\TenantResource;
use App\Filament\Resources\TenantReviewResource;
use App\Models\EvidenceSnapshot;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\OperationRun;
use App\Models\PlatformUser;
use App\Models\ReviewPack;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Findings\FindingExceptionService;
use App\Support\Evidence\EvidenceCompletenessState;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\TenantReviewCompletenessState;
use App\Support\TenantReviewStatus;
use App\Support\Auth\PlatformCapabilities;
use App\Support\System\SystemOperationRunLinks;
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->browser()->timeout(20_000);
uses(RefreshDatabase::class);
function spec194ApprovedFindingException(Tenant $tenant, User $requester): FindingException
{
$approver = User::factory()->create();
createUserWithTenant(
tenant: $tenant,
user: $approver,
role: 'owner',
workspaceRole: 'manager',
ensureDefaultMicrosoftProviderConnection: false,
);
$finding = Finding::factory()->for($tenant)->create([
'workspace_id' => (int) $tenant->workspace_id,
'status' => Finding::STATUS_RISK_ACCEPTED,
]);
/** @var FindingExceptionService $service */
$service = app(FindingExceptionService::class);
$requested = $service->request($finding, $tenant, $requester, [
'owner_user_id' => (int) $requester->getKey(),
'request_reason' => 'Spec194 browser smoke request.',
'review_due_at' => now()->addDays(7)->toDateTimeString(),
'expires_at' => now()->addDays(14)->toDateTimeString(),
]);
return $service->approve($requested, $approver, [
'effective_from' => now()->subDay()->toDateTimeString(),
'expires_at' => now()->addDays(14)->toDateTimeString(),
'approval_reason' => 'Spec194 browser smoke approval.',
]);
}
function spec194SmokeLoginUrl(User $user, Tenant $tenant, string $redirect = ''): string
{
return route('admin.local.smoke-login', array_filter([
'email' => $user->email,
'tenant' => $tenant->external_id,
'workspace' => $tenant->workspace->slug,
'redirect' => $redirect,
], static fn (?string $value): bool => filled($value)));
}
it('smokes tenant and admin governance semantics through modal entry points', function (): void {
[$user, $tenant] = createUserWithTenant(
role: 'owner',
workspaceRole: 'manager',
ensureDefaultMicrosoftProviderConnection: false,
);
$finding = Finding::factory()->for($tenant)->create();
$pendingException = FindingException::query()->create([
'workspace_id' => (int) $tenant->workspace_id,
'tenant_id' => (int) $tenant->getKey(),
'finding_id' => (int) $finding->getKey(),
'requested_by_user_id' => (int) $user->getKey(),
'owner_user_id' => (int) $user->getKey(),
'status' => FindingException::STATUS_PENDING,
'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT,
'request_reason' => 'Spec194 focused review queue smoke.',
'requested_at' => now()->subDay(),
'review_due_at' => now()->addDay(),
'evidence_summary' => ['reference_count' => 0],
]);
$approvedException = spec194ApprovedFindingException($tenant, $user);
$snapshotRun = OperationRun::factory()->forTenant($tenant)->create([
'workspace_id' => (int) $tenant->workspace_id,
]);
$snapshot = EvidenceSnapshot::query()->create([
'tenant_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'operation_run_id' => (int) $snapshotRun->getKey(),
'initiated_by_user_id' => (int) $user->getKey(),
'status' => EvidenceSnapshotStatus::Active->value,
'completeness_state' => EvidenceCompletenessState::Complete->value,
'summary' => ['finding_count' => 2],
'generated_at' => now(),
]);
ReviewPack::factory()->ready()->create([
'tenant_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'evidence_snapshot_id' => (int) $snapshot->getKey(),
'initiated_by_user_id' => (int) $user->getKey(),
]);
$review = composeTenantReviewForTest($tenant, $user, $snapshot);
$review->forceFill([
'status' => TenantReviewStatus::Ready->value,
'completeness_state' => TenantReviewCompletenessState::Complete->value,
'summary' => array_replace_recursive(is_array($review->summary) ? $review->summary : [], [
'publish_blockers' => [],
'section_state_counts' => [
'complete' => 6,
'partial' => 0,
'missing' => 0,
'stale' => 0,
],
]),
])->save();
$review = $review->refresh();
$archivedTenant = Tenant::factory()->archived()->create([
'workspace_id' => (int) $tenant->workspace_id,
'name' => 'Spec194 Archived Tenant',
]);
createUserWithTenant(
tenant: $archivedTenant,
user: $user,
role: 'owner',
workspaceRole: 'manager',
ensureDefaultMicrosoftProviderConnection: false,
);
visit(spec194SmokeLoginUrl($user, $tenant))
->waitForText('Dashboard')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs();
visit(FindingExceptionsQueue::getUrl(panel: 'admin').'?exception='.(int) $pendingException->getKey())
->waitForText('Focused review lane')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Approve exception')
->assertSee('Reject exception');
visit(FindingExceptionResource::getUrl('view', ['record' => $approvedException], tenant: $tenant))
->waitForText('Related context')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Renew exception')
->assertSee('Revoke exception');
visit(TenantReviewResource::tenantScopedUrl('view', ['record' => $review], $tenant))
->waitForText('Related context')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->click('Publish review')
->waitForText('Publication reason')
->click('Cancel')
->click('[aria-label="More"]')
->assertSee('Refresh review')
->assertSee('Export executive pack')
->click('[aria-label="Danger"]')
->click('Archive review')
->waitForText('Archive reason')
->click('Cancel')
->assertSee('Publish review')
->assertSee('Evidence snapshot');
visit(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant))
->waitForText('Related context')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->click('Refresh evidence')
->waitForText('Confirm')
->click('Cancel')
->click('Expire snapshot')
->waitForText('Expiry reason')
->click('Cancel')
->assertSee('Refresh evidence')
->assertSee('Expire snapshot');
visit(TenantResource::getUrl('view', ['record' => $tenant], panel: 'admin'))
->waitForText('Related context')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->click('[aria-label="Lifecycle"]')
->click('Archive')
->waitForText('Archive reason')
->click('Cancel')
->assertSee('Lifecycle');
visit(TenantResource::getUrl('edit', ['record' => $tenant], panel: 'admin'))
->waitForText('Related context')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Lifecycle');
visit(TenantResource::getUrl('view', ['record' => $archivedTenant], panel: 'admin'))
->waitForText('Related context')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Lifecycle');
visit(TenantResource::getUrl('edit', ['record' => $archivedTenant], panel: 'admin'))
->waitForText('Related context')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Lifecycle');
});
it('smokes system run triage semantics without javascript errors', function (): void {
$failedRun = OperationRun::factory()->create([
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Failed->value,
'type' => 'inventory_sync',
]);
$runningRun = OperationRun::factory()->create([
'status' => OperationRunStatus::Running->value,
'outcome' => OperationRunOutcome::Pending->value,
'type' => 'inventory_sync',
'created_at' => now()->subMinutes(15),
'started_at' => now()->subMinutes(10),
]);
$platformUser = PlatformUser::factory()->create([
'capabilities' => [
PlatformCapabilities::ACCESS_SYSTEM_PANEL,
PlatformCapabilities::OPERATIONS_VIEW,
PlatformCapabilities::OPERATIONS_MANAGE,
],
'is_active' => true,
]);
auth('web')->logout();
$this->flushSession();
$this->actingAs($platformUser, 'platform');
visit(SystemOperationRunLinks::view($failedRun))
->waitForText('Operation #'.(int) $failedRun->getKey())
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Retry')
->assertSee('Mark investigated')
->assertDontSee('Cancel');
visit(SystemOperationRunLinks::view($runningRun))
->waitForText('Operation #'.(int) $runningRun->getKey())
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Mark investigated')
->assertSee('Cancel');
});