browser()->timeout(10_000); it('keeps stale verification warnings and the selected provider connection stable after refresh', function (): void { $workspace = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => '30303030-3030-3030-3030-303030303030', 'name' => 'Stale Verification Tenant', 'status' => Tenant::STATUS_ONBOARDING, ]); $user = User::factory()->create(['name' => 'Verification Owner']); createUserWithTenant( tenant: $tenant, user: $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false, ); $verifiedConnection = 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' => 'Previously verified connection', 'is_default' => true, 'status' => 'connected', ]); $selectedConnection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'dummy', 'entra_tenant_id' => (string) $tenant->tenant_id, 'display_name' => 'Current selected connection', 'is_default' => false, 'status' => 'connected', ]); $run = 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, 'context' => [ 'provider_connection_id' => (int) $verifiedConnection->getKey(), 'target_scope' => [ 'entra_tenant_id' => (string) $tenant->tenant_id, ], ], ]); $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) $selectedConnection->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()); $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('Verify access') ->assertSee('Status: Needs attention') ->assertSee('The selected provider connection has changed since this verification run. Start verification again to validate the current connection.') ->assertSee('Start verification') ->refresh() ->waitForText('The selected provider connection has changed since this verification run. Start verification again to validate the current connection.') ->assertNoJavaScriptErrors() ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]) ->assertSee('Status: Needs attention') ->assertSee('Start verification') ->click('Provider connection') ->assertScript($visibleSelectValue, (string) $selectedConnection->getKey()); }); it('preserves bootstrap revisit state and blocked activation guards after refresh', function (): void { $workspace = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'tenant_id' => '40404040-4040-4040-4040-404040404040', 'name' => 'Blocked Review Tenant', 'status' => Tenant::STATUS_ONBOARDING, ]); $user = User::factory()->create(['name' => 'Review 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' => 'Blocked review 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::Failed->value, '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' => [], ], ]), ], ]); $bootstrapRun = createInventorySyncOperationRun($tenant, [ 'workspace_id' => (int) $workspace->getKey(), 'status' => 'success', ]); $draft = createOnboardingDraft([ 'workspace' => $workspace, 'tenant' => $tenant, 'started_by' => $user, 'updated_by' => $user, 'current_step' => 'complete', '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()])); $activateButtonIsDisabled = <<<'JS' (() => { const button = [...document.querySelectorAll('button')].find((element) => element.textContent?.includes('Activate tenant')); return button?.disabled ?? null; })() JS; $openBootstrapStep = <<<'JS' (() => { const button = [...document.querySelectorAll('button')].find((element) => element.textContent?.includes('Bootstrap')); if (! button) { return false; } button.click(); return true; })() JS; $page ->assertNoJavaScriptErrors() ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]) ->assertSee('Complete') ->assertSee('Override blocked verification') ->assertSee('Blocked — 0/1 checks passed') ->assertSee('Started - 1 operation run(s) started') ->assertScript($activateButtonIsDisabled, true) ->refresh() ->waitForText('Override blocked verification') ->assertNoJavaScriptErrors() ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]) ->assertSee('Blocked — 0/1 checks passed') ->assertSee('Started - 1 operation run(s) started') ->assertScript($activateButtonIsDisabled, true) ->assertScript($openBootstrapStep, true) ->assertSee('Started 1 bootstrap run(s).'); });