Files
fuel-alert/tests/Feature/Console/BackfillSearchAreasTest.php
Ovidiu U ea22387c9d Reverse-geocode a general area label for logged searches
Each search now stores an `area_label` (district/town) reverse-geocoded from its
coarsened ~1km lat/lng bucket via postcodes.io, surfaced in the Filament Searches
admin as a sortable/searchable column plus an area filter. Geocoding is cached 30
days per bucket, queries a 2km radius so low-density buckets still match the
default 100m miss, and fails gracefully to null. Adds `searches:backfill-areas`
(scheduled hourly) to label existing rows and retry stragglers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 09:05:03 +01:00

51 lines
1.7 KiB
PHP

<?php
use App\Models\Search;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
uses(RefreshDatabase::class);
it('fills the area label for searches missing one, once per bucket', function () {
Http::fake([
'*/postcodes?*' => Http::response([
'status' => 200,
'result' => [['admin_district' => 'Peterborough']],
]),
]);
// Two searches share a bucket; a third is in a different bucket.
Search::factory()->count(2)->create(['lat_bucket' => 52.54, 'lng_bucket' => -0.21, 'area_label' => null]);
Search::factory()->create(['lat_bucket' => 51.50, 'lng_bucket' => -0.14, 'area_label' => null]);
$this->artisan('searches:backfill-areas')->assertSuccessful();
expect(Search::whereNull('area_label')->count())->toBe(0)
->and(Search::where('area_label', 'Peterborough')->count())->toBe(3);
// One reverse-geocode call per distinct bucket, not per row.
Http::assertSentCount(2);
});
it('leaves searches that already have an area label untouched', function () {
Http::fake([
'*/postcodes?*' => Http::response([
'status' => 200,
'result' => [['admin_district' => 'Peterborough']],
]),
]);
Search::factory()->create(['lat_bucket' => 52.54, 'lng_bucket' => -0.21, 'area_label' => 'Manchester']);
$this->artisan('searches:backfill-areas')->assertSuccessful();
expect(Search::where('area_label', 'Manchester')->count())->toBe(1);
Http::assertNothingSent();
});
it('reports when there is nothing to backfill', function () {
$this->artisan('searches:backfill-areas')
->expectsOutputToContain('No searches need an area label.')
->assertSuccessful();
});