2

I am writing specs for my first gem. But i am stuck with this weird error. code for my rspec is

describe '#success' do
    let(:resp) { {"TwilioResponse"=>{"SMSMessage"=>{"Sid"=>"0d1c0cbfb2b5e8f97dddb4479bdbbc6a", "AccountSid"=>"exotel_sid", "From"=>"/exotel_sid", "To"=>"1234", "DateCreated"=>"2016-07-18 15:35:29", "DateUpdated"=>"2016-07-18 15:35:29", "DateSent"=>nil, "Body"=>"test sms", "Direction"=>"outbound-api", "Uri"=>"/v1/Accounts/exotel_sid/Sms/Messages/0d1c0cbfb2b5e8f97dddb4479bdbbc6a", "ApiVersion"=>nil, "Price"=>nil, "Status"=>"queued"}}} }
    before{ allow(Generator::Exotel).to receive(:post).with("/#{Generator::configuration.sid}/Sms/send", 
      {:body => {:To => 1234, :Body => 'test sms'},:basic_auth=>{:username=>"#{Generator::configuration.sid}", :password=>"#{Generator::configuration.token}"}}).and_return(resp) }

    it 'returns response object' do  
      response = Generator::Exotel.send(:to => 1234, :body => "test sms")
      expect(response).to eq ({"Status"=>200, "Message"=>"Success"})
    end
  end

when i run rspec i am getting this error

NoMethodError:
       undefined method `code' for #<Hash:0x007ff3625a4800>

This is where my response.code is being called

def handle_response(response)
  response_base = response['TwilioResponse']
  if response_base.include?('RestException')
    response_base['RestException']
  else
    {"Status" => response.code, "Message" => "Success" }
  end
end

I know httparty creates a response object for request and returns response code. But i am not getting how do i create a dummy response_code so that my test case pass. It's nearly 2 days since i am stuck here. Anyone help please. I am really new to ruby and for first time writing spec. Any help will be appreciated.

Update - result for response.inspect

> Generator::Exotel.send(:to => 9030435595, :body => 'jsdhgjkdfg')

it returns following response

> #<HTTParty::Response:0x7fb8c02f93d0 parsed_response={"TwilioResponse"=>{"SMSMessage"=>{"Sid"=>"d6ee0650072c82941ad2f06746d14ab4", "AccountSid"=>"sinscary", "From"=>"/sinscary", "To"=>"9030435595", "DateCreated"=>"2016-07-21 19:56:07", "DateUpdated"=>"2016-07-21 19:56:07", "DateSent"=>nil, "Body"=>"jsdhgjkdfg", "Direction"=>"outbound-api", "Uri"=>"/v1/Accounts/sinscary/Sms/Messages/d6ee0650072c82941ad2f06746d14ab4", "ApiVersion"=>nil, "Price"=>nil, "Status"=>"queued"}}}, @response=#<Net::HTTPOK 200 OK readbody=true>, @headers={"content-type"=>["application/xml"], "date"=>["Thu, 21 Jul 2016 14:26:07 GMT"], "server"=>["Apache/2.2.29 (Amazon)"], "x-powered-by"=>["PHP/5.3.28"], "content-length"=>["542"], "connection"=>["Close"]}>
Sinscary
  • 652
  • 12
  • 32
  • Its likely that somewhere you're calling `xxx.code` where xxx is a hash, you should be calling `xxx[:code]`. Please provide a Minimal, Complete, and Verifiable example : http://stackoverflow.com/help/mcve – Yule Jul 21 '16 at 13:06
  • yes @Yule i am calling `response.code` in my code, where i am making a post request. I have updated my question. – Sinscary Jul 21 '16 at 13:45
  • i tried as you suggested `xxx[:code]` but it returns `nil`, because there is no such key in hash. – Sinscary Jul 21 '16 at 13:52
  • Please put a line `puts response.inspect` in the very beginning of `handle_response` method and share what will be printed. – Aleksei Matiushkin Jul 21 '16 at 14:05
  • @mudasobwa added the result for `response.inspect` – Sinscary Jul 21 '16 at 14:31

1 Answers1

5

OK, you are mocking an HTTParty::Response. One way would be to mock it directly with only code and parsed_response:

let(:resp) do
  Struct.new(:code, :parsed_response).new(200, {"TwilioResponse"=>...})
end

Another way would be to instantiate a real HTTParty::Response with:

let(:resp) do
  HTTParty::Response.new(
    nil, 
    Struct.new(:code, :parsed_response)
          .new(200, {"TwilioResponse"=>...}), -> { ... }
  )
end

I would go with the first approach. Please note, that you probably will need to change in handle_response:

response_base = response['TwilioResponse']

to

response_base = response.parsed_response['TwilioResponse']
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • hey @mudasobwa thanks for reply. Yes the first way is better but i would like to use 2nd way. but i am getting an error `NoMethodError: undefined method 'body' for 200:Fixnum` , any help on that. – Sinscary Jul 21 '16 at 16:53
  • Oh, sorry, I was in rush and posted an incomplete example. As you could see in the `HTTParty::Response#initialize` code I linked, the second parameter there is to be a response object. Please see an update. BTW, I see no reason here to use the 2nd approach, that’s why I was not too picky with re-checking it. – Aleksei Matiushkin Jul 21 '16 at 17:56
  • Hey well thanks, first approach worked. In second approach still getting the same error. Can you explain what's `-> { ... }` this argument is for. – Sinscary Jul 21 '16 at 18:13
  • I linked the code of `HTTParty::Response`’s constructor. What’s the problem to got there and look for all parameters? The third one is to be a `proc`, I do not care what is it for. I guessed there might be any `proc` instance passed, maybe I was wrong. – Aleksei Matiushkin Jul 21 '16 at 18:20
  • hey i was just asking, i don't have that much experience with httparty and rspec. Thanks buddy, your first approach worked like charm. – Sinscary Jul 21 '16 at 18:22
  • @mudasobwa - Why do you use a Struct instead of a double? – B Seven Jul 21 '16 at 18:37
  • @BSeven for the sake of being as much pure Ruby as possible. – Aleksei Matiushkin Jul 21 '16 at 19:15
  • @mudasobwa - That makes sense. I had a feeling there was a good reason. – B Seven Jul 21 '16 at 20:02
  • For some reason to satisfy `response.success?` My `resp` Struct needed to be: `Struct.new(:success?, :parsed_response).new(true, auth_response)` Where `auth_response` is another variable of the response body I wanted returned – Jeff Spicoli May 25 '22 at 17:55
  • 1 up because of the `parsed_response`. I was getting nuts trying to create a double for the response but always receiving ` received unexpected message :[]` – Ramon Dias Jul 07 '23 at 13:59