TenantAtlas/tests/Feature/Filament/EmptyStateConsistencyTest.php
2026-03-08 03:16:51 +01:00

196 lines
7.1 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Resources\BackupScheduleResource;
use App\Filament\Resources\BackupScheduleResource\Pages\ListBackupSchedules;
use App\Filament\Resources\BackupSetResource;
use App\Filament\Resources\BackupSetResource\Pages\ListBackupSets;
use App\Filament\Resources\PolicyResource\Pages\ListPolicies;
use App\Filament\Resources\RestoreRunResource;
use App\Filament\Resources\RestoreRunResource\Pages\ListRestoreRuns;
use App\Filament\Resources\Workspaces\Pages\ListWorkspaces;
use App\Filament\Resources\Workspaces\WorkspaceResource;
use App\Jobs\SyncPoliciesJob;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Filament\Tables\Table;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Features\SupportTesting\Testable;
use Livewire\Livewire;
uses(RefreshDatabase::class);
function getFeature122EmptyStateTable(Testable $component): Table
{
return $component->instance()->getTable();
}
function getFeature122EmptyStateAction(Testable $component, string $name): ?Action
{
foreach (getFeature122EmptyStateTable($component)->getEmptyStateActions() as $action) {
if ($action instanceof Action && $action->getName() === $name) {
return $action;
}
}
return null;
}
function makeWorkspaceListComponent(string $role = 'owner'): Testable
{
$workspace = Workspace::factory()->create([
'archived_at' => now(),
]);
$user = User::factory()->create();
WorkspaceMembership::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'user_id' => (int) $user->getKey(),
'role' => $role,
]);
$user->forceFill([
'last_workspace_id' => (int) $workspace->getKey(),
])->save();
test()->actingAs($user)
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()]);
return Livewire::test(ListWorkspaces::class);
}
it('defines the policies empty state contract and keeps the sync CTA outcome intact', function (): void {
Queue::fake();
bindFailHardGraphClient();
[$user, $tenant] = createUserWithTenant(role: 'owner');
$this->actingAs($user);
$tenant->makeCurrent();
Filament::setTenant($tenant, true);
$component = Livewire::test(ListPolicies::class)
->assertTableEmptyStateActionsExistInOrder(['sync'])
->assertSee('No policies synced yet')
->assertSee('Sync your first tenant to see Intune policies here.');
$table = getFeature122EmptyStateTable($component);
expect($table->getEmptyStateHeading())->toBe('No policies synced yet');
expect($table->getEmptyStateDescription())->toBe('Sync your first tenant to see Intune policies here.');
expect($table->getEmptyStateIcon())->toBe('heroicon-o-arrow-path');
$action = getFeature122EmptyStateAction($component, 'sync');
expect($action)->not->toBeNull();
expect($action?->getLabel())->toBe('Sync from Intune');
$component
->mountAction('sync')
->callMountedAction()
->assertHasNoActionErrors();
Queue::assertPushed(SyncPoliciesJob::class);
});
it('defines the backup sets empty state contract and links its CTA to create', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$this->actingAs($user);
$tenant->makeCurrent();
Filament::setTenant($tenant, true);
$component = Livewire::test(ListBackupSets::class)
->assertTableEmptyStateActionsExistInOrder(['create'])
->assertSee('No backup sets')
->assertSee('Create a backup set to start protecting your configurations.');
$table = getFeature122EmptyStateTable($component);
expect($table->getEmptyStateHeading())->toBe('No backup sets');
expect($table->getEmptyStateDescription())->toBe('Create a backup set to start protecting your configurations.');
expect($table->getEmptyStateIcon())->toBe('heroicon-o-archive-box');
$action = getFeature122EmptyStateAction($component, 'create');
expect($action)->not->toBeNull();
expect($action?->getLabel())->toBe('Create backup set');
expect($action?->getUrl())->toBe(BackupSetResource::getUrl('create', tenant: $tenant));
});
it('defines the restore runs empty state contract and links its CTA to create', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$this->actingAs($user);
$tenant->makeCurrent();
Filament::setTenant($tenant, true);
$component = Livewire::test(ListRestoreRuns::class)
->assertTableEmptyStateActionsExistInOrder(['create'])
->assertSee('No restore runs')
->assertSee('Start a restoration from a backup set.');
$table = getFeature122EmptyStateTable($component);
expect($table->getEmptyStateHeading())->toBe('No restore runs');
expect($table->getEmptyStateDescription())->toBe('Start a restoration from a backup set.');
expect($table->getEmptyStateIcon())->toBe('heroicon-o-arrow-path-rounded-square');
$action = getFeature122EmptyStateAction($component, 'create');
expect($action)->not->toBeNull();
expect($action?->getLabel())->toBe('New restore run');
expect($action?->getUrl())->toBe(RestoreRunResource::getUrl('create', tenant: $tenant));
});
it('defines the backup schedules empty state contract and links its CTA to create', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$this->actingAs($user);
$tenant->makeCurrent();
Filament::setTenant($tenant, true);
$component = Livewire::test(ListBackupSchedules::class)
->assertTableEmptyStateActionsExistInOrder(['create'])
->assertSee('No schedules configured')
->assertSee('Set up automated backups.');
$table = getFeature122EmptyStateTable($component);
expect($table->getEmptyStateHeading())->toBe('No schedules configured');
expect($table->getEmptyStateDescription())->toBe('Set up automated backups.');
expect($table->getEmptyStateIcon())->toBe('heroicon-o-clock');
$action = getFeature122EmptyStateAction($component, 'create');
expect($action)->not->toBeNull();
expect($action?->getLabel())->toBe('New backup schedule');
expect($action?->getUrl())->toBe(BackupScheduleResource::getUrl('create', tenant: $tenant));
});
it('defines the workspaces empty state contract and links its CTA to create', function (): void {
$component = makeWorkspaceListComponent()
->assertTableEmptyStateActionsExistInOrder(['create'])
->assertSee('No workspaces')
->assertSee('Create your first workspace.');
$table = getFeature122EmptyStateTable($component);
expect($table->getEmptyStateHeading())->toBe('No workspaces');
expect($table->getEmptyStateDescription())->toBe('Create your first workspace.');
expect($table->getEmptyStateIcon())->toBe('heroicon-o-squares-2x2');
$action = getFeature122EmptyStateAction($component, 'create');
expect($action)->not->toBeNull();
expect($action?->getLabel())->toBe('New workspace');
expect($action?->getUrl())->toBe(WorkspaceResource::getUrl('create'));
});