New_Micro_Learning/backend/tests/Feature/Organizations/OrganizationAdministrationT...

102 خطوط
6.4 KiB
PHP

<?php
namespace Tests\Feature\Organizations;
use App\Models\User;
use App\Modules\Identity\Domain\Enums\UserRole;
use App\Modules\Organizations\Domain\Organization;
use App\Modules\Subscriptions\Domain\Subscription;
use App\Modules\System\Domain\DeploymentCapabilities;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;
class OrganizationAdministrationTest extends TestCase
{
use RefreshDatabase;
public function test_super_admin_can_manage_organizations_without_learning_analytics(): void
{
Sanctum::actingAs(User::factory()->create(['role' => UserRole::SuperAdmin]));
$id = $this->postJson('/api/v1/organizations', [
'name' => 'Acme Learning', 'slug' => 'acme-learning', 'defaultLocale' => 'fa', 'timezone' => 'Asia/Tehran',
])->assertCreated()->assertJsonMissingPath('data.learningAnalytics')->json('data.id');
$this->getJson('/api/v1/organizations')->assertOk()->assertJsonPath('meta.total', 2)->assertJsonFragment(['slug' => 'acme-learning']);
$this->patchJson("/api/v1/organizations/{$id}", ['status' => 'disabled'])->assertOk()->assertJsonPath('data.status', 'disabled');
}
public function test_tenant_roles_cannot_access_platform_organization_administration(): void
{
Sanctum::actingAs(User::factory()->create(['role' => UserRole::CourseDesigner]));
$this->getJson('/api/v1/organizations')->assertForbidden();
}
public function test_on_premise_mode_hides_multi_organization_endpoints(): void
{
config()->set('deployment.mode', 'on_premise');
$this->app->forgetInstance(DeploymentCapabilities::class);
Sanctum::actingAs(User::factory()->create(['role' => UserRole::SuperAdmin]));
$this->getJson('/api/v1/organizations')->assertNotFound();
}
public function test_organization_slug_is_unique(): void
{
Organization::factory()->create(['slug' => 'taken']);
Sanctum::actingAs(User::factory()->create(['role' => UserRole::SuperAdmin]));
$this->postJson('/api/v1/organizations', ['name' => 'Duplicate', 'slug' => 'taken', 'defaultLocale' => 'en', 'timezone' => 'UTC'])
->assertUnprocessable()->assertJsonValidationErrors('slug');
}
public function test_platform_list_supports_search_filters_sorting_and_complete_pagination_metadata(): void
{
$alpha = Organization::factory()->create(['name' => 'Alpha Learning', 'slug' => 'alpha', 'status' => 'active']);
Organization::factory()->create(['name' => 'Beta Academy', 'slug' => 'beta', 'status' => 'disabled']);
User::factory()->count(2)->for($alpha)->create();
Subscription::query()->create(['organization_id' => $alpha->getKey(), 'plan_key' => 'enterprise', 'status' => 'active', 'starts_at' => now()->subDay(), 'expires_at' => now()->addMonth(), 'seat_limit' => 50, 'storage_quota_bytes' => 1000, 'ai_credit_quota' => 500]);
DB::table('audit_logs')->insert(['id' => (string) str()->ulid(), 'organization_id' => $alpha->getKey(), 'actor_id' => null, 'action' => 'organization.activity', 'entity_type' => 'organization', 'entity_id' => $alpha->getKey(), 'metadata' => json_encode(['schemaVersion' => 1]), 'ip_address' => '127.0.0.1', 'created_at' => now()]);
Sanctum::actingAs(User::factory()->create(['organization_id' => null, 'role' => UserRole::SuperAdmin]));
$this->getJson('/api/v1/organizations?search=alpha&status=active&plan=enterprise&sort=users&direction=desc&perPage=1')
->assertOk()
->assertJsonPath('meta.currentPage', 1)
->assertJsonPath('meta.lastPage', 1)
->assertJsonPath('meta.perPage', 1)
->assertJsonPath('meta.total', 1)
->assertJsonPath('data.0.id', $alpha->getKey())
->assertJsonPath('data.0.planKey', 'enterprise')
->assertJsonPath('data.0.usersCount', 2)
->assertJsonPath('data.0.aiCreditsUsed', 0)
->assertJsonStructure(['data' => [['lastActivityAt', 'subscriptionExpiresAt', 'storageUsedBytes', 'storageQuotaBytes']]]);
}
public function test_organization_detail_is_platform_scoped_and_exposes_real_operational_metadata(): void
{
$organization = Organization::factory()->create(['name' => 'Detail Org']);
User::factory()->for($organization)->create(['name' => 'Member One']);
Subscription::query()->create(['organization_id' => $organization->getKey(), 'plan_key' => 'growth', 'status' => 'active', 'starts_at' => now()->subDay(), 'seat_limit' => 20, 'storage_quota_bytes' => 2048, 'storage_used_bytes' => 512, 'ai_credit_quota' => 100, 'ai_credits_used' => 12, 'enabled_features' => ['exports']]);
DB::table('audit_logs')->insert(['id' => (string) str()->ulid(), 'organization_id' => $organization->getKey(), 'actor_id' => null, 'action' => 'organization.seeded', 'entity_type' => 'organization', 'entity_id' => $organization->getKey(), 'metadata' => json_encode(['schemaVersion' => 1]), 'ip_address' => '127.0.0.1', 'created_at' => now()]);
Sanctum::actingAs(User::factory()->create(['organization_id' => null, 'role' => UserRole::SuperAdmin]));
$this->getJson('/api/v1/organizations/'.$organization->getKey())
->assertOk()
->assertJsonPath('data.subscription.planKey', 'growth')
->assertJsonPath('data.subscription.aiCreditsUsed', 12)
->assertJsonPath('data.recentUsers.0.name', 'Member One')
->assertJsonPath('data.recentActivity.0.action', 'organization.seeded')
->assertJsonStructure(['data' => ['storageUsedBytes', 'aiJobsCount', 'failedAiJobsCount', 'recentUsers', 'recentActivity']]);
}
public function test_organization_lifecycle_changes_are_audited(): void
{
Sanctum::actingAs(User::factory()->create(['organization_id' => null, 'role' => UserRole::SuperAdmin]));
$id = $this->postJson('/api/v1/organizations', ['name' => 'Audited Org', 'slug' => 'audited-org', 'defaultLocale' => 'fa', 'timezone' => 'Asia/Tehran'])->assertCreated()->json('data.id');
$this->patchJson('/api/v1/organizations/'.$id, ['status' => 'disabled'])->assertOk();
$this->assertDatabaseHas('audit_logs', ['organization_id' => $id, 'action' => 'organization.created', 'entity_id' => $id]);
$this->assertDatabaseHas('audit_logs', ['organization_id' => $id, 'action' => 'organization.updated', 'entity_id' => $id]);
}
}