webmock

How to write functioning Webmock stubs with nested data?


I'm trying to write rspec tests. Some of them have to stub calls to external service.

Some of these calls send nested data, and this data never seems to be processed by Webmock correctly.

describe 'calc' do
  before do
    stub_request(:any, url).with(body: hash_including(operation: 'calc'))
  end

  it 'works' do
    request_data = { sale_type: 'money', cover_type: 'money', 
                     region: 'rf', period: 9,
                     adults: 600, children: 750, mice: 500 }

    # This thing makes a HTTP request:
    MiteService.new(login_params).calc(request_data)

    expected_body = { operation: 'calc', product: 'mite3', 
                      sessionID: session, data: request_data }
    expect(WebMock).to have_requested(:post, url).with(body: expected_body)
  end
end

This test is expected to pass. The http call made by service seems to be correct, but Webmock is unable to read any nested data (which is in data part of body in this case).

1) MiteService API calls calc works
 Failure/Error: expect(WebMock).to have_requested(:post, url).with(body: expected_body)

   The request POST http://example.com/api with body {"data"=>{"sale_type"=>"money", "cover_type"=>"money", "region"=>"rf", "period"=>9, "adults"=>600, "children"=>750, "mice"=>500}, "operation"=>"calc", "product"=>"mite3", "sessionID"=>"123"} was expected to execute 1 time but it executed 0 times

   The following requests were made:

   <...>
   POST http://example.com/api with body 'operation=calc&product=mite3&sessionID=123&data=%7B%3Asale_type%3D%3E%22money%22%2C+%3Acover_type%3D%3E%22money%22%2C+%3Aregion%3D%3E%22rf%22%2C+%3Aperiod%3D%3E9%2C+%3Aadults%3D%3E600%2C+%3Achildren%3D%3E750%2C+%3Amice%3D%3E500%7D' with headers {'Accept'=>'*/*', 'Content-Type'=>'application/x-www-form-urlencoded', 'Date'=>'Tue, 25 Dec 2018 08:20:32 GMT', 'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.4.1 (2017-03-22))'} was made 1 time

Solution

  • Made it work for this example by converting fields into json in example spec.

    expect(WebMock).to have_requested(:post, url).with(body: expected_body.to_json)