dawarich/spec/services/location_search/geocoding_service_spec.rb
2025-09-03 19:28:26 +02:00

200 lines
No EOL
4.9 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe LocationSearch::GeocodingService do
let(:query) { 'Kaufland Berlin' }
let(:service) { described_class.new(query) }
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: {
'type' => 'shop',
'osm_id' => '12345',
'place_rank' => 30,
'importance' => 0.8
}
)
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
results = service.search
expect(results).to be_an(Array)
expect(results.first).to include(
lat: 52.5200,
lon: 13.4050,
name: 'Kaufland',
address: 'Kaufland, Alexanderplatz 1, Berlin',
type: 'shop'
)
end
it 'includes provider data' do
results = service.search
expect(results.first[:provider_data]).to include(
osm_id: '12345',
place_rank: 30,
importance: 0.8
)
end
it 'caches results' do
expect(Rails.cache).to receive(:fetch).and_call_original
service.search
end
it 'limits results to MAX_RESULTS' do
expect(Geocoder).to receive(:search).with(query, limit: 10)
service.search
end
context 'with cached results' do
let(:cached_results) { [{ lat: 1.0, lon: 2.0, name: 'Cached' }] }
before do
allow(Rails.cache).to receive(:fetch).and_return(cached_results)
end
it 'returns cached results without calling Geocoder' do
expect(Geocoder).not_to receive(:search)
results = service.search
expect(results).to eq(cached_results)
end
end
end
context 'with blank query' do
let(:service) { described_class.new('') }
it 'returns empty array' do
expect(service.search).to eq([])
end
end
context 'when Geocoder returns no results' do
before do
allow(Geocoder).to receive(:search).and_return([])
end
it 'returns empty array' do
expect(service.search).to eq([])
end
end
context 'when Geocoder raises an error' do
before do
allow(Geocoder).to receive(:search).and_raise(StandardError.new('Geocoding error'))
end
it 'handles error gracefully and returns empty array' do
expect(service.search).to eq([])
end
end
context 'with invalid coordinates' do
let(:invalid_result) do
double(
'Geocoder::Result',
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',
data: {}
)
end
before do
allow(Geocoder).to receive(:search).and_return([invalid_result, valid_result])
end
it 'filters out results with invalid coordinates' do
results = service.search
expect(results.length).to eq(1)
expect(results.first[:lat]).to eq(52.5200)
end
end
describe '#deduplicate_results' do
let(:duplicate_results) do
[
{
lat: 52.5200,
lon: 13.4050,
name: 'Location 1',
address: 'Address 1',
type: 'shop',
provider_data: {}
},
{
lat: 52.5201, # Within 100m of first location
lon: 13.4051,
name: 'Location 2',
address: 'Address 2',
type: 'shop',
provider_data: {}
}
]
end
let(:mock_results) do
duplicate_results.map do |result|
double(
'Geocoder::Result',
latitude: result[:lat],
longitude: result[:lon],
address: result[:address],
data: { 'type' => result[:type] }
)
end
end
before do
allow(Geocoder).to receive(:search).and_return(mock_results)
end
it 'removes locations within 100m of each other' do
service = described_class.new('test')
results = service.search
expect(results.length).to eq(1)
expect(results.first[:name]).to eq('Address 1')
end
end
end
describe '#provider_name' do
before do
allow(Geocoder.config).to receive(:lookup).and_return(:nominatim)
end
it 'returns the current geocoding provider name' do
expect(service.provider_name).to eq('Nominatim')
end
end
end