create(); $foreignTenant = Tenant::factory()->create(); $ownedRecord = Policy::factory()->create(['tenant_id' => $tenant->getKey()]); Policy::factory()->create(['tenant_id' => $foreignTenant->getKey()]); $records = app(TenantOwnedQueryScope::class) ->apply(Policy::query(), $tenant) ->pluck('id') ->all(); expect($records)->toBe([(int) $ownedRecord->getKey()]); }); it('fails closed when no tenant context is available', function (): void { Tenant::factory()->count(2)->create()->each(function (Tenant $tenant): void { Policy::factory()->create(['tenant_id' => $tenant->getKey()]); }); $count = app(TenantOwnedQueryScope::class) ->apply(Policy::query(), null) ->count(); expect($count)->toBe(0); }); it('resolves only records inside the already-scoped tenant query', function (): void { $tenant = Tenant::factory()->create(); $foreignTenant = Tenant::factory()->create(); $ownedRecord = Policy::factory()->create(['tenant_id' => $tenant->getKey()]); $foreignRecord = Policy::factory()->create(['tenant_id' => $foreignTenant->getKey()]); $resolver = app(TenantOwnedRecordResolver::class); $scopedQuery = app(TenantOwnedQueryScope::class)->apply(Policy::query(), $tenant); expect($resolver->resolve($scopedQuery, $ownedRecord)) ->toBeInstanceOf(Model::class) ->and($resolver->resolve($scopedQuery, $ownedRecord)?->is($ownedRecord))->toBeTrue(); expect($resolver->resolve($scopedQuery, $foreignRecord))->toBeNull(); }); it('lets the shared filament trait expose the scoped query and resolver helpers', function (): void { $tenant = Tenant::factory()->create(); $foreignTenant = Tenant::factory()->create(); $ownedRecord = Policy::factory()->create(['tenant_id' => $tenant->getKey()]); Policy::factory()->create(['tenant_id' => $foreignTenant->getKey()]); TestTenantOwnedPolicyResource::fakeTenant($tenant); expect(TestTenantOwnedPolicyResource::queryViaTrait()->pluck('id')->all()) ->toBe([(int) $ownedRecord->getKey()]); expect(TestTenantOwnedPolicyResource::resolveViaTrait($ownedRecord)?->is($ownedRecord)) ->toBeTrue(); }); class TestTenantOwnedPolicyResource extends Resource { use InteractsWithTenantOwnedRecords; protected static ?string $model = Policy::class; protected static ?string $tenantOwnershipRelationshipName = 'tenant'; protected static ?Tenant $fakeTenant = null; public static function fakeTenant(?Tenant $tenant): void { static::$fakeTenant = $tenant; } public static function queryViaTrait() { return static::getTenantOwnedEloquentQuery(); } public static function resolveViaTrait(Model|int|string|null $record): ?Model { return static::resolveTenantOwnedRecord($record); } protected static function resolveTenantContextForTenantOwnedRecords(): ?Tenant { return static::$fakeTenant; } public static function form(Schema $schema): Schema { return $schema; } }