browser()->timeout(60_000); it('Spec346 smokes the governance inbox summary-first hierarchy and lane scanability', function (): void { [$user, $environmentA, $environmentB] = spec346GovernanceInboxBrowserFixture(); spec346AuthenticateGovernanceInboxBrowser($this, $user, $environmentA); $page = visit(GovernanceInbox::getUrl(panel: 'admin')) ->resize(1440, 1100) ->waitForText('Governance Inbox') ->assertSee('Daily operator queue for governance follow-up, accepted risk, evidence gaps, and review handoff.') ->assertSee('Open governance work') ->assertSee('Next recommended action') ->assertSee('Triage Finding #') ->assertSee('Triage finding') ->assertSee('View lane') ->assertSee('Primary inbox lanes') ->assertSee('Needs triage') ->assertSee('Requires decision') ->assertSee('Risk / exception review') ->assertSee('Evidence required') ->assertSee('Blocked') ->assertSee('Recently resolved') ->assertSee('More context') ->assertSee('Source detail') ->assertDontSee('Primary next action') ->assertDontSee('Decision workbench') ->assertDontSee('Queue context') ->assertScript('document.querySelector("[data-testid=\"governance-inbox-diagnostics\"]")?.open === false', true) ->assertScript('document.querySelectorAll("[data-testid^=\"governance-inbox-item-\"] details[open]").length === 0', true) ->assertScript('(() => { const summary = document.querySelector("[data-testid=\"governance-inbox-operator-summary\"]"); const nextAction = document.querySelector("[data-testid=\"governance-inbox-next-action\"]"); const lanes = document.querySelector("[data-testid=\"governance-inbox-lanes\"]"); const sourceDetail = document.querySelector("[data-testid=\"governance-inbox-source-detail\"]"); if (! summary || ! nextAction || ! lanes || ! sourceDetail) { return false; } return summary.getBoundingClientRect().top < nextAction.getBoundingClientRect().top && nextAction.getBoundingClientRect().top < lanes.getBoundingClientRect().top && lanes.getBoundingClientRect().top < sourceDetail.getBoundingClientRect().top; })()', true) ->assertScript('(() => { const nextAction = document.querySelector("[data-testid=\"governance-inbox-next-action\"]"); const button = nextAction?.querySelector("a[href]"); if (! nextAction || ! button) { return false; } const rect = nextAction.getBoundingClientRect(); const buttonRect = button.getBoundingClientRect(); return rect.top >= 0 && rect.top < window.innerHeight && buttonRect.top < window.innerHeight && nextAction.textContent.includes("Next recommended action") && nextAction.textContent.includes("Triage Finding #"); })()', true) ->assertScript('document.documentElement.scrollWidth <= window.innerWidth', true) ->assertSee($environmentA->name) ->assertSee($environmentB->name) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $page->script('window.scrollTo(0, 0);'); $page->screenshot(true, spec346GovernanceInboxScreenshot('governance-inbox--summary-first')); spec346CopyBrowserScreenshot('governance-inbox--summary-first'); $page->resize(390, 844); $page->script('window.scrollTo(0, 0);'); $page ->assertScript('document.documentElement.scrollWidth <= window.innerWidth', true) ->assertScript('(() => { const nextAction = document.querySelector("[data-testid=\"governance-inbox-next-action\"]"); const firstItem = document.querySelector("[data-testid^=\"governance-inbox-item-\"]"); if (! nextAction || ! firstItem) { return false; } const nextRect = nextAction.getBoundingClientRect(); return nextRect.top >= 0 && nextRect.top < window.innerHeight && nextAction.textContent.includes("Triage Finding #") && firstItem.textContent.includes("Reason") && firstItem.textContent.includes("Impact") && firstItem.textContent.includes("More context"); })()', true) ->screenshot(true, spec346GovernanceInboxScreenshot('governance-inbox--mobile-density')); spec346CopyBrowserScreenshot('governance-inbox--mobile-density'); $hashPage = visit(GovernanceInbox::getUrl(panel: 'admin').'#lane-needs_triage') ->resize(1440, 1100) ->waitForText('Needs triage'); $hashPage->script('async () => { await new Promise((resolve) => setTimeout(resolve, 250)); return true; }'); $hashPage ->assertScript('(() => { const lane = document.getElementById("lane-needs_triage"); if (! lane) { return false; } const rect = lane.getBoundingClientRect(); return window.location.hash === "#lane-needs_triage" && window.scrollY > 0 && rect.top >= 0 && rect.top < Math.min(window.innerHeight * 0.35, 260); })()', true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs() ->screenshot(true, spec346GovernanceInboxScreenshot('governance-inbox--hash-lane-needs-triage')); spec346CopyBrowserScreenshot('governance-inbox--hash-lane-needs-triage'); } ); it('Spec346 smokes the filtered governance inbox URL contract', function (): void { [$user, $environmentA, $environmentB] = spec346GovernanceInboxBrowserFixture(); spec346AuthenticateGovernanceInboxBrowser($this, $user, $environmentA); $page = visit(GovernanceInbox::getUrl(panel: 'admin', parameters: [ 'environment_id' => (int) $environmentA->getKey(), 'family' => 'stale_operations', ])) ->waitForText('Environment filter:') ->assertSee('Environment filter: '.$environmentA->name) ->assertSee('Next recommended action') ->assertSee('Open terminal operation proof') ->assertSee('Blocked') ->assertDontSee($environmentB->name) ->assertScript('window.location.search.includes("environment_id='.(int) $environmentA->getKey().'")', true) ->assertScript('window.location.search.includes("family=stale_operations")', true) ->assertScript('! window.location.search.includes("tenant=")', true) ->assertScript('! window.location.search.includes("tenant_id=")', true) ->assertScript('! window.location.search.includes("managed_environment_id=")', true) ->assertScript('! window.location.search.includes("tenant_scope=")', true) ->assertScript('! window.location.search.includes("tableFilters")', true) ->assertScript('(() => { const sourceDetail = document.querySelector("[data-testid=\"governance-inbox-source-detail\"]"); const activeFamily = sourceDetail?.querySelector("a[aria-current=\"page\"]"); return sourceDetail?.open === true && activeFamily?.textContent.includes("Operations follow-up") && activeFamily?.href.includes("family=stale_operations") && activeFamily?.hash === "#source-detail"; })()', true) ->assertScript('(() => { const active = document.querySelector("[data-testid=\"governance-inbox-summary-active-counts\"]"); const clear = document.querySelector("[data-testid=\"governance-inbox-summary-clear-counts\"]"); if (! active || ! clear) { return false; } return active.textContent.includes("Blocked") && clear.textContent.includes("Needs triage") && clear.textContent.includes("Requires decision") && clear.textContent.includes("Risk / exception review") && clear.textContent.includes("Evidence required") && (clear.textContent.match(/Clear/g) || []).length >= 4 && document.querySelector("[data-testid=\"governance-inbox-lane-needs_triage\"]") === null && document.querySelector("[data-testid=\"governance-inbox-lane-blocked\"]") !== null; })()', true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $page->screenshot(true, spec346GovernanceInboxScreenshot('governance-inbox--filtered')); spec346CopyBrowserScreenshot('governance-inbox--filtered'); } ); it('Spec346 smokes a representative primary action hop and returns to the same inbox scope', function (): void { [$user, $environmentA] = spec346GovernanceInboxBrowserFixture(); spec346AuthenticateGovernanceInboxBrowser($this, $user, $environmentA); $expectedQueuePath = json_encode((string) parse_url(FindingExceptionsQueue::getUrl(panel: 'admin'), PHP_URL_PATH), JSON_THROW_ON_ERROR); $page = visit(GovernanceInbox::getUrl(panel: 'admin', parameters: [ 'environment_id' => (int) $environmentA->getKey(), ])) ->waitForText('Environment filter:') ->assertSee('Blocked') ->assertSee('Review accepted risk') ->assertScript('(() => { const lane = document.querySelector("[data-testid=\"governance-inbox-lane-risk_exception_review\"]"); const link = [...(lane?.querySelectorAll("a[href]") || [])] .find((element) => element.textContent.includes("Review accepted risk")); return Boolean(link); })()', true); $page->script('(() => { const lane = document.querySelector("[data-testid=\"governance-inbox-lane-risk_exception_review\"]"); const link = [...(lane?.querySelectorAll("a[href]") || [])] .find((element) => element.textContent.includes("Review accepted risk")); link?.click(); })()'); $page ->waitForText('Finding Exceptions Queue') ->assertScript("window.location.pathname === {$expectedQueuePath}", true) ->assertScript('window.location.search.includes("environment_id='.(int) $environmentA->getKey().'")', true) ->assertScript('window.location.search.includes("exception=")', true) ->assertScript('! window.location.search.includes("tenant=")', true) ->assertScript('! window.location.search.includes("tenant_id=")', true) ->assertScript('! window.location.search.includes("managed_environment_id=")', true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $page->script('window.history.back();'); $page ->waitForText('Governance Inbox') ->waitForText('Environment filter: '.$environmentA->name) ->assertSee('Blocked') ->assertSee('Environment filter: '.$environmentA->name) ->assertScript('window.location.search.includes("environment_id='.(int) $environmentA->getKey().'")', true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs() ->screenshot(true, spec346GovernanceInboxScreenshot('governance-inbox--return-scope')); spec346CopyBrowserScreenshot('governance-inbox--return-scope'); } ); /** * @return array{0: User, 1: ManagedEnvironment, 2: ManagedEnvironment} */ function spec346GovernanceInboxBrowserFixture(): array { $environmentA = ManagedEnvironment::factory()->active()->create([ 'name' => 'Spec346 Browser Environment A', 'external_id' => 'spec346-browser-environment-a', ]); [$user, $environmentA] = createUserWithTenant( tenant: $environmentA, role: 'owner', workspaceRole: 'owner', ); $environmentB = ManagedEnvironment::factory()->active()->create([ 'workspace_id' => (int) $environmentA->workspace_id, 'name' => 'Spec346 Browser Environment B', 'external_id' => 'spec346-browser-environment-b', ]); createUserWithTenant( tenant: $environmentB, user: $user, role: 'owner', workspaceRole: 'owner', ); Finding::factory() ->for($environmentA) ->create([ 'workspace_id' => (int) $environmentA->workspace_id, 'status' => Finding::STATUS_NEW, 'owner_user_id' => null, 'assignee_user_id' => null, 'evidence_jsonb' => [], ]); Finding::factory() ->for($environmentA) ->assignedTo((int) $user->getKey()) ->ownedBy((int) $user->getKey()) ->create([ 'workspace_id' => (int) $environmentA->workspace_id, 'status' => Finding::STATUS_IN_PROGRESS, 'evidence_jsonb' => [], ]); Finding::factory() ->for($environmentB) ->assignedTo((int) $user->getKey()) ->ownedBy((int) $user->getKey()) ->create([ 'workspace_id' => (int) $environmentB->workspace_id, 'status' => Finding::STATUS_IN_PROGRESS, 'evidence_jsonb' => [ 'summary' => [ 'kind' => 'policy_snapshot', ], ], ]); $exceptionFinding = Finding::factory() ->for($environmentA) ->riskAccepted() ->create([ 'workspace_id' => (int) $environmentA->workspace_id, ]); FindingException::query()->create([ 'workspace_id' => (int) $environmentA->workspace_id, 'managed_environment_id' => (int) $environmentA->getKey(), 'finding_id' => (int) $exceptionFinding->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' => 'Spec346 browser accepted-risk support review', 'requested_at' => now()->subDay(), 'review_due_at' => now()->addDays(3), 'evidence_summary' => ['reference_count' => 0], ]); OperationRun::factory() ->forTenant($environmentA) ->create([ 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Failed->value, 'completed_at' => now()->subMinutes(10), ]); $backupHealthResolver = app(TenantBackupHealthResolver::class); $fingerprints = app(ManagedEnvironmentTriageReviewFingerprint::class); $fingerprint = $fingerprints->forBackupHealth($backupHealthResolver->assess($environmentA)); ManagedEnvironmentTriageReview::factory() ->for($environmentA) ->followUpNeeded() ->create([ 'workspace_id' => (int) $environmentA->workspace_id, 'reviewed_by_user_id' => (int) $user->getKey(), 'concern_family' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH, 'review_fingerprint' => $fingerprint['fingerprint'], 'review_snapshot' => $fingerprint['snapshot'], ]); spec346SeedBrowserRecentlyClosedDecision($environmentA, $user); return [$user, $environmentA, $environmentB]; } function spec346AuthenticateGovernanceInboxBrowser( mixed $test, User $user, ManagedEnvironment $rememberedEnvironment, ): void { $workspaceId = (int) $rememberedEnvironment->workspace_id; $session = [ WorkspaceContext::SESSION_KEY => $workspaceId, WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [ (string) $workspaceId => (int) $rememberedEnvironment->getKey(), ], ]; $test->actingAs($user)->withSession($session); foreach ($session as $key => $value) { session()->put($key, $value); } setAdminPanelContext($rememberedEnvironment); } function spec346GovernanceInboxScreenshot(string $name): string { return 'spec346-'.$name; } function spec346CopyBrowserScreenshot(string $name, ?string $targetFilename = null): void { $filename = spec346GovernanceInboxScreenshot($name).'.png'; $source = base_path('tests/Browser/Screenshots/'.$filename); $targetDirectory = repo_path('specs/346-governance-inbox-final-operator-workflow/artifacts/screenshots'); $targetFilename ??= $filename; 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_dir($targetDirectory)) { @mkdir($targetDirectory, 0755, true); } if (! is_dir($targetDirectory) || ! is_writable($targetDirectory)) { return; } if (is_file($source)) { @copy($source, $targetDirectory.DIRECTORY_SEPARATOR.$targetFilename); } } function spec346SeedBrowserRecentlyClosedDecision(ManagedEnvironment $environment, User $user): void { $finding = Finding::factory() ->for($environment) ->create([ 'workspace_id' => (int) $environment->workspace_id, 'status' => Finding::STATUS_IN_PROGRESS, ]); $exception = FindingException::query()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'finding_id' => (int) $finding->getKey(), 'requested_by_user_id' => (int) $user->getKey(), 'owner_user_id' => (int) $user->getKey(), 'status' => FindingException::STATUS_REJECTED, 'current_validity_state' => FindingException::VALIDITY_REJECTED, 'request_reason' => 'Browser recently closed decision', 'requested_at' => now()->subDays(5), 'review_due_at' => now()->subDays(2), 'rejected_at' => now()->subDay(), 'evidence_summary' => ['reference_count' => 0], ]); $decision = FindingExceptionDecision::query()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'finding_exception_id' => (int) $exception->getKey(), 'actor_user_id' => (int) $user->getKey(), 'decision_type' => FindingExceptionDecision::TYPE_REJECTED, 'reason' => 'Browser recently rejected closure reason', 'decided_at' => now()->subDay(), 'metadata' => [], ]); $exception->forceFill([ 'current_decision_id' => (int) $decision->getKey(), ])->save(); }