delete(); } public function test_index_returns_successful_response(): void { Log::factory()->count(5)->create(); $response = $this->getJson('/api/v1/logs'); $response->assertStatus(200) ->assertJsonStructure([ 'success', 'message', 'data' => [ 'logs' => [ '*' => [ 'id', 'level', 'message', 'context', 'created_at', 'updated_at', ] ], 'pagination' => [ 'current_page', 'last_page', 'per_page', 'total', 'from', 'to', ] ] ]) ->assertJson([ 'success' => true, 'message' => 'Logs retrieved successfully.' ]); } public function test_index_orders_logs_by_created_at_desc(): void { $oldLog = Log::factory()->create(['created_at' => now()->subDays(2)]); $newLog = Log::factory()->create(['created_at' => now()->subDay()]); $newestLog = Log::factory()->create(['created_at' => now()]); $response = $this->getJson('/api/v1/logs'); $response->assertStatus(200); $logs = $response->json('data.logs'); $this->assertEquals($newestLog->id, $logs[0]['id']); $this->assertEquals($newLog->id, $logs[1]['id']); $this->assertEquals($oldLog->id, $logs[2]['id']); } public function test_index_filters_by_level(): void { Log::factory()->create(['level' => LogLevelEnum::ERROR]); Log::factory()->create(['level' => LogLevelEnum::WARNING]); Log::factory()->create(['level' => LogLevelEnum::INFO]); $response = $this->getJson('/api/v1/logs?level=error'); $response->assertStatus(200); $logs = $response->json('data.logs'); $this->assertCount(1, $logs); $this->assertEquals('error', $logs[0]['level']); } public function test_index_respects_per_page_parameter(): void { Log::factory()->count(15)->create(); $response = $this->getJson('/api/v1/logs?per_page=5'); $response->assertStatus(200); $logs = $response->json('data.logs'); $pagination = $response->json('data.pagination'); $this->assertCount(5, $logs); $this->assertEquals(5, $pagination['per_page']); $this->assertEquals(15, $pagination['total']); $this->assertEquals(3, $pagination['last_page']); } public function test_index_limits_per_page_to_maximum(): void { Log::factory()->count(10)->create(); $response = $this->getJson('/api/v1/logs?per_page=150'); $response->assertStatus(200); $pagination = $response->json('data.pagination'); // Should be limited to 100 as per controller logic $this->assertEquals(100, $pagination['per_page']); } public function test_index_uses_default_per_page_when_not_specified(): void { Log::factory()->count(25)->create(); $response = $this->getJson('/api/v1/logs'); $response->assertStatus(200); $pagination = $response->json('data.pagination'); // Should use default of 20 $this->assertEquals(20, $pagination['per_page']); } public function test_index_handles_empty_logs(): void { $response = $this->getJson('/api/v1/logs'); $response->assertStatus(200) ->assertJson([ 'success' => true, 'message' => 'Logs retrieved successfully.', 'data' => [ 'logs' => [], 'pagination' => [ 'total' => 0, 'current_page' => 1, 'last_page' => 1, ] ] ]); } public function test_index_pagination_works_correctly(): void { Log::factory()->count(25)->create(); // Test first page $response = $this->getJson('/api/v1/logs?per_page=10&page=1'); $response->assertStatus(200); $pagination = $response->json('data.pagination'); $this->assertEquals(1, $pagination['current_page']); $this->assertEquals(3, $pagination['last_page']); $this->assertEquals(1, $pagination['from']); $this->assertEquals(10, $pagination['to']); // Test second page $response = $this->getJson('/api/v1/logs?per_page=10&page=2'); $response->assertStatus(200); $pagination = $response->json('data.pagination'); $this->assertEquals(2, $pagination['current_page']); $this->assertEquals(11, $pagination['from']); $this->assertEquals(20, $pagination['to']); } public function test_index_with_multiple_log_levels(): void { Log::factory()->create(['level' => LogLevelEnum::ERROR, 'message' => 'Error message']); Log::factory()->create(['level' => LogLevelEnum::WARNING, 'message' => 'Warning message']); Log::factory()->create(['level' => LogLevelEnum::INFO, 'message' => 'Info message']); Log::factory()->create(['level' => LogLevelEnum::DEBUG, 'message' => 'Debug message']); $response = $this->getJson('/api/v1/logs'); $response->assertStatus(200); $logs = $response->json('data.logs'); $this->assertCount(4, $logs); $levels = array_column($logs, 'level'); $this->assertContains('error', $levels); $this->assertContains('warning', $levels); $this->assertContains('info', $levels); $this->assertContains('debug', $levels); } public function test_index_handles_negative_per_page(): void { Log::factory()->count(5)->create(); $response = $this->getJson('/api/v1/logs?per_page=-5'); $response->assertStatus(200); $pagination = $response->json('data.pagination'); // Should use default of 20 when negative value provided $this->assertEquals(20, $pagination['per_page']); } public function test_index_handles_zero_per_page(): void { Log::factory()->count(5)->create(); $response = $this->getJson('/api/v1/logs?per_page=0'); $response->assertStatus(200); $pagination = $response->json('data.pagination'); // Should use default of 20 when zero provided $this->assertEquals(20, $pagination['per_page']); } public function test_index_excludes_system_noise_messages(): void { // Create a log with system noise message that should be excluded Log::factory()->create(['message' => 'No active feeds found. Article discovery skipped.']); Log::factory()->create(['message' => 'Regular log message']); $response = $this->getJson('/api/v1/logs'); $response->assertStatus(200); $logs = $response->json('data.logs'); // Should only get the regular log, not the system noise $this->assertCount(1, $logs); $this->assertEquals('Regular log message', $logs[0]['message']); } public function test_index_handles_non_numeric_per_page(): void { Log::factory()->count(5)->create(); $response = $this->getJson('/api/v1/logs?per_page=invalid'); $response->assertStatus(200); $pagination = $response->json('data.pagination'); // Should use default of 20 when invalid value provided $this->assertEquals(20, $pagination['per_page']); } }