set('graph.client_id', 'spec353-platform-client'); config()->set('graph.client_secret', 'spec353-platform-secret'); config()->set('graph.managed_environment_id', 'organizations'); }); function mockSpec353PermissionOverview(array $overview = []): void { mock(ManagedEnvironmentRequiredPermissionsViewModelBuilder::class, function ($mock) use ($overview): void { $mock->shouldReceive('build')->andReturn([ 'overview' => array_replace_recursive([ 'counts' => [ 'missing_application' => 0, 'missing_delegated' => 0, 'present' => 12, 'error' => 0, ], 'freshness' => [ 'last_refreshed_at' => now()->toIso8601String(), 'is_stale' => false, ], ], $overview), ]); }); } it('returns connection-missing guidance when no default provider connection exists', function (): void { [, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false); mockSpec353PermissionOverview(); $case = app(ProviderReadinessResolutionAdapter::class) ->forEnvironment($environment, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_INDEX); expect($case['key'])->toBe('provider_readiness.connection_missing') ->and(data_get($case, 'primary_action.url'))->toBe(ManagedEnvironmentLinks::providerConnectionsUrl($environment)) ->and((string) data_get($case, 'status'))->toBe(__('localization.provider_guidance.status_blocked')); }); it('distinguishes admin-consent blockers from missing-permission blockers', function (): void { [, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false); $connection = ProviderConnection::factory()->platform()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'is_default' => true, 'consent_status' => ProviderConsentStatus::Required->value, 'verification_status' => ProviderVerificationStatus::Unknown->value, ]); mockSpec353PermissionOverview([ 'counts' => [ 'missing_application' => 3, ], ]); $case = app(ProviderReadinessResolutionAdapter::class) ->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_VIEW); expect($case['key'])->toBe('provider_readiness.admin_consent_required') ->and((string) data_get($case, 'primary_action.label'))->toBe(__('localization.provider_guidance.action_open_admin_consent')) ->and((string) data_get($case, 'reason'))->toBe(__('localization.provider_guidance.admin_consent_required_reason')); }); it('returns required-permissions guidance when application permissions are missing', function (): void { [, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false); $connection = ProviderConnection::factory()->platform()->consentGranted()->verifiedHealthy()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'is_default' => true, ]); mockSpec353PermissionOverview([ 'counts' => [ 'missing_application' => 2, 'present' => 10, ], ]); $case = app(ProviderReadinessResolutionAdapter::class) ->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_VIEW); expect($case['key'])->toBe('provider_readiness.required_permissions_missing') ->and((string) data_get($case, 'primary_action.label'))->toBe(__('localization.provider_guidance.action_open_required_permissions')) ->and((string) data_get($case, 'reason'))->toBe(__('localization.provider_guidance.required_application_permissions_reason')); }); it('returns verification-required guidance when verification has not run yet', function (): void { [, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'is_default' => true, 'verification_status' => ProviderVerificationStatus::Unknown->value, 'last_health_check_at' => null, ]); mockSpec353PermissionOverview([ 'freshness' => [ 'last_refreshed_at' => null, 'is_stale' => true, ], ]); $case = app(ProviderReadinessResolutionAdapter::class) ->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_REQUIRED_PERMISSIONS); expect($case['key'])->toBe('provider_readiness.verification_required') ->and((string) data_get($case, 'primary_action.action_name'))->toBe('runProviderVerification') ->and((string) data_get($case, 'primary_action.label'))->toBe(__('localization.provider_guidance.action_run_provider_verification')); }); it('returns verification-failed guidance with an operation link when a failed run exists', function (): void { [, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'is_default' => true, 'verification_status' => ProviderVerificationStatus::Error->value, 'last_error_message' => 'Graph verification failed for this connection.', ]); $run = OperationRun::factory()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'type' => 'provider.connection.check', 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), ], ]); mockSpec353PermissionOverview(); $case = app(ProviderReadinessResolutionAdapter::class) ->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_VIEW); expect($case['key'])->toBe('provider_readiness.verification_failed') ->and((string) data_get($case, 'primary_action.url'))->toBe(OperationRunLinks::view($run, $environment)) ->and((string) data_get($case, 'reason'))->toContain('Graph verification failed'); }); it('returns a ready case when provider signals are satisfied', function (): void { [, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false); $connection = ProviderConnection::factory()->platform()->verifiedHealthy()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'is_default' => true, 'last_health_check_at' => now(), ]); mockSpec353PermissionOverview(); $case = app(ProviderReadinessResolutionAdapter::class) ->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_VIEW); expect($case['key'])->toBe('provider_readiness.ready') ->and((string) data_get($case, 'primary_action.url'))->toBe(ManagedEnvironmentLinks::viewUrl($environment)) ->and((string) data_get($case, 'status'))->toBe(__('localization.provider_guidance.status_ready')); });