seed(RoleSeeder::class); $this->superAdmin = User::factory()->create(); $this->superAdmin->assignRole('super_admin'); $this->orgAdmin = User::factory()->create(); $this->organisation = Organisation::factory()->create(['billing_status' => 'active']); $this->organisation->users()->attach($this->orgAdmin, ['role' => 'org_admin']); } // ─── Index ─────────────────────────────────────────────── public function test_index_returns_all_organisations_for_super_admin(): void { Organisation::factory()->count(3)->create(); Sanctum::actingAs($this->superAdmin); $response = $this->getJson('/api/v1/admin/organisations'); $response->assertOk(); $response->assertJsonStructure([ 'data' => [['id', 'name', 'slug', 'billing_status', 'events_count', 'users_count']], ]); // 1 from setUp + 3 created = 4 $this->assertCount(4, $response->json('data')); } public function test_index_denied_for_org_admin(): void { Sanctum::actingAs($this->orgAdmin); $response = $this->getJson('/api/v1/admin/organisations'); $response->assertForbidden(); } public function test_index_denied_for_unauthenticated(): void { $response = $this->getJson('/api/v1/admin/organisations'); $response->assertUnauthorized(); } public function test_search_by_name(): void { Organisation::factory()->create(['name' => 'Festival Corp']); Organisation::factory()->create(['name' => 'Music Events BV']); Sanctum::actingAs($this->superAdmin); $response = $this->getJson('/api/v1/admin/organisations?search=Festival'); $response->assertOk(); $this->assertCount(1, $response->json('data')); $response->assertJsonPath('data.0.name', 'Festival Corp'); } public function test_filter_by_billing_status(): void { Organisation::factory()->create(['billing_status' => 'trial']); Organisation::factory()->create(['billing_status' => 'suspended']); Sanctum::actingAs($this->superAdmin); $response = $this->getJson('/api/v1/admin/organisations?billing_status=trial'); $response->assertOk(); foreach ($response->json('data') as $org) { $this->assertEquals('trial', $org['billing_status']); } } // ─── Show ──────────────────────────────────────────────── public function test_show_returns_organisation_with_members(): void { $event = Event::factory()->create(['organisation_id' => $this->organisation->id]); Sanctum::actingAs($this->superAdmin); $response = $this->getJson("/api/v1/admin/organisations/{$this->organisation->id}"); $response->assertOk(); $response->assertJsonPath('data.organisation.id', $this->organisation->id); $response->assertJsonPath('data.organisation.events_count', 1); $response->assertJsonPath('data.organisation.users_count', 1); $response->assertJsonStructure([ 'data' => [ 'organisation' => ['id', 'name', 'slug', 'billing_status', 'billing_status_label', 'events_count', 'users_count', 'total_persons'], 'members' => [['id', 'first_name', 'last_name', 'email', 'role']], ], ]); $this->assertCount(1, $response->json('data.members')); $response->assertJsonPath('data.members.0.email', $this->orgAdmin->email); } // ─── Update ────────────────────────────────────────────── public function test_update_changes_billing_status(): void { Sanctum::actingAs($this->superAdmin); $response = $this->putJson("/api/v1/admin/organisations/{$this->organisation->id}", [ 'billing_status' => 'suspended', ]); $response->assertOk(); $response->assertJsonPath('data.billing_status', 'suspended'); $this->assertDatabaseHas('organisations', [ 'id' => $this->organisation->id, 'billing_status' => 'suspended', ]); } // ─── Destroy ───────────────────────────────────────────── public function test_destroy_soft_deletes(): void { Sanctum::actingAs($this->superAdmin); $response = $this->deleteJson("/api/v1/admin/organisations/{$this->organisation->id}"); $response->assertNoContent(); $this->assertSoftDeleted('organisations', ['id' => $this->organisation->id]); } // ─── Invite ────────────────────────────────────────────── public function test_invite_creates_invitation_for_new_email(): void { Sanctum::actingAs($this->superAdmin); $response = $this->postJson("/api/v1/admin/organisations/{$this->organisation->id}/invite", [ 'email' => 'newuser@example.com', 'role' => 'org_member', ]); $response->assertCreated(); $this->assertDatabaseHas('user_invitations', [ 'email' => 'newuser@example.com', 'organisation_id' => $this->organisation->id, 'role' => 'org_member', 'status' => 'pending', ]); } public function test_invite_adds_existing_user_directly(): void { $existingUser = User::factory()->create(['email' => 'exists@example.com']); Sanctum::actingAs($this->superAdmin); $response = $this->postJson("/api/v1/admin/organisations/{$this->organisation->id}/invite", [ 'email' => 'exists@example.com', 'role' => 'org_admin', ]); $response->assertOk(); $this->assertDatabaseHas('organisation_user', [ 'user_id' => $existingUser->id, 'organisation_id' => $this->organisation->id, 'role' => 'org_admin', ]); } public function test_invite_fails_for_existing_member(): void { Sanctum::actingAs($this->superAdmin); $response = $this->postJson("/api/v1/admin/organisations/{$this->organisation->id}/invite", [ 'email' => $this->orgAdmin->email, 'role' => 'org_member', ]); $response->assertUnprocessable(); $response->assertJsonPath('message', 'Gebruiker is al lid van deze organisatie.'); } public function test_invite_denied_for_non_super_admin(): void { Sanctum::actingAs($this->orgAdmin); $response = $this->postJson("/api/v1/admin/organisations/{$this->organisation->id}/invite", [ 'email' => 'test@example.com', 'role' => 'org_member', ]); $response->assertForbidden(); } // ─── Remove Member ─────────────────────────────────────── public function test_remove_member_detaches_from_org(): void { Sanctum::actingAs($this->superAdmin); $response = $this->deleteJson("/api/v1/admin/organisations/{$this->organisation->id}/members/{$this->orgAdmin->id}"); $response->assertNoContent(); $this->assertDatabaseMissing('organisation_user', [ 'user_id' => $this->orgAdmin->id, 'organisation_id' => $this->organisation->id, ]); } public function test_remove_self_fails(): void { // Attach super admin to the org so the self-removal check kicks in $this->organisation->users()->attach($this->superAdmin, ['role' => 'org_admin']); Sanctum::actingAs($this->superAdmin); $response = $this->deleteJson("/api/v1/admin/organisations/{$this->organisation->id}/members/{$this->superAdmin->id}"); $response->assertUnprocessable(); $response->assertJsonPath('message', 'Je kunt jezelf niet verwijderen.'); } // ─── Update Member Role ────────────────────────────────── public function test_update_member_role(): void { Sanctum::actingAs($this->superAdmin); $response = $this->putJson("/api/v1/admin/organisations/{$this->organisation->id}/members/{$this->orgAdmin->id}", [ 'role' => 'org_member', ]); $response->assertOk(); $response->assertJsonPath('data.role', 'org_member'); $this->assertDatabaseHas('organisation_user', [ 'user_id' => $this->orgAdmin->id, 'organisation_id' => $this->organisation->id, 'role' => 'org_member', ]); } }