Mocking login for remote services - Cucumber, Capybara, Rails - ruby-on-rails

I have a Rails application that has changed from user authentication via devise to accessing a remote API for authentication. For the test suite, this requires that I mock the https request for authentication and return a valid response. We are using Cucumber and Capybara for testing and I am attempting to use the webmock Gem to mock the login response.
The login is initiated by a button click on a form (Capybara action 'click_button').
Unfortunately, although webmock appears to be installed correctly (I am able to make a Net::HTTP POST request and this is recognized by Webmock), the POST to the remote authorization facility is not being captured by webmock. I know that the form POST is making its way to the controller, because the stacktrace shows that the POST is being executed in the controller as it should and the error message is "Errno::ECONNREFUSED at ... Failed to open TCP connection".
I have tried:
WebMock.stub_request(:any, '127.0.0.1').to_return(body: {STATUSCODE: 1}.to_json)
and
WebMock::stub_request(:any, '127.0.0.1').to_return(body: {STATUSCODE: 1}.to_json)
and
stub_request(:any, '127.0.0.1').to_return(body: {STATUSCODE: 1}.to_json)
I have tried putting the stub_request call in the devise_steps.rb file, just before the "click_button" command, as well as in the features/support/env.rb and features/support/webmock.rb file.
I assume that what I am doing is so common that it has to be possible, but I have found nothing that indicates why the stub_request is not successful.

So the domain of the remote API for authentication is localhost? So it would be running on the same server with a different port? Then you have to mock the address with the port.
For instance your Rails app is running on port 80 and your auth API is running on 8080 then you have to do this.
stub_request(:any, '127.0.0.1:8080').to_return(body: {STATUSCODE: 1}.to_json)
I think Webmock should support different ports but I'm not 100% sure. Also have you set WebMock.disable_net_connect!(allow_localhost: true)?
https://github.com/bblimke/webmock#external-requests-can-be-disabled-while-allowing-localhost
Edit:
If this is not working, I suggest you make the API URL configurable and e.g. set it in tests to auth-api.com and then mock this.

The root cause of the problem was that the path on the stub_request was not complete. I had misread the webmock documentation....

Related

Stub requests in capybara rspec

I am writing a feature rspec(capybara) which uses stub request. I am stubbing the request in capybara but getting an error that body is different. When I checked, the port number is changing everytime a request is made.
http://127.0.0.1:44949/v2
how to fix the port number everytime a new request is made or any other way to solve this issue ?

Javascript tests using poltergeist and capybara accessing internal api

I am using capbara with poltergeist to run my javascript tests and i often get this error, it is trying to access internal api,it is even worse when my internet connection is off as more tests start failing, I am also using vcr and webmock to test external apis. What might the problem be
Failure/Error: visit user_session_url
Capybara::Poltergeist::StatusFailError:
Request to 'http://www.example.com:65264/users/sign_in' failed to r
reach server, check DNS and/or server status - Timed out with no
open resource requests
Could be a restriction on the app to allow traffic hitting internal API's.
On a side note, PhantomJS is not being actively supported/developed anymore. Consider alternative headless browser solutions. Chrome Headless was suggested by the guy that declared PhantomJS dead.

What is the `__identify__` route that Capybara looks for?

When I disable Webmock or VCR I get the following error in my Rspec tests. Apparently it's looking for an /__identify__ route.
WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: GET http://127.0.0.1:51768/__identify__ with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}
A bit of googling shows that this is something specific to Capybara, but I wasn't able to find out what exactly it's trying to do and why it might need to be stubbed.
Thanks!
You shouldn't be stubbing it - you should be allowing it (like all requests to your app). Its a route added via middleware Capybara installs when it starts up the "server" thread running your app. Capybara needs it to know the app has started up and is ready to go.
For VCR you can configure this way:
VCR.configure do |config|
// more VCR configs here
config.ignore_request do |request|
URI(request.uri).host == "127.0.0.1"
end
end

How to mock requests made by the browser in a Rails app?

WebMock works fine for requests made by the app. But how to mock AJAX requests made by the browser to 3rd party services?
Rails 4.
Finally found 2 answers:
Approach #1: Puffing Billy
A rewriting web proxy for testing interactions between your browser and external sites.
Works like WebMock:
proxy.stub('http://www.google.com/')
.and_return(:text => "I'm not Google!")
Approach #2: Rack Middleware
Although the previous approach can work, I discovered that it does not work with WebMock. So, if you want to mock your browser requests to external services, you can't mock your app requests.
The approach that worked for me is to run a separate Rack app and inject it into the middleware stack:
spec_helper.rb:
def test_app
Rack::Builder.new{
use ExternalServiceMock
run app
}.to_app
end
Capybara.app = test_app
ExternalServiceMock is a rack app that only responds to certain request paths.
For this particular app, all of the external service URI's were stored in configs, and I set them in the spec helper:
ENV[ 'EXTERNAL_SERVICE_URI' ] = 'http://localhost:3000'
This forces all external requests to be sent to the ExternalServiceMock.
So basically you only need to save the response from 3rd party services and stub the request, then you can test it! Also checkout VCR: https://github.com/vcr/vcr.

HTTP Logging in rails?

Does anyone know of a plugin / gem that will log any HTTP requests your rails app may be making when responding to a request? For example if you are using HTTParty to hit an API, how can you see what outbound requests are coming out of your rails app?
You have to tell the outbound HTTP client to use a proxy.
For HTTParty it's fairly simple (from the docs),
class Twitter
include HTTParty
http_proxy 'http://myProxy', 1080
If you're looking for a proxy to set up, personally I like Paros proxy (Java so cross platform and does SSL).
Try also http_logger gem:
require 'http_logger'
Net::HTTP.logger = Logger.new(...) # defaults to Rails.logger if Rails is defined
Net::HTTP.colorize = true # Default: true
This will log all requests that goes through Net::HTTP library.
https://github.com/railsware/http_logger
If you're doing development on your own machine, Charles Proxy is a good option.
In production, you'd probably be better off creating your own logger.debug() messages.
The only way I got this to work was to specify only the IP as the first parameter to the http_proxy call:
http_proxy '10.2.2.1', 8888
The example above, with the http:// prefix, did not work, I got a SocketError: getaddrinfo: nodename nor servname provided
Try my httplog gem, you can customize it to log requests, responses, headers etc.

Resources