create(['lat' => 52.555064, 'lng' => -0.256119]); StationPriceCurrent::factory()->create([ 'station_id' => $station->node_id, 'fuel_type' => FuelType::B7Standard, 'price_pence' => 14500, ]); $this->getJson('/api/stations?lat=52.555064&lng=-0.256119&fuel_type=diesel&radius=10&sort=price') ->assertOk() ->assertJsonStructure([ 'data' => [['station_id', 'name', 'brand', 'is_supermarket', 'lat', 'lng', 'distance_km', 'fuel_type', 'price_pence', 'price', 'price_updated_at']], 'meta' => ['count', 'fuel_type', 'radius_km', 'lowest_pence'], ]) ->assertJsonPath('data.0.price_pence', 14500) ->assertJsonPath('meta.fuel_type', 'b7_standard'); }); it('excludes stations with no matching fuel type', function () { $station = Station::factory()->create(['lat' => 52.555064, 'lng' => -0.256119]); StationPriceCurrent::factory()->create([ 'station_id' => $station->node_id, 'fuel_type' => FuelType::E10, // not diesel 'price_pence' => 13800, ]); $this->getJson('/api/stations?lat=52.555064&lng=-0.256119&fuel_type=diesel&radius=10') ->assertOk() ->assertJsonPath('meta.count', 0); }); it('excludes temporarily closed stations', function () { $closed = Station::factory()->create([ 'lat' => 52.555064, 'lng' => -0.256119, 'temporary_closure' => true, ]); StationPriceCurrent::factory()->create([ 'station_id' => $closed->node_id, 'fuel_type' => FuelType::B7Standard, 'price_pence' => 14200, ]); $this->getJson('/api/stations?lat=52.555064&lng=-0.256119&fuel_type=diesel&radius=10') ->assertOk() ->assertJsonPath('meta.count', 0); }); it('excludes stations beyond radius', function () { // Station ~100km north $farStation = Station::factory()->create(['lat' => 53.5, 'lng' => -0.256119]); StationPriceCurrent::factory()->create([ 'station_id' => $farStation->node_id, 'fuel_type' => FuelType::B7Standard, 'price_pence' => 14200, ]); $this->getJson('/api/stations?lat=52.555064&lng=-0.256119&fuel_type=diesel&radius=10') ->assertOk() ->assertJsonPath('meta.count', 0); }); it('sorts by price when sort=price', function () { $sLat = 52.555; $sLng = -0.256; $cheap = Station::factory()->create(['lat' => $sLat, 'lng' => $sLng]); $expensive = Station::factory()->create(['lat' => $sLat + 0.001, 'lng' => $sLng]); StationPriceCurrent::factory()->create(['station_id' => $cheap->node_id, 'fuel_type' => FuelType::B7Standard, 'price_pence' => 13900]); StationPriceCurrent::factory()->create(['station_id' => $expensive->node_id, 'fuel_type' => FuelType::B7Standard, 'price_pence' => 14500]); $this->getJson("/api/stations?lat={$sLat}&lng={$sLng}&fuel_type=diesel&radius=10&sort=price") ->assertOk() ->assertJsonPath('data.0.price_pence', 13900); }); it('logs a search record for each request', function () { $station = Station::factory()->create(['lat' => 52.555064, 'lng' => -0.256119]); StationPriceCurrent::factory()->create(['station_id' => $station->node_id, 'fuel_type' => FuelType::B7Standard, 'price_pence' => 14500]); $this->getJson('/api/stations?lat=52.555064&lng=-0.256119&fuel_type=diesel&radius=10'); $this->assertDatabaseHas('searches', [ 'lat_bucket' => '52.56', 'lng_bucket' => '-0.26', 'fuel_type' => 'b7_standard', 'results_count' => 1, 'lowest_pence' => 14500, 'highest_pence' => 14500, ]); }); it('returns 422 when required params are missing', function () { $this->getJson('/api/stations?lat=52.5') ->assertUnprocessable(); });