dawarich/spec/services/places/name_fetcher_spec.rb
2025-07-12 11:21:38 +02:00

220 lines
5.7 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Places::NameFetcher do
describe '#call' do
subject(:service) { described_class.new(place) }
let(:place) do
create(
:place,
name: Place::DEFAULT_NAME,
city: nil,
country: nil,
geodata: {},
lonlat: 'POINT(10.0 10.0)'
)
end
let(:geocoder_result) do
double(
'geocoder_result',
data: {
'properties' => {
'name' => 'Central Park',
'city' => 'New York',
'country' => 'United States'
}
}
)
end
before do
allow(Geocoder).to receive(:search).and_return([geocoder_result])
end
context 'when geocoding is successful' do
it 'calls Geocoder with correct parameters' do
expect(Geocoder).to receive(:search)
.with([place.lat, place.lon], units: :km, limit: 1, distance_sort: true)
.and_return([geocoder_result])
service.call
end
it 'updates place name from geocoder data' do
expect { service.call }.to change(place, :name)
.from(Place::DEFAULT_NAME)
.to('Central Park')
end
it 'updates place city from geocoder data' do
expect { service.call }.to change(place, :city)
.from(nil)
.to('New York')
end
it 'updates place country from geocoder data' do
expect { service.call }.to change(place, :country)
.from(nil)
.to('United States')
end
it 'saves the place' do
expect(place).to receive(:save!)
service.call
end
context 'when DawarichSettings.store_geodata? is enabled' do
before do
allow(DawarichSettings).to receive(:store_geodata?).and_return(true)
end
it 'stores geodata in the place' do
expect { service.call }.to change(place, :geodata)
.from({})
.to(geocoder_result.data)
end
end
context 'when DawarichSettings.store_geodata? is disabled' do
before do
allow(DawarichSettings).to receive(:store_geodata?).and_return(false)
end
it 'does not store geodata in the place' do
expect { service.call }.not_to change(place, :geodata)
end
end
context 'when place has visits with default name' do
let!(:visit_with_default_name) do
create(:visit, name: Place::DEFAULT_NAME)
end
let!(:visit_with_custom_name) do
create(:visit, name: 'Custom Visit Name')
end
before do
place.visits << visit_with_default_name
place.visits << visit_with_custom_name
end
it 'updates visits with default name to the new place name' do
expect { service.call }.to \
change { visit_with_default_name.reload.name }
.from(Place::DEFAULT_NAME)
.to('Central Park')
end
it 'does not update visits with custom names' do
expect { service.call }.not_to \
change { visit_with_custom_name.reload.name }
end
end
context 'when using transactions' do
it 'wraps updates in a transaction' do
expect(ActiveRecord::Base).to \
receive(:transaction).and_call_original
service.call
end
it 'rolls back changes if save fails' do
allow(place).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
expect { service.call }.to raise_error(ActiveRecord::RecordInvalid)
expect(place.reload.name).to eq(Place::DEFAULT_NAME)
end
end
it 'returns the updated place' do
result = service.call
expect(result).to eq(place)
expect(result.name).to eq('Central Park')
end
end
context 'when geocoding returns no results' do
before do
allow(Geocoder).to receive(:search).and_return([])
end
it 'returns nil' do
expect(service.call).to be_nil
end
it 'does not update the place' do
expect { service.call }.not_to change(place, :name)
end
it 'does not call save on the place' do
expect(place).not_to receive(:save!)
service.call
end
end
context 'when geocoding returns nil result' do
before do
allow(Geocoder).to receive(:search).and_return([nil])
end
it 'returns nil' do
expect(service.call).to be_nil
end
it 'does not update the place' do
expect { service.call }.not_to change(place, :name)
end
end
context 'when geocoder result has missing properties' do
let(:incomplete_geocoder_result) do
double(
'geocoder_result',
data: {
'properties' => {
'name' => 'Partial Place',
'city' => nil,
'country' => 'United States'
}
}
)
end
before do
allow(Geocoder).to receive(:search).and_return([incomplete_geocoder_result])
end
it 'updates place with available data' do
service.call
expect(place.name).to eq('Partial Place')
expect(place.city).to be_nil
expect(place.country).to eq('United States')
end
end
context 'when geocoder result has no properties' do
let(:no_properties_result) do
double('geocoder_result', data: {})
end
before do
allow(Geocoder).to receive(:search).and_return([no_properties_result])
end
it 'handles missing properties gracefully' do
expect { service.call }.not_to raise_error
expect(place.name).to eq(Place::DEFAULT_NAME)
expect(place.city).to be_nil
expect(place.country).to be_nil
end
end
end
end