Home > Mobile >  Mock GoogleAPI request
Mock GoogleAPI request

Time:02-18

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.

  • Related