seed(RoleSeeder::class); $this->organisation = Organisation::factory()->create(); $this->otherOrganisation = Organisation::factory()->create(); $this->orgAdmin = User::factory()->create(); $this->organisation->users()->attach($this->orgAdmin, ['role' => 'org_admin']); $this->outsider = User::factory()->create(); $this->otherOrganisation->users()->attach($this->outsider, ['role' => 'org_admin']); } public function test_index_returns_paginated_logs(): void { EmailLog::factory()->count(3)->create([ 'organisation_id' => $this->organisation->id, ]); Sanctum::actingAs($this->orgAdmin); $response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/email-logs"); $response->assertOk(); $this->assertCount(3, $response->json('data.data')); } public function test_filter_by_status(): void { EmailLog::factory()->sent()->create([ 'organisation_id' => $this->organisation->id, ]); EmailLog::factory()->failed()->create([ 'organisation_id' => $this->organisation->id, ]); Sanctum::actingAs($this->orgAdmin); $response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/email-logs?status=sent"); $response->assertOk(); $this->assertCount(1, $response->json('data.data')); $this->assertEquals('sent', $response->json('data.data.0.status')); } public function test_filter_by_template_type(): void { EmailLog::factory()->create([ 'organisation_id' => $this->organisation->id, 'template_type' => EmailTemplateType::INVITATION->value, ]); EmailLog::factory()->create([ 'organisation_id' => $this->organisation->id, 'template_type' => EmailTemplateType::PASSWORD_RESET->value, ]); Sanctum::actingAs($this->orgAdmin); $response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/email-logs?template_type=invitation"); $response->assertOk(); $this->assertCount(1, $response->json('data.data')); $this->assertEquals('invitation', $response->json('data.data.0.template_type')); } public function test_filter_by_date_range(): void { EmailLog::factory()->create([ 'organisation_id' => $this->organisation->id, 'created_at' => '2026-04-10 12:00:00', ]); EmailLog::factory()->create([ 'organisation_id' => $this->organisation->id, 'created_at' => '2026-04-15 12:00:00', ]); Sanctum::actingAs($this->orgAdmin); $response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/email-logs?from=2026-04-14&to=2026-04-16"); $response->assertOk(); $this->assertCount(1, $response->json('data.data')); } public function test_search_by_recipient_email(): void { EmailLog::factory()->create([ 'organisation_id' => $this->organisation->id, 'recipient_email' => 'needle@example.com', ]); EmailLog::factory()->create([ 'organisation_id' => $this->organisation->id, 'recipient_email' => 'other@example.com', ]); Sanctum::actingAs($this->orgAdmin); $response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/email-logs?search=needle"); $response->assertOk(); $this->assertCount(1, $response->json('data.data')); $this->assertEquals('needle@example.com', $response->json('data.data.0.recipient_email')); } public function test_denied_for_non_org_admin(): void { Sanctum::actingAs($this->outsider); $response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/email-logs"); $response->assertForbidden(); } public function test_cannot_see_other_org_logs(): void { EmailLog::factory()->count(2)->create([ 'organisation_id' => $this->otherOrganisation->id, ]); Sanctum::actingAs($this->orgAdmin); $response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/email-logs"); $response->assertOk(); $this->assertCount(0, $response->json('data.data')); } public function test_unauthenticated_returns_401(): void { $response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/email-logs"); $response->assertUnauthorized(); } }