browser()->timeout(60_000); beforeEach(function (): void { Storage::fake('exports'); }); it('Spec386 smokes the blocked review publication resolution entry point', function (): void { [$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager'); $environment->forceFill(['name' => 'Spec386 Browser Resolution'])->save(); $review = composeEnvironmentReviewForTest( $environment, $user, seedPartialEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0), ); $review->forceFill([ 'status' => EnvironmentReviewStatus::Draft->value, 'published_at' => null, 'published_by_user_id' => null, ])->save(); spec386AuthenticateBrowser($this, $user, $environment); $page = visit(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $review], $environment)) ->resize(1236, 900) ->waitForText('Resolve publication blockers') ->assertSee('Resolve publication blockers') ->click('Resolve publication blockers') ->waitForText('Review can\'t be published yet') ->assertSee('Why publication is blocked') ->assertSee('Next safe action') ->assertSee('TenantPilot will update the missing required reports. It will not publish the review.') ->assertSee('Publication preparation') ->assertSee('Update required reports') ->assertSee('Required reports') ->assertSee('Permission posture') ->assertSee('Technical proof and operation history') ->assertSee('Back to review') ->assertDontSee('Cancel resolution') ->assertDontSee('Report-backed evidence') ->click('Update required reports') ->waitForText('TenantPilot will update the missing required reports. This will not publish the review.') ->assertSee('TenantPilot will update the missing required reports. This will not publish the review.') ->click('Cancel') ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $page->screenshot(true, spec386BrowserScreenshotName('01-resolution-page-desktop')); spec386CopyBrowserScreenshot('01-resolution-page-desktop'); $mobilePage = $page ->resize(390, 844) ->waitForText('Publication preparation') ->assertSee('Update required reports') ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $mobilePage->screenshot(true, spec386BrowserScreenshotName('02-resolution-page-mobile')); spec386CopyBrowserScreenshot('02-resolution-page-mobile'); }); function spec386BrowserScreenshotName(string $name): string { return 'spec386-review-publication-resolution-'.$name; } function spec386CopyBrowserScreenshot(string $name): void { $filename = spec386BrowserScreenshotName($name).'.png'; $primarySource = base_path('tests/Browser/Screenshots/'.$filename); $fallbackSource = \Pest\Browser\Support\Screenshot::path($filename); $targetDirectory = repo_path('specs/386-review-publication-resolution-workflow-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'); } } function spec386AuthenticateBrowser(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); }