8, 'assignments_total' => 12, 'high_privilege_assignments' => 5, ], $summaryOverrides ?? []); return StoredReport::query()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'report_type' => StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES, 'fingerprint' => hash('sha256', (string) now()->timestamp), 'payload' => [ 'provider_key' => 'microsoft', 'domain' => 'entra.admin_roles', 'measured_at' => now()->toIso8601String(), 'role_definitions' => [], 'role_assignments' => [], 'totals' => $totals, 'high_privilege' => [ [ 'role_display_name' => 'Global Administrator', 'role_template_id' => '62e90394-69f5-4237-9190-012177145e10', 'principal_id' => 'user-1', 'principal_display_name' => 'Admin User', 'assignment_scope' => '/', 'severity' => 'critical', ], ], ], ]); } // --------------------------------------------------------------------------- // Widget renders with report data // --------------------------------------------------------------------------- it('renders with report data showing timestamp and high-privilege count', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); Filament::setTenant($tenant, true); createAdminRolesReport($tenant, [ 'high_privilege_assignments' => 7, ]); Livewire::actingAs($user) ->test(AdminRolesSummaryWidget::class, ['record' => $tenant]) ->assertSee('Entra admin roles') ->assertSee('High-privilege assignments') ->assertSee('7') ->assertSee('Last scan') ->assertSuccessful(); }); // --------------------------------------------------------------------------- // Empty state // --------------------------------------------------------------------------- it('renders empty state when no report exists', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(AdminRolesSummaryWidget::class, ['record' => $tenant]) ->assertSee('No scan performed yet.') ->assertDontSee('Last scan') ->assertSuccessful(); }); // --------------------------------------------------------------------------- // Scan now — dispatches job // --------------------------------------------------------------------------- it('dispatches ScanEntraAdminRolesJob when user has ENTRA_ROLES_MANAGE', function (): void { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'owner'); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(AdminRolesSummaryWidget::class, ['record' => $tenant]) ->call('scanNow') ->assertSuccessful(); Queue::assertPushed(ScanEntraAdminRolesJob::class, function (ScanEntraAdminRolesJob $job) use ($tenant, $user): bool { return $job->tenantId === (int) $tenant->getKey() && $job->workspaceId === (int) $tenant->workspace_id && $job->initiatorUserId === (int) $user->getKey(); }); }); // --------------------------------------------------------------------------- // Scan now — RBAC enforcement (readonly cannot scan) // --------------------------------------------------------------------------- it('returns 403 when readonly user tries to scan', function (): void { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'readonly'); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(AdminRolesSummaryWidget::class, ['record' => $tenant]) ->call('scanNow') ->assertForbidden(); Queue::assertNotPushed(ScanEntraAdminRolesJob::class); }); // --------------------------------------------------------------------------- // Non-member user sees empty state (no tenant data exposed) // --------------------------------------------------------------------------- it('renders empty state for non-member user', function (): void { $user = \App\Models\User::factory()->create(); $tenant = Tenant::factory()->create(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(AdminRolesSummaryWidget::class, ['record' => $tenant]) ->assertSee('No scan performed yet.') ->assertDontSee('Scan now') ->assertSuccessful(); }); // --------------------------------------------------------------------------- // Widget shows scan button only for users with manage capability // --------------------------------------------------------------------------- it('does not show scan button for readonly users', function (): void { [$user, $tenant] = createUserWithTenant(role: 'readonly'); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(AdminRolesSummaryWidget::class, ['record' => $tenant]) ->assertDontSee('Scan now') ->assertSuccessful(); }); it('shows scan button for owner users', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(AdminRolesSummaryWidget::class, ['record' => $tenant]) ->assertSee('Scan now') ->assertSuccessful(); }); // --------------------------------------------------------------------------- // Notification on successful scan dispatch // --------------------------------------------------------------------------- it('sends success notification after scan dispatch', function (): void { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'owner'); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(AdminRolesSummaryWidget::class, ['record' => $tenant]) ->call('scanNow') ->assertSuccessful(); $notifications = collect(session('filament.notifications', [])); $titles = $notifications->pluck('title')->filter()->values()->all(); expect($titles)->toContain('Entra admin roles scan queued'); });