create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $this->actingAs($user) ->get(ReviewPackResource::getUrl('index', tenant: $tenant)) ->assertOk(); }); it('shows review packs belonging to the active tenant', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $otherTenant = Tenant::factory()->create(); $pack = ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'initiated_by_user_id' => (int) $user->getKey(), ]); ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $otherTenant->getKey(), ]); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListReviewPacks::class) ->assertCanSeeTableRecords([$pack]); }); it('displays the empty state when no packs exist', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListReviewPacks::class) ->assertSee('No review packs yet'); }); // ─── List Page Header Action ───────────────────────────────── it('shows the generate_pack header action for a MANAGE user', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListReviewPacks::class) ->assertActionVisible('generate_pack'); }); it('disables the generate_pack action for a readonly user', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly'); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListReviewPacks::class) ->assertActionVisible('generate_pack') ->assertActionDisabled('generate_pack') ->assertActionExists('generate_pack', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission()); }); it('reuses an existing ready pack instead of starting a new run', function (): void { Queue::fake(); $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $fingerprint = app(ReviewPackService::class)->computeFingerprint($tenant, [ 'include_pii' => true, 'include_operations' => true, ]); ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'initiated_by_user_id' => (int) $user->getKey(), 'fingerprint' => $fingerprint, 'expires_at' => now()->addDay(), ]); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $operationRunsBefore = OperationRun::query()->count(); $reviewPacksBefore = ReviewPack::query()->count(); Livewire::actingAs($user) ->test(ListReviewPacks::class) ->callAction('generate_pack', [ 'include_pii' => true, 'include_operations' => true, ]) ->assertNotified(); expect(OperationRun::query()->count())->toBe($operationRunsBefore); expect(ReviewPack::query()->count())->toBe($reviewPacksBefore); Queue::assertNothingPushed(); }); // ─── Table Row Actions ─────────────────────────────────────── it('shows the download action for a ready pack', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $filePath = 'review-packs/test.zip'; Storage::disk('exports')->put($filePath, 'PK-fake'); $pack = ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'initiated_by_user_id' => (int) $user->getKey(), 'file_path' => $filePath, ]); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListReviewPacks::class) ->assertTableActionVisible('download', $pack); }); it('shows the expire action for a ready pack with confirmation', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $filePath = 'review-packs/expire-test.zip'; Storage::disk('exports')->put($filePath, 'PK-fake'); $pack = ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'initiated_by_user_id' => (int) $user->getKey(), 'file_path' => $filePath, 'file_disk' => 'exports', ]); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListReviewPacks::class) ->assertTableActionVisible('expire', $pack) ->callTableAction('expire', $pack); $pack->refresh(); expect($pack->status)->toBe(ReviewPackStatus::Expired->value); Storage::disk('exports')->assertMissing($filePath); }); // ─── View Page ─────────────────────────────────────────────── it('renders the view page for a ready pack', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $pack = ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'initiated_by_user_id' => (int) $user->getKey(), 'summary' => [ 'finding_count' => 5, 'report_count' => 2, 'operation_count' => 12, 'data_freshness' => [ 'permission_posture' => now()->toIso8601String(), 'entra_admin_roles' => now()->toIso8601String(), 'findings' => now()->toIso8601String(), 'hardening' => now()->toIso8601String(), ], ], 'options' => ['include_pii' => true, 'include_operations' => true], ]); $this->actingAs($user) ->get(ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $tenant)) ->assertOk(); }); it('shows download header action on view page for a ready pack', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $pack = ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'initiated_by_user_id' => (int) $user->getKey(), ]); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ViewReviewPack::class, ['record' => $pack->getKey()]) ->assertActionVisible('download'); }); it('shows regenerate header action on view page', function (): void { $tenant = Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $pack = ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'initiated_by_user_id' => (int) $user->getKey(), ]); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ViewReviewPack::class, ['record' => $pack->getKey()]) ->assertActionVisible('regenerate'); }); // ─── Non-Member Access ─────────────────────────────────────── it('returns 404 for non-members on list page', function (): void { $tenant = Tenant::factory()->create(); $otherTenant = Tenant::factory()->create(); [$user] = createUserWithTenant($otherTenant, role: 'owner'); $this->actingAs($user) ->get(ReviewPackResource::getUrl('index', tenant: $tenant)) ->assertNotFound(); }); it('returns 404 for non-members on view page', function (): void { $tenant = Tenant::factory()->create(); $otherTenant = Tenant::factory()->create(); [$user] = createUserWithTenant($otherTenant, role: 'owner'); $pack = ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), ]); $this->actingAs($user) ->get(ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $tenant)) ->assertNotFound(); });