browser()->timeout(10_000); it('restores the canonical draft route, derived stage, and transient secret inputs after a refresh', function (): void { $workspace = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => '20202020-2020-2020-2020-202020202020', 'name' => 'Browser Refresh Tenant', 'status' => Tenant::STATUS_ONBOARDING, ]); $user = User::factory()->create(['name' => 'Browser Owner']); createUserWithTenant( tenant: $tenant, user: $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false, ); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => (string) $tenant->tenant_id, 'display_name' => 'Browser platform connection', 'is_default' => true, 'status' => 'connected', ]); $draft = createOnboardingDraft([ 'workspace' => $workspace, 'tenant' => $tenant, 'started_by' => $user, 'updated_by' => $user, 'current_step' => 'connection', 'state' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'tenant_name' => (string) $tenant->name, 'environment' => 'prod', 'provider_connection_id' => (int) $connection->getKey(), ], ]); $this->actingAs($user)->withSession([ WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(), ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey()); $visibleSelectValue = <<<'JS' (() => { const select = [...document.querySelectorAll('select')].find((element) => { const style = window.getComputedStyle(element); return style.display !== 'none' && style.visibility !== 'hidden'; }); return select?.value ?? null; })() JS; $page = visit(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])); $page ->assertNoJavaScriptErrors() ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]) ->assertSee('Onboarding draft') ->assertSee('Verify access') ->assertSee('Status: Not started') ->refresh() ->waitForText('Status: Not started') ->assertNoJavaScriptErrors() ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]) ->assertSee('Verify access') ->assertSee('Status: Not started') ->click('Provider connection') ->assertScript($visibleSelectValue, (string) $connection->getKey()) ->click('Create new connection') ->check('internal:label="Dedicated override"s') ->fill('[type="password"]', 'browser-only-secret') ->assertValue('[type="password"]', 'browser-only-secret') ->refresh() ->waitForText('Status: Not started') ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]) ->assertSee('Verify access') ->click('Provider connection') ->assertScript($visibleSelectValue, (string) $connection->getKey()) ->click('Create new connection') ->check('internal:label="Dedicated override"s') ->assertValue('[type="password"]', ''); }); it('auto-refreshes verification status and blocked assist visibility without a manual refresh', function (): void { $workspace = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => '50505050-5050-5050-5050-505050505050', 'name' => 'Browser Poll Verification Tenant', 'status' => Tenant::STATUS_ONBOARDING, ]); $user = User::factory()->create(['name' => 'Polling Owner']); createUserWithTenant( tenant: $tenant, user: $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false, ); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => (string) $tenant->tenant_id, 'display_name' => 'Polling verification connection', 'is_default' => true, 'status' => 'connected', ]); $run = OperationRun::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => (int) $tenant->getKey(), 'type' => 'provider.connection.check', 'status' => OperationRunStatus::Running->value, 'outcome' => OperationRunOutcome::Pending->value, 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), 'target_scope' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'entra_tenant_name' => (string) $tenant->name, ], ], ]); $draft = createOnboardingDraft([ 'workspace' => $workspace, 'tenant' => $tenant, 'started_by' => $user, 'updated_by' => $user, 'current_step' => 'verify', 'state' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'tenant_name' => (string) $tenant->name, 'provider_connection_id' => (int) $connection->getKey(), 'verification_operation_run_id' => (int) $run->getKey(), ], ]); $this->actingAs($user)->withSession([ WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(), ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey()); $page = visit(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])); $page ->assertNoJavaScriptErrors() ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]) ->assertSee('Verify access') ->assertSee('Status: In progress') ->assertSee('Status updates automatically about every 5 seconds.'); $run->forceFill([ 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Blocked->value, 'completed_at' => now(), 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), 'target_scope' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'entra_tenant_name' => (string) $tenant->name, ], 'verification_report' => VerificationReportWriter::build('provider.connection.check', [ [ 'key' => 'permissions.admin_consent', 'title' => 'Required application permissions', 'status' => 'fail', 'severity' => 'critical', 'blocking' => true, 'reason_code' => 'permission_denied', 'message' => 'Missing required Graph permissions.', 'evidence' => [], 'next_steps' => [], ], ]), ], ])->save(); $page ->wait(7) ->assertNoJavaScriptErrors() ->assertSee('Status: Blocked') ->assertSee('View required permissions'); }); it('auto-refreshes bootstrap checkpoint summaries without a manual refresh', function (): void { $workspace = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => '60606060-6060-6060-6060-606060606060', 'name' => 'Browser Poll Bootstrap Tenant', 'status' => Tenant::STATUS_ONBOARDING, ]); $user = User::factory()->create(['name' => 'Bootstrap Poll Owner']); createUserWithTenant( tenant: $tenant, user: $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false, ); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => (string) $tenant->tenant_id, 'display_name' => 'Polling bootstrap connection', 'is_default' => true, 'status' => 'connected', ]); $verificationRun = OperationRun::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => (int) $tenant->getKey(), 'type' => 'provider.connection.check', 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Succeeded->value, 'completed_at' => now(), 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), 'target_scope' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'entra_tenant_name' => (string) $tenant->name, ], ], ]); $bootstrapRun = createInventorySyncOperationRun($tenant, [ 'workspace_id' => (int) $workspace->getKey(), 'status' => 'running', ]); $draft = createOnboardingDraft([ 'workspace' => $workspace, 'tenant' => $tenant, 'started_by' => $user, 'updated_by' => $user, 'current_step' => 'bootstrap', 'state' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, 'tenant_name' => (string) $tenant->name, 'provider_connection_id' => (int) $connection->getKey(), 'verification_operation_run_id' => (int) $verificationRun->getKey(), 'bootstrap_operation_types' => ['inventory_sync'], 'bootstrap_operation_runs' => [ 'inventory_sync' => (int) $bootstrapRun->getKey(), ], ], ]); $this->actingAs($user)->withSession([ WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(), ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey()); $page = visit(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])); $page ->assertNoJavaScriptErrors() ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]) ->assertSee('Bootstrap (optional)') ->assertSee('Bootstrap is running across 1 operation run(s).'); $bootstrapRun->forceFill([ 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Succeeded->value, 'completed_at' => now(), ])->save(); $page ->wait(7) ->assertNoJavaScriptErrors() ->assertSee('Bootstrap completed across 1 operation run(s).'); });