browser()->timeout(60_000); beforeEach(function (): void { Storage::fake('exports'); }); it('Spec350 smokes the shared resolution path from workspace guidance into review detail', function (): void { [$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager'); $environment->forceFill(['name' => 'Spec350 Browser Blocked'])->save(); [$review] = spec350BrowserCreatePublishedReviewWithPack( $environment, $user, seedPartialEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0), [ 'publish_blockers' => ['Operator approval note is still missing.'], ], [ 'include_pii' => false, 'include_operations' => true, ], 'review-packs/spec350-browser-blocked.zip', markReady: false, ); spec350AuthenticateBrowser($this, $user, $environment); $detailUrl = EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $review], $environment) .'?'.http_build_query([ CustomerReviewWorkspace::DETAIL_CONTEXT_QUERY_KEY => 1, 'source_surface' => CustomerReviewWorkspace::SOURCE_SURFACE, 'tenant_filter_id' => (int) $environment->getKey(), ]); $page = visit(CustomerReviewWorkspace::environmentFilterUrl($environment)) ->resize(1236, 900) ->waitForText('What is the current review pack output state?') ->assertSee('Output not customer-ready') ->assertSee('Create next review') ->assertSee('Evidence basis incomplete') ->assertSee('Technical details') ->click('[data-testid="customer-review-primary-action"]') ->waitForText('Create next review?') ->assertSee('Create next review?') ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $page->screenshot(true, spec350BrowserScreenshotName('01-workspace-blocked')); spec350CopyBrowserScreenshot('01-workspace-blocked'); $page = visit($detailUrl) ->waitForText('Output not customer-ready') ->assertSee('Review limitations below') ->assertSee('You are already on the review detail for this output.') ->assertDontSee('Open evidence basis') ->assertDontSee('Open operation proof') ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $page->screenshot(true, spec350BrowserScreenshotName('02-detail-context')); spec350CopyBrowserScreenshot('02-detail-context'); }); function spec350BrowserScreenshotName(string $name): string { return 'spec350-operator-resolution-guidance-'.$name; } function spec350CopyBrowserScreenshot(string $name): void { $filename = spec350BrowserScreenshotName($name).'.png'; $source = base_path('tests/Browser/Screenshots/'.$filename); $targetDirectory = repo_path('specs/350-operator-resolution-guidance-framework-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.$name.'.png'); } } function spec350AuthenticateBrowser(mixed $test, User $user, ManagedEnvironment $environment): void { $workspaceId = (int) $environment->workspace_id; $test->actingAs($user)->withSession([ WorkspaceContext::SESSION_KEY => $workspaceId, WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [ (string) $workspaceId => (int) $environment->getKey(), ], ]); session()->put(WorkspaceContext::SESSION_KEY, $workspaceId); session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [ (string) $workspaceId => (int) $environment->getKey(), ]); setAdminPanelContext($environment); } /** * @param array $summaryOverrides * @param array $packOptions * @return array{0: EnvironmentReview, 1: ReviewPack} */ function spec350BrowserCreatePublishedReviewWithPack( ManagedEnvironment $environment, User $user, EvidenceSnapshot $snapshot, array $summaryOverrides = [], array $packOptions = [], string $filePath = 'review-packs/spec350-browser-review-pack.zip', bool $markReady = true, ): array { $review = composeEnvironmentReviewForTest($environment, $user, $snapshot); $summary = array_replace_recursive( is_array($review->summary) ? $review->summary : [], [ 'control_interpretation' => [ 'version_key' => ComplianceEvidenceMappingV1::VERSION_KEY, 'controls' => [ [ 'control_key' => 'customer-output', 'title' => 'Customer output', 'readiness_bucket' => $markReady ? 'evidence_on_record' : 'review_recommended', 'readiness_label' => $markReady ? 'Evidence on record' : 'Review recommended', 'primary_reason' => $markReady ? 'Evidence path is complete.' : 'Evidence basis needs review.', 'recommended_next_action' => $markReady ? 'Open the current customer review pack.' : 'Review the evidence basis before sharing.', ], ], ], ], $summaryOverrides, ); Storage::disk('exports')->put($filePath, 'PK-spec350-browser-test'); $review->forceFill([ 'status' => EnvironmentReviewStatus::Published->value, 'completeness_state' => $markReady ? EnvironmentReviewCompletenessState::Complete->value : (string) $review->completeness_state, 'summary' => $summary, 'generated_at' => now()->subMinutes(5), 'published_at' => now()->subMinutes(3), 'published_by_user_id' => (int) $user->getKey(), ])->save(); if ($markReady) { $review = markEnvironmentReviewCustomerSafeReady($review); } $pack = ReviewPack::factory()->ready()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'environment_review_id' => (int) $review->getKey(), 'evidence_snapshot_id' => (int) $snapshot->getKey(), 'initiated_by_user_id' => (int) $user->getKey(), 'options' => array_replace([ 'include_pii' => false, 'include_operations' => true, ], $packOptions), 'file_path' => $filePath, 'file_disk' => 'exports', 'generated_at' => now()->subMinutes(4), ]); $review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save(); return [$review->fresh(['tenant', 'evidenceSnapshot', 'currentExportReviewPack.operationRun', 'operationRun']), $pack]; }