browser()->timeout(60_000); it('Spec389 smokes review publication resolution intake from governance inbox to preparation detail', function (): void { [$user, $environment] = spec389GovernanceInboxBrowserFixture(); spec389AuthenticateGovernanceInboxBrowser($this, $user, $environment); $page = visit(GovernanceInbox::getUrl(panel: 'admin', parameters: [ 'family' => 'review_publication_resolution', 'status' => 'needs_attention', 'updated' => 'last_24_hours', ])) ->resize(1366, 920) ->waitForText('Governance Inbox') ->assertSee('Review publication work') ->assertSee('Status: Needs attention') ->assertSee('Updated: Last 24 hours') ->assertSee('Review cannot be published yet') ->assertSee('A current evidence snapshot is required.') ->assertSee('Continue preparation') ->assertSee('Review publication status') ->assertDontSee('Operation #') ->assertDontSee('OperationRun') ->assertScript('(() => { const sourceDetail = document.querySelector("[data-testid=\"governance-inbox-source-detail\"]"); const filters = document.querySelector("[data-testid=\"governance-inbox-review-publication-filters\"]"); const active = filters?.querySelectorAll("a[aria-current=\"page\"]") || []; return sourceDetail?.open === true && filters !== null && [...active].some((link) => link.textContent.includes("Needs attention")) && [...active].some((link) => link.textContent.includes("Last 24 hours")) && document.documentElement.scrollWidth <= window.innerWidth; })()', true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $page->screenshot(true, spec389GovernanceInboxScreenshot('review-publication-inbox')); spec389CopyGovernanceInboxScreenshot('review-publication-inbox'); $page ->resize(390, 844) ->assertSee('Review cannot be published yet') ->assertSee('Continue preparation') ->assertScript('document.documentElement.scrollWidth <= window.innerWidth', true); $page->screenshot(true, spec389GovernanceInboxScreenshot('review-publication-inbox-mobile')); spec389CopyGovernanceInboxScreenshot('review-publication-inbox-mobile'); $page->resize(1366, 920); $page->script('(() => { const link = [...document.querySelectorAll("a[href*=\'resolve-publication\']")] .find((element) => element.textContent.includes("Continue preparation")); link?.click(); })()'); $detailPage = $page ->waitForText('Publication preparation') ->assertSee('Collect evidence') ->assertSee('will not publish the review') ->assertDontSee('OperationRun') ->assertDontSee('Artifact proof') ->assertScript('window.location.pathname.includes("/resolve-publication")', true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $detailPage->screenshot(true, spec389GovernanceInboxScreenshot('review-publication-resolution-detail')); spec389CopyGovernanceInboxScreenshot('review-publication-resolution-detail'); visit(CustomerReviewWorkspace::environmentFilterUrl($environment)) ->resize(1366, 920) ->waitForText('Customer Review Workspace') ->assertDontSee('Review publication work') ->assertDontSee('Resolution Case') ->assertDontSee('OperationRun') ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); }); /** * @return array{0: User, 1: ManagedEnvironment, 2: EnvironmentReview, 3: ReviewPublicationResolutionCase} */ function spec389GovernanceInboxBrowserFixture(): array { $environment = ManagedEnvironment::factory()->active()->create([ 'name' => 'Spec389 Browser Publication', ]); [$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner', workspaceRole: 'owner'); $snapshot = spec389GovernanceInboxBrowserEvidence($environment); $review = composeEnvironmentReviewForTest($environment, $user, $snapshot); $case = app(ReviewPublicationResolutionService::class)->openOrResume($review, $user); $case->loadMissing('steps'); foreach ($case->steps as $step) { $step->forceFill([ 'status' => $step->step_key === ReviewPublicationResolutionStepKey::CollectEvidenceSnapshot->value ? ReviewPublicationResolutionStepStatus::Actionable->value : ReviewPublicationResolutionStepStatus::Completed->value, 'summary' => array_replace(is_array($step->summary) ? $step->summary : [], [ 'state_description' => $step->step_key === ReviewPublicationResolutionStepKey::CollectEvidenceSnapshot->value ? 'A current evidence snapshot is required.' : 'Requirement is satisfied.', ]), 'operation_run_id' => null, ])->save(); } $case->forceFill([ 'status' => ReviewPublicationResolutionCaseStatus::InProgress->value, 'current_step_key' => ReviewPublicationResolutionStepKey::CollectEvidenceSnapshot->value, 'updated_at' => now(), ])->save(); return [$user, $environment, $review->fresh(), $case->fresh('steps')]; } function spec389GovernanceInboxBrowserEvidence(ManagedEnvironment $environment): EvidenceSnapshot { return seedPartialEnvironmentReviewEvidence( tenant: $environment, findingCount: 0, driftCount: 0, operationRunCount: 0, ); } function spec389AuthenticateGovernanceInboxBrowser( mixed $test, User $user, ManagedEnvironment $environment, ): void { $workspaceId = (int) $environment->workspace_id; $session = [ WorkspaceContext::SESSION_KEY => $workspaceId, WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [ (string) $workspaceId => (int) $environment->getKey(), ], ]; $test->actingAs($user)->withSession($session); foreach ($session as $key => $value) { session()->put($key, $value); } setAdminPanelContext($environment); } function spec389GovernanceInboxScreenshot(string $name): string { return 'spec389-governance-inbox-resolution-'.$name; } function spec389CopyGovernanceInboxScreenshot(string $name): void { $filename = spec389GovernanceInboxScreenshot($name).'.png'; $primarySource = base_path('tests/Browser/Screenshots/'.$filename); $fallbackSource = \Pest\Browser\Support\Screenshot::path($filename); $targetDirectory = repo_path('specs/389-governance-inbox-resolution-intake-v1/artifacts/screenshots'); if (! is_dir($targetDirectory)) { @mkdir($targetDirectory, 0755, true); } $source = null; for ($attempt = 0; $attempt < 50 && $source === null; $attempt++) { foreach ([$primarySource, $fallbackSource] as $candidate) { if (is_file($candidate)) { $source = $candidate; break; } } if ($source !== null) { break; } usleep(100_000); clearstatcache(true, $primarySource); clearstatcache(true, $fallbackSource); } if (is_string($source) && is_file($source) && is_dir($targetDirectory) && is_writable($targetDirectory)) { @copy($source, $targetDirectory.DIRECTORY_SEPARATOR.$name.'.png'); } }