Search code examples
ruby-on-railsruby-on-rails-4stubbraintreewebmock

Webmock: how to fake a gzipped response?


I don't have much experience with stubbing and am having issues with requests to Braintree using webmock and braintree-rails.

spec/spec_helper.rb

RSpec.configure do |config|
  config.include(ConnectionHelper)

  config.before(:each) do
    stub_request(:post, /.*braintree.*/).
    with(braintree_hash).to_return(gzipped_response)
  end
end

spec/support/connection_helper.rb

def gzipped_response
  {
    status: 200,
    body: "\u001F\x8B\b\0:\x87GU\0\u0003\u0003\0\0\0\0\0\0\0\0\0",
    headers: {}
  } 
end

def braintree_hash
  { :body => /.*/,
    :headers => {'Accept'=>'application/xml', 'Content-Type'=>'application/xml',
    'User-Agent'=>'Braintree Ruby Gem 2.42.0 (braintree-rails-1.4.0)',
    'X-Apiversion'=>'4'}
  }
end

Rspec error:

2) Content: when ordering content show page has relevant information 
     Failure/Error: click_button "Order"
     Braintree::UnexpectedError:
       expected a gzipped response
     # ./app/classes/payment.rb:13:in `generate_token'
     # ./app/controllers/posts_controller.rb:44:in `pay'
     # ./spec/features/content_spec.rb:251:in `block (4 levels) in <top (required)>'

I'm trying to test the page, not the payments themselves, however when rendering the page a token needs to be retrieved first and so I'm getting this error.

How would I go about faking a gzipped response, or alternatively skip anything to do with Braintree requests in my tests?

app/controllers/posts_controller.rb

def pay
  @post = Post.find(params[:id])
  @client_token = Payment.new(current_user).generate_token
end

app/classes/payment.rb

class Payment    
  def initialize(customer)
    @customer = customer
    @customer_id = @customer.id
  end

  def generate_token
    Braintree::ClientToken.generate(customer_id: @customer_id)
  end   
end

Solution

  • I work at Braintree. If you have any questions specifically about our API and client libraries, you can always reach out to our support team.

    Your stubbed response body needs to be gzipped. You can create an empty gzipped string like this:

    irb(main):010:0> require 'stringio' 
    => false
    irb(main):011:0> require 'zlib'
    => false
    irb(main):012:0> Zlib::GzipWriter.new(StringIO.new("w")).close.string
    => "\u001F\x8B\b\0:\x87GU\0\u0003\u0003\0\0\0\0\0\0\0\0\0"
    

    So try this for your status_ok method:

    def status_ok
      {
        status: 200,
        body: "\u001F\x8B\b\0:\x87GU\0\u0003\u0003\0\0\0\0\0\0\0\0\0",
        headers: {"Content-Encoding" => "gzip"}
      } 
    end