dawarich/spec/services/location_search/geocoding_service_spec.rb

179 lines
4.4 KiB
Ruby
Raw Normal View History

2025-08-30 17:18:16 -04:00
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe LocationSearch::GeocodingService do
2025-09-03 13:28:26 -04:00
let(:query) { 'Kaufland Berlin' }
let(:service) { described_class.new(query) }
2025-08-30 17:18:16 -04:00
describe '#search' do
context 'with valid query' do
let(:mock_geocoder_result) do
double(
'Geocoder::Result',
latitude: 52.5200,
longitude: 13.4050,
address: 'Kaufland, Alexanderplatz 1, Berlin',
data: {
2025-09-03 13:28:26 -04:00
'type' => 'shop',
'osm_id' => '12345',
'place_rank' => 30,
'importance' => 0.8
2025-08-30 17:18:16 -04:00
}
)
end
before do
allow(Geocoder).to receive(:search).and_return([mock_geocoder_result])
allow(Geocoder.config).to receive(:lookup).and_return(:photon)
end
it 'returns normalized geocoding results' do
2025-09-03 13:28:26 -04:00
results = service.search
2025-08-30 17:18:16 -04:00
expect(results).to be_an(Array)
expect(results.first).to include(
lat: 52.5200,
lon: 13.4050,
2025-09-03 13:28:26 -04:00
name: 'Kaufland',
address: 'Kaufland, Alexanderplatz 1, Berlin',
2025-08-30 17:18:16 -04:00
type: 'shop'
)
end
it 'includes provider data' do
2025-09-03 13:28:26 -04:00
results = service.search
2025-08-30 17:18:16 -04:00
expect(results.first[:provider_data]).to include(
osm_id: '12345',
2025-09-03 13:28:26 -04:00
place_rank: 30,
importance: 0.8
2025-08-30 17:18:16 -04:00
)
end
it 'limits results to MAX_RESULTS' do
2025-09-02 15:21:22 -04:00
expect(Geocoder).to receive(:search).with(query, limit: 10)
2025-08-30 17:18:16 -04:00
2025-09-03 13:28:26 -04:00
service.search
2025-08-30 17:18:16 -04:00
end
end
context 'with blank query' do
2025-09-03 13:28:26 -04:00
let(:service) { described_class.new('') }
2025-08-30 17:18:16 -04:00
it 'returns empty array' do
2025-09-03 13:28:26 -04:00
expect(service.search).to eq([])
2025-08-30 17:18:16 -04:00
end
end
context 'when Geocoder returns no results' do
before do
allow(Geocoder).to receive(:search).and_return([])
end
it 'returns empty array' do
2025-09-03 13:28:26 -04:00
expect(service.search).to eq([])
2025-08-30 17:18:16 -04:00
end
end
context 'when Geocoder raises an error' do
before do
2025-09-03 13:28:26 -04:00
allow(Geocoder).to receive(:search).and_raise(StandardError.new('Geocoding error'))
2025-08-30 17:18:16 -04:00
end
it 'handles error gracefully and returns empty array' do
2025-09-03 13:28:26 -04:00
expect(service.search).to eq([])
2025-08-30 17:18:16 -04:00
end
end
context 'with invalid coordinates' do
let(:invalid_result) do
double(
'Geocoder::Result',
2025-09-03 13:28:26 -04:00
latitude: 91.0, # Invalid latitude
longitude: 13.4050,
address: 'Invalid location',
data: {}
)
end
let(:valid_result) do
double(
'Geocoder::Result',
latitude: 52.5200,
longitude: 13.4050,
address: 'Valid location',
2025-08-30 17:18:16 -04:00
data: {}
)
end
before do
2025-09-03 13:28:26 -04:00
allow(Geocoder).to receive(:search).and_return([invalid_result, valid_result])
2025-08-30 17:18:16 -04:00
end
it 'filters out results with invalid coordinates' do
2025-09-03 13:28:26 -04:00
results = service.search
expect(results.length).to eq(1)
expect(results.first[:lat]).to eq(52.5200)
2025-08-30 17:18:16 -04:00
end
end
describe '#deduplicate_results' do
let(:duplicate_results) do
[
{
lat: 52.5200,
lon: 13.4050,
2025-09-03 13:28:26 -04:00
name: 'Location 1',
address: 'Address 1',
type: 'shop',
provider_data: {}
2025-08-30 17:18:16 -04:00
},
{
2025-09-03 13:28:26 -04:00
lat: 52.5201, # Within 100m of first location
2025-08-30 17:18:16 -04:00
lon: 13.4051,
2025-09-03 13:28:26 -04:00
name: 'Location 2',
address: 'Address 2',
type: 'shop',
provider_data: {}
2025-08-30 17:18:16 -04:00
}
]
end
2025-09-03 13:28:26 -04:00
let(:mock_results) do
duplicate_results.map do |result|
2025-09-02 15:55:47 -04:00
double(
2025-09-03 13:28:26 -04:00
'Geocoder::Result',
2025-09-02 15:55:47 -04:00
latitude: result[:lat],
longitude: result[:lon],
address: result[:address],
2025-09-03 13:28:26 -04:00
data: { 'type' => result[:type] }
2025-09-02 15:55:47 -04:00
)
end
2025-09-03 13:28:26 -04:00
end
before do
allow(Geocoder).to receive(:search).and_return(mock_results)
2025-08-30 17:18:16 -04:00
end
it 'removes locations within 100m of each other' do
2025-09-03 13:28:26 -04:00
service = described_class.new('test')
results = service.search
2025-08-30 17:18:16 -04:00
2025-09-03 13:28:26 -04:00
expect(results.length).to eq(1)
expect(results.first[:name]).to eq('Address 1')
2025-08-30 17:18:16 -04:00
end
end
end
describe '#provider_name' do
2025-09-03 13:28:26 -04:00
before do
allow(Geocoder.config).to receive(:lookup).and_return(:nominatim)
2025-08-30 17:18:16 -04:00
end
2025-09-03 13:28:26 -04:00
it 'returns the current geocoding provider name' do
expect(service.provider_name).to eq('Nominatim')
2025-08-30 17:18:16 -04:00
end
end
end