I am using the google-maps gem.
I am trying to mock/stub api requests unsuccessfully.
module GoogleMap
class Route
attr_accessor :start_location, :end_location
def initialize(start_location, end_location)
@start_location = start_location
@end_location = end_location
end
def driving_duration_in_seconds
route.duration.value
end
def driving_distance_in_meters
route.distance.value
end
def driving_distance_hash
return unless start_location && end_location
{ distance_in_meters: driving_distance_in_meters, duration_in_seconds: driving_duration_in_seconds }
end
private
def coordinates_as_strings(location)
"#{location.latitude},#{location.longitude}"
end
def route
@route ||= Google::Maps.route(coordinates_as_strings(start_location), coordinates_as_strings(end_location))
end
end
end
I need to stub:
WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: GET https://maps.googleapis.com/maps/api/directions/json?destination=37.19687112,116.43791248&key=<apikey>&language=en&origin=2.15362819,-81.63712649 with headers {'Accept'=>'*/*', 'Date'=>'Sat, 12 Feb 2022 21:35:55 GMT', 'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))'}
You can stub this request with the following snippet:
stub_request(:get, "https://maps.googleapis.com/maps/api/directions/json?destination=37.19687112,116.43791248&key=<apikey>&language=en&origin=2.15362819,-81.63712649").
with(
headers: {
'Accept'=>'*/*',
'Date'=>'Sat, 12 Feb 2022 21:35:55 GMT',
'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))'
}).
to_return(status: 200, body: "", headers: {})
If I try a most basic stub I get an error:
stub_request(:any, /maps.googleapis.com/).
to_return(status: 200, body: '', headers: {})
Google::Maps::InvalidResponseException:
unknown error: 783: unexpected token at ''
# .../gems/ruby-2.7.2/gems/google-maps-3.0.7/lib/google_maps/api.rb:64:in `rescue in response'
# .../gems/ruby-2.7.2/gems/google-maps-3.0.7/lib/google_maps/api.rb:60:in `response'
# .../.rvm/gems/ruby-2.7.2/gems/google-maps-3.0.7/lib/google_maps/api.rb:27:in `query'
I think it is erroring out because I am not passing a key in. But I don't see why I should have to pass in a valid api key into a webmock.
I also would not have my route defined by anything. And in order to test that route
can return route.distance.value
etc, I would need to mock with something.
For other tests I was successful in mocking instances, but to test this lib that it actually works, I feel like mocking instance methods and not that an api was actually called is a waste of a test. Maybe this is just a waste of time, and I should assume it works because I am using a gem.
But I was expecting something like this:
RSpec.describe GoogleMap do
let(:start_location) { create(:location) }
let(:end_location) { create(:location) }
context 'GoogleMaps::Route.new(start_location, end_location)' do
let(:subject) { GoogleMap::Route.new(start_location, end_location) }
# I have not been successful in stubbing this with the correct regex
# stub_request(:get, "https://maps.googleapis.com/maps/api/directions/json?destination=<lat>,<long>key=<key>&language=en&origin=<lat>,<long>").
# with(
# headers: {
# 'Accept'=>'*/*',
# 'Date'=>'Thu, 10 Feb 2022 21:09:02 GMT',
# 'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))'
# }).
# to_return(status: 200, body: "", headers: {})
# stub_request(:get, %r{https:\/\/maps\.googleapis\.com\/maps\/api\/directions\/json\?destination=. ,. &key=. &language=en&origin=. ,. }).
# stub_request(:any, /maps.googleapis.com/).
# to_return(status: 200, body: '', headers: {})
xit 'gives driving distance in seconds'
xit 'gives driving duration in meters'
end
end
CodePudding user response:
Your WebMock is working fine. Google::Maps::InvalidResponseException
is raised after WebMock has replaced the network call. At the point that exception is raised, the Google Maps API client is trying to parse what the network call returned, which is ''
.
It's expecting some valid JSON to be returned. If you have your mock return {}
is should get past that line. It may well stumble on some other exception later though, as the gem expects a certain schema.
You can dig that out and add in a valid response if you wanted to continue down this path. However, I'd recommend not mocking the network request as that's an implementation detail of a third party piece of code which could change at any time - making your test fail. Instead, I would mock out Google::Maps.route
to return what you need it to.