create(); $this->actingAs($user); $contextTenant = Tenant::create([ 'tenant_id' => 'tenant-context', 'name' => 'Context Tenant', ]); [$user, $contextTenant] = createUserWithTenant($contextTenant, $user, role: 'owner'); $this->actingAs($user); Filament::setTenant($contextTenant, true); Livewire::test(CreateTenant::class) ->fillForm([ 'name' => 'Contoso', 'environment' => 'other', 'tenant_id' => 'tenant-guid', 'domain' => 'contoso.com', ]) ->call('create') ->assertHasNoFormErrors(); $tenant = Tenant::query()->where('tenant_id', 'tenant-guid')->first(); expect($tenant)->not->toBeNull(); $connection = ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'provider' => 'microsoft', 'entra_tenant_id' => (string) $tenant->tenant_id, 'is_default' => true, 'status' => 'enabled', ]); ProviderCredential::factory()->create([ 'provider_connection_id' => (int) $connection->getKey(), 'type' => 'client_secret', 'payload' => [ 'client_id' => 'client-id', 'client_secret' => 'client-secret', ], ]); Livewire::test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->callAction('verify'); $run = OperationRun::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('type', 'provider.connection.check') ->latest('id') ->first(); expect($run)->not->toBeNull() ->and($run?->status)->toBe('queued') ->and($run?->outcome)->toBe('pending') ->and($run?->context['provider_connection_id'] ?? null)->toBe((int) $connection->getKey()); $notificationActionUrls = collect(session('filament.notifications', [])) ->flatMap(static fn (array $notification): array => is_array($notification['actions'] ?? null) ? $notification['actions'] : []) ->pluck('url') ->filter(static fn (mixed $url): bool => is_string($url) && trim($url) !== '') ->values() ->all(); expect($notificationActionUrls)->toContain(OperationRunLinks::tenantlessView($run)); Queue::assertPushed(\App\Jobs\ProviderConnectionHealthCheckJob::class, 1); $this->assertDatabaseMissing('audit_logs', [ 'tenant_id' => $tenant->id, 'action' => 'tenant.config.verified', ]); }); test('verify configuration creates a blocked run when default connection credentials are missing', function () { Queue::fake(); $user = User::factory()->create(); $tenant = Tenant::factory()->create([ 'tenant_id' => 'tenant-error', 'name' => 'Error Tenant', 'status' => 'active', ]); [$user, $tenant] = createUserWithTenant(tenant: $tenant, user: $user, role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); $connection = ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'provider' => 'microsoft', 'entra_tenant_id' => (string) $tenant->tenant_id, 'is_default' => true, 'status' => 'connected', ]); Livewire::test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->callAction('verify'); $run = OperationRun::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('type', 'provider.connection.check') ->latest('id') ->first(); expect($run)->not->toBeNull() ->and($run?->outcome)->toBe('blocked') ->and($run?->context['provider_connection_id'] ?? null)->toBe((int) $connection->getKey()) ->and($run?->context['reason_code'] ?? null)->toBe(ProviderReasonCodes::ProviderCredentialMissing); expect(VerificationReportSchema::isValidReport($run?->context['verification_report'] ?? []))->toBeTrue(); Queue::assertNothingPushed(); }); test('tenant detail shows required permissions with statuses', function () { $user = User::factory()->create(); $this->actingAs($user); $tenant = Tenant::create([ 'tenant_id' => 'tenant-ui', 'name' => 'UI Tenant', ]); [$user, $tenant] = createUserWithTenant($tenant, $user, role: 'owner'); $this->actingAs($user); config(['intune_permissions.granted_stub' => []]); $permissions = config('intune_permissions.permissions', []); $firstKey = $permissions[0]['key'] ?? 'DeviceManagementConfiguration.ReadWrite.All'; TenantPermission::create([ 'tenant_id' => $tenant->id, 'permission_key' => $firstKey, 'status' => 'ok', ]); $response = $this->get(route('filament.admin.resources.tenants.view', array_merge(filamentTenantRouteParams($tenant), ['record' => $tenant]))); $response->assertOk(); $response->assertSee('Actions'); $response->assertSee($firstKey); $response->assertSee('ok'); $response->assertSee('Missing'); }); test('tenant list shows Open in Entra action', function () { $user = User::factory()->create(); $this->actingAs($user); $tenant = Tenant::create([ 'tenant_id' => 'tenant-ui-list', 'name' => 'UI Tenant List', 'app_client_id' => 'client-123', ]); [$user, $tenant] = createUserWithTenant($tenant, $user, role: 'owner'); $this->actingAs($user); $response = $this->get(route('filament.admin.resources.tenants.index', filamentTenantRouteParams($tenant))); $response->assertOk(); $response->assertSee('Open in Entra'); }); test('tenant can be deactivated from the tenant detail action menu', function () { $user = User::factory()->create(); $this->actingAs($user); $tenant = Tenant::create([ 'tenant_id' => 'tenant-ui-deactivate', 'name' => 'UI Tenant Deactivate', ]); [$user, $tenant] = createUserWithTenant($tenant, $user, role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); Livewire::test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->mountAction('archive') ->callMountedAction() ->assertHasNoActionErrors(); $this->assertSoftDeleted('tenants', ['id' => $tenant->id]); });