TenantAtlas/apps/platform/tests/Browser/Spec354AcceptedRiskGuidanceSmokeTest.php
Ahmed Darrazi 68ff50d460
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 3m45s
feat: finding exceptions accepted risk resolution guidance v1 (spec 354)
Implemented the accepted risk resolution guidance, including the AcceptedRiskResolutionAdapter, guidance cards, and updated related Filament views. Added unit, feature, and browser tests.
2026-06-05 04:18:59 +02:00

308 lines
13 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\Monitoring\FindingExceptionsQueue;
use App\Filament\Resources\FindingExceptionResource;
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;
pest()->browser()->timeout(30_000);
uses(RefreshDatabase::class);
function spec354BrowserScreenshot(string $name): string
{
return 'spec354-'.$name;
}
function spec354CopyBrowserScreenshot(string $name): void
{
$filename = spec354BrowserScreenshot($name).'.png';
$source = base_path('tests/Browser/Screenshots/'.$filename);
$targetDirectory = repo_path('specs/354-finding-exceptions-accepted-risk-resolution-guidance-v1/artifacts/screenshots');
if (! is_dir($targetDirectory)) {
@mkdir($targetDirectory, 0755, true);
}
if (! is_file($source)) {
$source = \Pest\Browser\Support\Screenshot::path($filename);
}
for ($attempt = 0; $attempt < 10 && ! is_file($source); $attempt++) {
usleep(100_000);
clearstatcache(true, $source);
}
if (is_file($source) && is_dir($targetDirectory) && is_writable($targetDirectory)) {
@copy($source, $targetDirectory.DIRECTORY_SEPARATOR.$filename);
}
}
function spec354AuthenticateBrowser(mixed $test, User $user, ManagedEnvironment $tenant): void
{
$workspaceId = (int) $tenant->workspace_id;
$test->actingAs($user)->withSession([
WorkspaceContext::SESSION_KEY => $workspaceId,
WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [
(string) $workspaceId => (int) $tenant->getKey(),
],
]);
session()->put(WorkspaceContext::SESSION_KEY, $workspaceId);
session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
(string) $workspaceId => (int) $tenant->getKey(),
]);
setAdminPanelContext($tenant);
}
function spec354BrowserException(
ManagedEnvironment $tenant,
User $user,
array $findingAttributes = [],
array $exceptionAttributes = [],
?string $decisionType = FindingExceptionDecision::TYPE_APPROVED,
): FindingException {
$decisionMetadata = is_array($exceptionAttributes['decision_metadata'] ?? null)
? $exceptionAttributes['decision_metadata']
: [];
unset($exceptionAttributes['decision_metadata']);
$finding = Finding::factory()
->for($tenant)
->riskAccepted()
->create(array_merge([
'workspace_id' => (int) $tenant->workspace_id,
], $findingAttributes));
$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) $user->getKey(),
'owner_user_id' => (int) $user->getKey(),
'approved_by_user_id' => (int) $user->getKey(),
'status' => FindingException::STATUS_ACTIVE,
'current_validity_state' => FindingException::VALIDITY_VALID,
'request_reason' => 'Spec354 browser accepted-risk guidance',
'approval_reason' => 'Spec354 browser approval',
'requested_at' => now()->subDays(5),
'approved_at' => now()->subDays(4),
'effective_from' => now()->subDays(4),
'review_due_at' => now()->addDays(10),
'expires_at' => now()->addDays(30),
'evidence_summary' => ['reference_count' => 0],
], $exceptionAttributes));
if ($decisionType !== null) {
$decision = $exception->decisions()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'actor_user_id' => (int) $user->getKey(),
'decision_type' => $decisionType,
'reason' => 'Spec354 browser decision',
'metadata' => $decisionMetadata,
'decided_at' => now()->subDays(4),
]);
$exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save();
}
return $exception->fresh(['finding', 'tenant', 'owner', 'currentDecision', 'decisions.actor', 'evidenceReferences']);
}
it('smokes expiring queue guidance', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$expiring = spec354BrowserException($tenant, $user, exceptionAttributes: [
'review_due_at' => now()->addDay(),
'expires_at' => now()->addDays(2),
]);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $expiring->getKey(),
]))
->resize(1440, 1100)
->waitForText(__('localization.accepted_risk_guidance.title_expiring'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.review_focus_label'))
->assertSee(__('localization.accepted_risk_guidance.next_step_expiring'))
->assertSee(__('localization.accepted_risk_guidance.action_open_exception'))
->screenshot(true, spec354BrowserScreenshot('ui-026-finding-exceptions-queue-guidance'));
spec354CopyBrowserScreenshot('ui-026-finding-exceptions-queue-guidance');
});
it('smokes expired queue guidance', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$expired = spec354BrowserException($tenant, $user, exceptionAttributes: [
'review_due_at' => now()->subDays(2),
'expires_at' => now()->subDay(),
]);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $expired->getKey(),
]))
->waitForText(__('localization.accepted_risk_guidance.title_expired'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.impact_expired'));
});
it('smokes pending-renewal queue guidance while governance remains non-lapsed', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$pendingRenewalValid = spec354BrowserException($tenant, $user, exceptionAttributes: [
'status' => FindingException::STATUS_PENDING,
'current_validity_state' => FindingException::VALIDITY_VALID,
'decision_metadata' => [
'previous_review_due_at' => now()->addDays(10)->toIso8601String(),
'previous_expires_at' => now()->addDays(30)->toIso8601String(),
],
], decisionType: FindingExceptionDecision::TYPE_RENEWAL_REQUESTED);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $pendingRenewalValid->getKey(),
]))
->waitForText(__('localization.accepted_risk_guidance.title_pending_renewal'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.next_step_pending_renewal'));
});
it('smokes pending-renewal queue guidance when expired governance stays dominant', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$pendingRenewalExpired = spec354BrowserException($tenant, $user, exceptionAttributes: [
'status' => FindingException::STATUS_PENDING,
'current_validity_state' => FindingException::VALIDITY_VALID,
'decision_metadata' => [
'previous_review_due_at' => now()->subDays(2)->toIso8601String(),
'previous_expires_at' => now()->subDay()->toIso8601String(),
],
], decisionType: FindingExceptionDecision::TYPE_RENEWAL_REQUESTED);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $pendingRenewalExpired->getKey(),
]))
->waitForText(__('localization.accepted_risk_guidance.title_expired'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertDontSee(__('localization.accepted_risk_guidance.title_pending_renewal'));
});
it('smokes german queue localization without fake remediation copy', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$expiring = spec354BrowserException($tenant, $user, exceptionAttributes: [
'review_due_at' => now()->addDay(),
'expires_at' => now()->addDays(2),
]);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $expiring->getKey(),
'locale' => 'de',
]))
->waitForText('Was zu prüfen ist')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Das aktuelle Accepted-Risk-Governance-Fenster ist noch aktiv, läuft aber bald ab und muss geprüft werden.')
->assertDontSee('The current accepted-risk governance window is still active, but it is nearing expiry and needs review.')
->assertDontSee('Fix accepted risk');
});
it('smokes detail guidance hierarchy and pending-renewal queue continuity', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$incomplete = spec354BrowserException($tenant, $user, exceptionAttributes: [
'owner_user_id' => null,
'request_reason' => '',
'review_due_at' => null,
]);
$pendingRenewalValid = spec354BrowserException($tenant, $user, exceptionAttributes: [
'status' => FindingException::STATUS_PENDING,
'current_validity_state' => FindingException::VALIDITY_VALID,
'decision_metadata' => [
'previous_review_due_at' => now()->addDays(10)->toIso8601String(),
'previous_expires_at' => now()->addDays(30)->toIso8601String(),
],
], decisionType: FindingExceptionDecision::TYPE_RENEWAL_REQUESTED);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionResource::getUrl('view', ['record' => $incomplete], tenant: $tenant))
->resize(1440, 1100)
->waitForText(__('localization.accepted_risk_guidance.title_incomplete_governance'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.detail_missing_fields_label'))
->assertSee('Renew exception')
->screenshot(true, spec354BrowserScreenshot('ui-036-exception-detail-guidance'));
spec354CopyBrowserScreenshot('ui-036-exception-detail-guidance');
visit(FindingExceptionResource::getUrl('view', ['record' => $pendingRenewalValid], tenant: $tenant))
->waitForText(__('localization.accepted_risk_guidance.title_pending_renewal'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.primary_action_label'))
->assertSee(__('localization.accepted_risk_guidance.next_step_pending_renewal'))
->click(__('localization.accepted_risk_guidance.next_step_pending_renewal'))
->waitForText(__('localization.accepted_risk_guidance.title_pending_renewal'))
->assertSee($tenant->name);
});
it('smokes ready and missing-support detail semantics without fake remediation', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$ready = spec354BrowserException($tenant, $user);
$missingSupport = spec354BrowserException($tenant, $user, exceptionAttributes: [
'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT,
]);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionResource::getUrl('view', ['record' => $ready], tenant: $tenant))
->resize(1440, 1100)
->waitForText(__('localization.accepted_risk_guidance.title_ready'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.review_focus_label'))
->assertSee(__('localization.accepted_risk_guidance.impact_ready'))
->assertDontSee(__('localization.accepted_risk_guidance.primary_action_label'))
->assertDontSee(__('localization.accepted_risk_guidance.title_expired'));
visit(FindingExceptionResource::getUrl('view', ['record' => $missingSupport], tenant: $tenant))
->waitForText(__('localization.accepted_risk_guidance.title_missing_support'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.review_focus_label'))
->assertSee(__('localization.accepted_risk_guidance.next_step_missing_support'))
->assertDontSee(__('localization.accepted_risk_guidance.primary_action_label'))
->assertDontSee('Fix accepted risk')
->assertDontSee('Resolve risk');
});