bind(GraphClientInterface::class, fn () => new class implements GraphClientInterface { public function listPolicies(string $policyType, array $options = []): GraphResponse { return new GraphResponse(true, []); } public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse { return new GraphResponse(true, []); } public function getOrganization(array $options = []): GraphResponse { return new GraphResponse(true, ['value' => [['id' => $options['tenant'] ?? 'tenant']]], 200); } public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse { return new GraphResponse(true, []); } public function getServicePrincipalPermissions(array $options = []): GraphResponse { // Return all required permissions as granted return new GraphResponse(true, [ 'permissions' => collect(config('intune_permissions.permissions', [])) ->pluck('key') ->toArray(), ]); } public function request(string $method, string $path, array $options = []): GraphResponse { return new GraphResponse(true, []); } }); $user = User::factory()->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', 'app_client_id' => 'client-123', 'app_notes' => 'Test tenant', ]) ->call('create') ->assertHasNoFormErrors(); $tenant = Tenant::query()->where('tenant_id', 'tenant-guid')->first(); expect($tenant)->not->toBeNull(); Livewire::test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->callAction('verify'); $tenant->refresh(); expect($tenant->app_status)->toBe('ok'); $this->assertDatabaseHas('audit_logs', [ 'tenant_id' => $tenant->id, 'action' => 'tenant.config.verified', 'status' => 'success', ]); $this->assertDatabaseHas('tenant_permissions', [ 'tenant_id' => $tenant->id, 'status' => 'granted', ]); }); test('verify configuration records error when graph fails', function () { app()->bind(GraphClientInterface::class, fn () => new class implements GraphClientInterface { public function listPolicies(string $policyType, array $options = []): GraphResponse { return new GraphResponse(true, []); } public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse { return new GraphResponse(true, []); } public function getOrganization(array $options = []): GraphResponse { return new GraphResponse(false, [], 401, ['auth failed']); } public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse { return new GraphResponse(true, []); } public function getServicePrincipalPermissions(array $options = []): GraphResponse { // Return error for permissions check return new GraphResponse(false, [], 403, ['Permission denied']); } public function request(string $method, string $path, array $options = []): GraphResponse { return new GraphResponse(true, []); } }); $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); Livewire::test(ViewTenant::class, ['record' => $tenant->getRouteKey()]) ->callAction('verify'); $tenant->refresh(); expect($tenant->app_status)->toBe('error'); $this->assertDatabaseHas('audit_logs', [ 'tenant_id' => $tenant->id, 'action' => 'tenant.config.verified', 'status' => 'error', ]); $this->assertDatabaseHas('tenant_permissions', [ 'tenant_id' => $tenant->id, 'status' => 'error', ]); }); 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]); });