seed(RoleSeeder::class); $this->org = Organisation::factory()->create(); $this->otherOrg = Organisation::factory()->create(); $this->orgAdmin = User::factory()->create(); $this->org->users()->attach($this->orgAdmin, ['role' => 'org_admin']); $this->programManager = User::factory()->create(); $this->org->users()->attach($this->programManager, ['role' => 'program_manager']); $this->outsider = User::factory()->create(); $this->otherOrg->users()->attach($this->outsider, ['role' => 'org_admin']); } public function test_index_lists_artists_for_member(): void { Artist::factory()->count(3)->create(['organisation_id' => $this->org->id]); Sanctum::actingAs($this->orgAdmin); $response = $this->getJson("/api/v1/organisations/{$this->org->id}/artists"); $response->assertOk(); $this->assertCount(3, $response->json('data')); } public function test_index_unauthenticated_returns_401(): void { $this->getJson("/api/v1/organisations/{$this->org->id}/artists")->assertUnauthorized(); } public function test_outsider_cannot_view_other_org_artists(): void { Artist::factory()->create(['organisation_id' => $this->org->id]); Sanctum::actingAs($this->outsider); $this->getJson("/api/v1/organisations/{$this->org->id}/artists")->assertForbidden(); } public function test_program_manager_can_create(): void { Sanctum::actingAs($this->programManager); $response = $this->postJson("/api/v1/organisations/{$this->org->id}/artists", [ 'name' => 'Headhunterz', ]); $response->assertCreated(); $this->assertSame('Headhunterz', $response->json('data.name')); } public function test_duplicate_name_returns_409_with_existing_id(): void { $existing = Artist::factory()->create([ 'organisation_id' => $this->org->id, 'name' => 'Devin Wild', ]); Sanctum::actingAs($this->programManager); $response = $this->postJson("/api/v1/organisations/{$this->org->id}/artists", [ 'name' => 'devin wild', ]); $response->assertStatus(409); $this->assertSame((string) $existing->id, (string) $response->json('errors.duplicate_artist_id')); } public function test_destroy_blocked_with_active_engagement(): void { $artist = Artist::factory()->create(['organisation_id' => $this->org->id]); $event = Event::factory()->create(['organisation_id' => $this->org->id]); ArtistEngagement::factory()->create([ 'artist_id' => $artist->id, 'event_id' => $event->id, 'booking_status' => ArtistEngagementStatus::Confirmed, ]); Sanctum::actingAs($this->orgAdmin); $this->deleteJson("/api/v1/organisations/{$this->org->id}/artists/{$artist->id}") ->assertForbidden(); $this->assertDatabaseHas('artists', ['id' => $artist->id, 'deleted_at' => null]); } public function test_destroy_with_only_terminal_engagements_succeeds(): void { $artist = Artist::factory()->create(['organisation_id' => $this->org->id]); $event = Event::factory()->create(['organisation_id' => $this->org->id]); ArtistEngagement::factory()->create([ 'artist_id' => $artist->id, 'event_id' => $event->id, 'booking_status' => ArtistEngagementStatus::Cancelled, ]); Sanctum::actingAs($this->orgAdmin); $this->deleteJson("/api/v1/organisations/{$this->org->id}/artists/{$artist->id}") ->assertNoContent(); } public function test_restore_brings_back_soft_deleted_artist(): void { $artist = Artist::factory()->create(['organisation_id' => $this->org->id]); $artist->delete(); Sanctum::actingAs($this->orgAdmin); $response = $this->postJson("/api/v1/organisations/{$this->org->id}/artists/{$artist->id}/restore"); $response->assertOk(); $this->assertDatabaseHas('artists', ['id' => $artist->id, 'deleted_at' => null]); } }