withHeaders(['X-Api-Key' => config('app.api_secret_key')]); }); it('returns search stats for current week', function () { // 10 searches within the rolling 7 days (3 unique IPs) Search::factory()->count(5)->create([ 'searched_at' => now()->subDays(2), 'ip_hash' => hash('sha256', '1.2.3.4'), 'lowest_pence' => 13800, 'highest_pence' => 14500, 'avg_pence' => 14150.00, 'results_count' => 20, ]); Search::factory()->count(3)->create([ 'searched_at' => now()->subDays(4), 'ip_hash' => hash('sha256', '5.6.7.8'), 'lowest_pence' => 14200, 'highest_pence' => 15000, 'avg_pence' => 14600.00, 'results_count' => 30, ]); Search::factory()->count(2)->create([ 'searched_at' => now()->subDays(6), 'ip_hash' => hash('sha256', '9.10.11.12'), 'lowest_pence' => 13500, 'highest_pence' => 14000, 'avg_pence' => 13750.00, 'results_count' => 10, ]); // 5 searches outside the 7-day window Search::factory()->count(5)->create(['searched_at' => now()->subDays(10)]); $this->getJson('/api/stats/searches?period=week') ->assertOk() ->assertJsonStructure(['total_searches', 'unique_searchers', 'avg_results', 'avg_lowest_price', 'avg_highest_price', 'avg_price', 'period', 'message']) ->assertJsonPath('total_searches', 10) ->assertJsonPath('unique_searchers', 3) ->assertJsonPath('period', 'week'); }); it('includes a human readable message', function () { Search::factory()->count(3)->create(['searched_at' => now()->subDay()]); $response = $this->getJson('/api/stats/searches?period=week')->assertOk(); expect($response->json('message'))->toContain('drivers'); }); it('returns zero stats when no searches exist', function () { $this->getJson('/api/stats/searches?period=week') ->assertOk() ->assertJsonPath('total_searches', 0) ->assertJsonPath('unique_searchers', 0); }); it('defaults to week period when period param is omitted', function () { $this->getJson('/api/stats/searches') ->assertOk() ->assertJsonPath('period', 'week'); });