0

Webmock provides a suggested stub for a Rails controller action.
I have not found proper syntax required for the return body.

The request (abbreviated)

intent = Stripe::PaymentIntent.create({ amount: authorisation.to_i, currency: 'eur', [...] { idempotency_key: @idempotency_key }, ) {client_secret: intent.client_secret}.to_json 

The suggestion:

stub_request(:post, "https://api.[...]payment"). with( body: {"amount"=>"250", "capture_method"=>"manual", "currency"=>"eur", "description"=>" user_747712275", "payment_method_types"=>["card"], "statement_descriptor_suffix"=>"full user_747712275"}, headers: { 'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer nil', [...] }). to_return(status: 200, body: "", headers: {}) 

the response is a long JSON hash, of which - for the time being - the interest remains on the client_secret as above:

{ "id": "3RFaceKOXN2EnLzd0yjHmzkd", "object": "payment", "amount": 250, [...] "client_secret": "pi_3mRFaceKOXN2EnLzd0yjHzkd_secret_if8u6njASlMQ8XJ0bAAvgNo4q", [...] "transfer_data": null, "transfer_group": null } 

no quotes matches the documentation indications for JSON and XML responses, but in that case minitest complains that NameError: undefined local variable or method 'null' for an instance of ApiControllerTest, where null is the API's database value which conflicts with ruby's nil.

At this point, the assumption in order to continue the test to completion of action:
• is it correct to have the hash syntax directly body: { "id": "OXN2EnLzd0yjHmzkd"..
• replace null with nil (any other ruby replacements needed?)

However, this then generates error:
WebMock::Response::InvalidBody: must be one of: [Proc, IO, Pathname, String, Array], but you've used a Hash. Please convert it by calling .to_json .to_xml, or otherwise convert it to a string. which the documentation does not contemplate.

Setting [...] "transfer_group": null } to [...] "transfer_group": nil }.to_json returns error of registered request stubs: [...] with no to_return(status: [...] . In other words the stub has no return.

How should the syntax be cast to have the return available for processing?

3
  • why don't you stub method that calls stripe? like allow(something).to receive(:something).and_return(some_hash)CommentedApr 20 at 14:30
  • 1
    don't mix hash and json. Hash is a ruby object, JSON is a string. request should return a string then whatever the underlying client is, will parse it into a Hash.
    – Alex
    CommentedApr 20 at 21:41
  • @Alex true. Webmock does provide a convenience method though so that you don't have to manually JSON encode mocked responses. github.com/bblimke/…
    – max
    CommentedApr 22 at 21:06

2 Answers 2

2

If you want to stub a JSON response use the aptly named to_return_json method.

stub_request(:post, "https://api.[...]payment"), ...) .to_return_json(status: 200, body: { foo: 'bar', baz: nil }, headers: {}) 

There is no special syntax. The body should just be a plain old Ruby hash corresponding to what the result of parsing the JSON response would be.

    0

    maxanswer was a pointer in the right direction. The method was not in the wiki, but in the readMe.

    It is also relevant to point out what that block states:

    stub_request(:any, "www.example.com"). to_return_json(body: {foo: "bar"}) Net::HTTP.get('www.example.com', '/') # ===> "{\"foo\": \"bar\"}" 

    that last line did cause a few iterations.

    With :get or :any for the stub_request, and then invoking Net::HTTP.get did not generate errors.

    stub_request(:get, "http://[https//api.stripe.com/v1/payment_intents%5D:80/"). with( headers: { 'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby' }). to_return_json(status: 200, body: {client_secret: 'pi_3RFaceKO'}, headers: {}) Net::HTTP.get('https://api.stripe.com/v1/payment_intents', '/') 

    Net::HTTP.post would lead to a NoMethodError: undefined method 'hostname' for an instance of String . Thus the console error message is misleading, in that it never mentions the Net::HTTP call..

    2
    • get has two signatures: get(host, path) or get(uri).Net::HTTP.get('api.stripe.com', 'v1/payment_intents') or preferable Net::HTTP.get(URI('https://api.stripe.com/v1/payment_intents')). note that you're stubbing garbage here: "http://[https//api.stripe.com/v1/payment_intents%5D:80/".
      – Alex
      CommentedApr 25 at 0:34
    • 1
      never mentions the Net::HTTP call - because the error is not in your application code. you have to disable backtrace cleaner Rails.backtrace_cleaner.remove_silencers! to see full trace.
      – Alex
      CommentedApr 25 at 0:38

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.