Using System Test in Rails 5.1 - ruby-on-rails

I'm trying to add some system tests in my already existing application written in Ruby On Rails. I've already updated the application to Rails 5.1.
When I execute the test, the result is it:
E
Error:
ResponsibleProductsAvailableForStudentsTest#test_responsible_should_not_browse_products_available_for_other_responsible_student:
WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled.
Unregistered request: POST http://127.0.0.1:9515/session with body
'{"desiredCapabilities":{"browserName":"chrome","version":"","platform":"ANY","javascriptEnabled":true,"cssSelectorsEnabled":true,"takesScreenshot":false,"nativeEvents":false,"rotatable":false}}' with headers {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Length'=>'193', 'Content-Type'=>'application/json; charset=utf-8', 'User-Agent'=>'Ruby'}
You can stub this request with the following snippet:
stub_request(:post, "http://127.0.0.1:9515/session").
with(body: "{\"desiredCapabilities\":
{\"browserName\":\"chrome\",\"version\":\"\",\"platform\":\"ANY\", \"javascriptEnabled\":true,\"cssSelectorsEnabled\":true,\"takesScreenshot\":false,\"nativeEvents\":false,\"rotatable\":false}}",
headers: {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Length'=>'193', 'Content-Type'=>'application/json; charset=utf-8', 'User-Agent'=>'Ruby'}).
to_return(status: 200, body: "", headers: {})
============================================================

Related

Stubbed request not allowing http connections (Real HTTP connections are disabled.)

I am trying to stub a POST request to an external API. The spec test does not replace the ENV variable with my fake one and goes to my local env (localhost:3000) in the stub request returning this error:
Failure/Error: response = http.request(request)
WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: POST http://localhost:3000/Target with body '{"name":"Wayfarer"}' with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}
You can stub this request with the following snippet:
stub_request(:post, "http://localhost:3000/Target").
with(
body: "{\"name\":\"Wayfarer\"}",
headers: {
'Accept'=>'*/*',
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
'User-Agent'=>'Ruby'
}).
to_return(status: 200, body: "", headers: {})
My test is:
let!(:user) { create(:user, target: 'Wayfarer') }
before(:each) do
allow(ENV).to receive(:fetch).with('API_METADATA_URL').and_return('http://example.com')
end
describe '#create_target' do
context 'successful API request to create target' do
it 'sends data to API and sets response instance variables' do
target = user.target
stub_request(:post, 'http://example.com/Target').with(
headers: {
},
body: '{
"name": "Wayfarer"
}'
).to_return(
status: 200,
body: '{"id": "uuid",' \
'"name": "Wayfarer",' \
'"created_at": 00000,' \
'"updated_at": 00000}'
)
api_client = ApiClient.new
api_client.create_target(target)
expect(api_client.response_status).to eq(200)
expect(api_client.response_body).to eq(
{
'id' => 'uuid',
'name' => 'Wayfarer',
'created_at' => 00000,
'updated_at' => 00000
}
)
end
end
end
It doesn't even reach the test, instead it seems to run the ApiClient as is including using my local environment variable (as stated above).
I ended up needing a separate .env file for tests (.env.test.local) for the API_METADATA_URL for a url that did not throw the error.

Stub request when request body is different

Hi I am working on RoR project with ruby-2.5.0 and Rails 5. I am stubbing an http request with stub_request. This http request is basically a mailjet api request to send email.
So, I can not just reuse the snippet, rspec spits out to me, because body differs on every execution.
Stub request
stub_request(:post, "https://api.mailjet.com/v3/send").
with(
body: "{\"FromEmail\":\"abc#abc.ocm\",\"FromName\":\"abc\",\"To\":\"abc#abc.com\",\"Subject\":\"Forgot Password\",\"Text-part\":\"xV3SEtaoa1oyYYfYBt12pw\"}",
headers: {
'Accept'=>'application/json',
'Accept-Encoding'=>'deflate',
'Authorization'=>'Basic YmY0NzdhZmYyMmZlMGQwMzAxNzYzNDNkODUwZTY1MzE6YmRhNmZmYzQ0Y2ZmNGM3MmZkZGNkMjUwODA5YWJhZjM=',
'Content-Length'=>'143',
'Content-Type'=>'application/json',
'Host'=>'api.mailjet.com',
'User-Agent'=>'mailjet-api-v3-ruby/1.5.4'
}).
to_return(status: 200, body: "", headers: {})
Here Text-part is different for each user. I tried hash_including method as follows:-
stub_request(:post, "https://api.mailjet.com/v3/send").
with(
body: hash_including({"FromEmail": "abc#abc.com","FromName": "abc"}),
headers: {
'Accept'=>'application/json',
'Accept-Encoding'=>'deflate',
'Authorization'=>'Basic YmY0NzdhZmYyMmZlMGQwMzAxNzYzNDNkODUwZTY1MzE6YmRhNmZmYzQ0Y2ZmNGM3MmZkZGNkMjUwODA5YWJhZjM=',
'Content-Length'=>'143',
'Content-Type'=>'application/json',
'Host'=>'api.mailjet.com',
'User-Agent'=>'mailjet-api-v3-ruby/1.5.4'
}).
to_return(status: 200, body: "", headers: {})
But when i run test it throws an error:-
JSON::ParserError:
765 : unexpected token at ''
Please help me what is the right syntax to use hash_including method. Thanks in advance.

How to stub requests on domain or after method?

config.before(:each) do
stub_request(:post, "https://api.3rdpartysmsprovider.com/send.php?body=This%20is%20a%20test%20message&destination=60123456789&dlr='1'&output=json&password=0000000&reference=#{#text.sms_uid}&sender=silver&username=0000000").
to_return(:status => 200, :body => "01", :headers => {})
end
I am currently writing specs for a service class that sends an SMS and creates a log of it in our database. I'm trying to stub this request, however #text.sms_uid is a SecureRandom.urlsafe_base64 random code. Also I'm stubbing in config.before(:each).
Because of that, I can't specify the sms_uid in stub_request as the random sms_uid is generated after the stub is called. This causes the test to fail every time. Is there a way I can stub the request after it generates the code (in other words, after it goes through the specific method) or is there a way to stub all requests going through the domain "https://api.silverstreet.com"?
I see two options:
Stub SecureRandom.urlsafe_base64 to return a known string and use that known string when you stub_request:
config.before(:each) do
known_string = "known-string"
allow(SecureRandom).to receive(:known_string) { known_string }
stub_request(:post, "https://api.3rdpartysmsprovider.com/send.php?body=This%20is%20a%20test%20message&destination=60123456789&dlr='1'&output=json&password=0000000&reference=#{known_string}&sender=silver&username=0000000").
to_return(status: 200, body: "01", headers: {})
end
If SecureRandom.urlsafe_base64 is used in other places in your application, you'll need to stub it only in the specs where this request is generated.
Yes, you can stub any POST to that hostname
stub_request(:post, "api.3rdpartysmsprovider.com").
to_return(status: 200, body: "01", headers: {})
or even any request of any kind to that hostname
stub_request(:any, "api.3rdpartysmsprovider.com").
to_return(status: 200, body: "01", headers: {})
and webmock has a very large number of other ways to match requests.

Rails RestClient POST request failing with "400 Bad Request"

Looking at the docs there aren't any good examples of how to make a POST request. I need to make a POST request with a auth_token parameter and get a response back:
response = RestClient::Request.execute(method: :post,
url: 'http://api.example.com/starthere',
payload: '{"auth_token" : "my_token"}',
headers: {"Content-Type" => "text/plain"}
)
400 bad request error:
RestClient::BadRequest: 400 Bad Request
from /Users/me/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rest-client-1.8.0/lib/restclient/abstract_response.rb:74:in `return!'
from /Users/me/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rest-client-1.8.0/lib/restclient/request.rb:495:in `process_result'
from /Users/me/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rest-client-1.8.0/lib/me/request.rb:421:in `block in transmit'
Any good examples how to make a POST request using RestClient?
EDIT:
This is how I make the request in the model:
def start
response = RestClient::Request.execute(method: :post,
url: 'http://api.example.com/starthere',
payload: '{"auth_token" : "my_token"}',
headers: {"Content-Type" => "text/plain"}
)
puts response
end
Try using a hash like this:
def start
url= 'http://api.example.com/starthere'
params = {auth_token: 'my_token'}.to_json
response = RestClient.post url, params
puts response
end
If you just want to replicate the curl request:
response = RestClient::Request.execute(method: :post, url: 'http://api.example.com/starthere', payload: {"auth_token" => "my_token"})
Both Curl and RestClient defaults to the same content type (application/x-www-form-urlencoded) when posting data the this format.
In case you land here having the same Issue, Just know that this is a common error that happens when your environment variables are not "set".
I put this in quotes because you might have set it but not available in the current terminal session!
You can check if the ENV KEY is available with:
printenv <yourenvkey>
if you get nothing then it means you need to re-add it or just put it in your bash files
FYI: Putting my ENV variables in my ~/.bash_profile fixed it

How to handle RestClient::ServerBrokeConnection

I am using the latest version of rest-client gem and upon external access I see a lots of RestClient::ServerBrokeConnection errors, how should I handle this?
The following call fails
response = RestClient::Request.execute(method: :post, url: url, headers: headers, "Content-Type" => "application/x-www-form-urlencoded")
This error happens when the server broke the connection with the client. You can decide to retry the request or just bubble the error for the user to know about it and handle it.
Because how rest-client handles broken connections as shown here, all you can do is rescue from it
begin
response = RestClient::Request.execute(method: :post, url: url, headers: headers, "Content-Type" => "application/x-www-form-urlencoded")
rescue RestClient::ServerBrokeConnection
// retry or do something
end

Resources