getting httparty undefined method `code' for #<Hash:0x007ff3625a4800> in rspec - ruby-on-rails

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"]}>

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']

Related

file_fixture_upload always passes File object as string in rspec rails 6

I am trying to upload a file in rspec and use that file in my controller. Everything worked fine in Rails 4 but now in Rails 6, the Rack::Test::UploadedFile hash when received in controller, my tempfile filed is a File hash string object which makes it impossible to be used.
describe V1::ApplicationsApiController, type: :request do
let(:ic_front) { fixture_file_upload(file_fixture("ic_front.jpg")) }
let(:ic_back) { fixture_file_upload(file_fixture("ic_back.png")) }
context "Loan Eligibility Check Screening" do
it "runs background check v1.0.1" do
payload = {
"ic_front" => ic_front,
"ic_back_path" => ic_back,
"data" => {
"product_code" => product.code,
"include" => ["fico"],
"applicant" => {
"name" => "Florian Test 1",
"ic_or_passport_no" => "1234567890",
"consented_at" => Time.now.iso8601,
}
}
}
VCR.use_cassette('ic_check_and_ctos') do
post "/api/v1.0.1/applications/background_check", params: payload, as: :json
expect(response.status).to eq 200
end
end
end
end
Now in my controller, i get the following in params[:ic_front]
<ActionController::Parameters {"original_filename"=>"ic_front.jpg", "tempfile"=>"#<File:0x0000558457ecd5c0>", "content_type"=>nil} permitted: false>
In my controller, i want to be able to get the params[:ic_front].tempfile.path which i cannot do because tempfile is a string file hash.
I have added
include ActionDispatch::TestProcess
include Rack::Test::Methods
in my rails_helper.rb but didnt work. I tried moving into my tests but also didn't work as well.
Appreciate any new input on this

Stub JSON.parse in RSPEC

I'm doing some RSPEC testing here.
If i have this method:
JSON.parse("https://test.com/return_json/reviews.json")
Then I can stub it RSPEC like:
test_reviews = {"reviews" => [{"data1" => "1", "data2"=> "2"}]}
allow(JSON).to receive(:parse).and_return(test_reviews.to_json)
But for this kind (with other method inside (to_uri & read)).
JSON.parse("https://test.com/return_json/reviews.json".to_uri.read)
I tried to used receive_message_chain but no success.
Thanks in advance guys!
You code is not actually calling the url you. You need to make an http call and parse the body. I should probably look like this.
describe :ReviewsController
let(:uri) { URI('https://test.com/return_json/reviews.json') }
let(:reviews) { {"reviews" => [{"data1" => "1", "data2"=> "2"}]} }
before do
stub_request(:get, uri).
with(headers: {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(status: 200, body: JSON.dump(reviews), headers: {})
end
it 'does whatever you want' do
response = Net::HTTP.get(uri)
expect(JSON.parse(response.body)['data1']).to eq('1') # or whatever you want to test
end
end
It's better explained here.

response.body is "" even though webmock .to_return(:body => "return") is set

I'm writing unit tests for a Rails service using minitest. A snippet of my test looks like this:
stub_request(:get, #service_url)
.with(:headers => #authheader)
.to_return(:body => "ABC", :status => 200)
get :index
After the get :index, response.code is 200 as expected (and I've changed it to 201 in the .to_return and seen that code be correct after get :index, but every time response.body is "". I'm sure I'm just doing something unimaginably dumb here and welcome being told what a dummy I am. :)
Thanks in advance
minitest 5.8.2
webmock 3.0.1
rails 4

RSpec allow_any_instance_of does not work within request test

I'm new to RSpec, and testing out some webhook test with request type.
But here even I use allow_any_instance_of, it errors out got 500 instead of 200. I checked every variable with binding.pry but it seems all okay.
In my opinion, the mocking fails so it returns 500.
Any ideas?
describe "stripe_invoice_created_webhook", type: :request do
let(:card_invoice){ create(:card_invoice, id: invoice.id) }
let(:invoice){ create(:invoice, payment_account_id: payment_card_account.payment_account_id) }
let(:payment_card_account){ create(:payment_card_account,
stripe_customer_id: event.data.object.customer) }
let(:event){ StripeMock.mock_webhook_event('invoice.created', {
closed: false
}) }
it 'responds 200 to invoice_created webhook with valid endpoint' do
allow_any_instance_of(CardInvoice).to receive(:process_invoice_items)
allow_any_instance_of(CardInvoice).to receive(:process!)
post '/stripe-events', event.as_json
expect(response.status).to eq 200
expect{ card_invoice.process_invoice_items }.not_to raise_error
expect{ card_invoice.process! }.not_to raise_error
end
and the original code is
class InvoiceCreated
def call(event)
invoice = event.data.object
# NOTE: Skip if the invoice is closed.
if invoice.closed == false
stripe_customer = invoice.customer
payment_account = PaymentCardAccount.find_by(stripe_customer_id: stripe_customer)
card_invoice = Invoice.find_card_invoice_in_this_month_within(payment_account: payment_account)
card_invoice.process_invoice_items(stripe_customer: stripe_customer,
event_invoice_id: invoice.id)
card_invoice.process!(:pending, id: invoice.id)
end
end
end
Yeah the mocking fails. You are expecting the object CardVoice to receive process! or process_invoice_item but you have notnta specified a return value. The syntax for allow_any_instance_of is
allow_any_instance_of(Object).to receive(:function).and_return(:return_value)

Getting undefined method in Controller yet method exists and works in Rails console

I am attempting to build a simple web app that takes data passed in to a text field and delivers it to an API. I have created a model with some methods to do some basic calls to the API. I have set up a form with a text field and a submit button to pass along the data to a controller. When I submit I am getting an error that the method I am calling is not defined. Yet if I go in the console and try the same thing it works as expected. Any suggestions on what I am missing?
Model:
def update(serial, deploy_value)
HTTParty.post("#{BASE_URL}devices/update/serial/#{serial}?#{API_KEY}",
:body => {"customFieldValues": [{"name": "Deploy","value": "#{deploy_value}"}] }.to_json,
:headers => { 'Content-Type' => 'application/json'}
)
end
Controller
class GroundControlController < ApplicationController
require 'GroundControl'
def update
serial = params[:serial]
GroundControl.new.update(serial, "TEST")
redirect_to(:back)
end
end
The error I am getting:
NoMethodError in GroundControlController#update
undefined method `update' for GroundControl:0x007fa062aa1298
From the console I can do the following:
2.3.0 :002 > require 'GroundControl'
=> true
2.3.0 :003 > test = GroundControl.new
=> #<GroundControl:0x007fa2676a8838>
2.3.0 :004 > GroundControl.new.update("ABC123", "TEST")
=> #<HTTParty::Response:0x7fa2671fb218 parsed_response={"id"=>43270, "serial"=>"ABC123", "udid"=>nil, "name"=>nil, "model"=>nil, "os"=>nil, "connected"=>false, "customFieldValues"=>[{"name"=>"Deploy", "value"=>"TEST"}]}, #response=#<Net::HTTPOK 200 OK readbody=true>, #headers={"server"=>["nginx/1.6.3"], "date"=>["Tue, 12 Apr 2016 15:09:27 GMT"], "content-type"=>["application/json; charset=utf-8"], "content-length"=>["150"], "connection"=>["close"], "access-control-allow-origin"=>["*"]}>
2.3.0 :005 >
More info on the error I am getting:
NoMethodError in GroundControlController#update
undefined method `update' for #
Extracted source (around line #10):
8 def update
9 serial = params[:serial]
10 GroundControl.new.update(serial, "TEST")
11 redirect_to(:back)
12
13 end

Resources