I've written a controller function that runs a curl command to send a message to a 3rd party service. I'd like to test this function to confirm my message was sent. However, when I use Webmock, it does not block the command. What can I do to validate that the message was sent in an rspec test?
I ended up using Typhoeus which allows me to send custom, curl style web requests in ruby. I can also stub calls with it. The rspec test content looks like:
it 'correctly prepares a new Typhoeus request and runs it' do
Typhoeus::Request.should_receive(:new).with(<request>).and_call_original
Typhoeus::Request.any_instance.should_receive(:run).and_call_original
object.method
end
You could either use ruby to make the HTTP call, or you could wrap the curl command in a module on which you could set an expectation:
module Curl
def self.perform(url)
`curl -s "#{url}"`
end
end
Curl.stub(perform: 'http response')
perform_some_action
expect(Curl).to have_received(:perform).with(the_url)
Related
Sorry for my stupid question.
I added the external api to get response in order to check zipcode's validation.
app/validators/zipcode_validator.rb
class ZipcodeValidator < ActiveModel::Validator
def validate(record)
record.errors.add(:zipcode, :blank) if record.zipcode.blank?
record.errors.add(:zipcode, :not_found) if WmsService.wms_delivery_dates(record.zipcode).nil?
end
end
It works fine in real but failed randomly and took more time when I run rspec.
What's the good solution for this situation?
You should not call external APIs in your tests. There are several methods to avoid it:
VCR gem records API response in first call then then replies it from disk (that is fast and reliable).
Mocking HTTP calls, e.g. with WebMock. You need to write specify mocked request and write a response in your specs. It may help you improve test readability also it helps in testing edge cases.
Wrap your service call in your class and replace it with an RSpec stub.
Wrap your service call in your class that accepts adapters. An adapter is responsible for calling external service. In test env pass a test adapter with predetermined responses.
Hi I am working on ROR project with rails 5 and ruby 2.5.1. I have written test cases in cucumber. When i run cucumber it runs locally i.e it gives the output based on local code but i want to test the remote API. How can i test the remote API without depending on local rails code?. I tried to mention the remote URL as follows:
When(/^I send a GET request to receipt details$/) do
#url = "http://example.com/api/receipts"
end
Then(/^the json response should have main receipt status complete$/) do
header 'login-token', #login_token
header 'user-id', #user_id
response = get #url
response_body = JSON response.body
#id = response_body['data']['id']
expect(response_body['data']['attributes']['status']).to eq('complete')
end
But still it checks for the local routes '/api/receipts'. It doesn't call the URL.
Please help me Thanks in advance.
I have a rails project that serves a JSON API with tests written in RSpec. Often when running specs (request specs, specifically), I’m interested in seeing some details about the HTTP request/response...i.e. the request URL, request body, and response body, ideally JSON pretty-formatted for readability. This isn't for the purposes of documentation but rather as part of the development / debugging process.
I have a helper method I wrote which does this...you just drop a method call into your spec and it prints this stuff out.
But, seems like it would be better if there was a switch that’s part of the running specs. RSpec has custom formatters which I thought might be the right direction, but in trying to build one, I can't figure out how to get access to the request/response objects like you can from inside of your spec.
How can I access the request/response objects in my custom RSpec formatter? Or, perhaps another way to approach the problem?
Here's an approach:
Assuming a rails project, in spec_helper.rb, define a global "after" hook like so:
config.after(:each) do #runs after each example
if ENV['PRINTHTTP']
#use request/response objects here, e.g. puts response.status
end
end
Then, you can conditionally enable by adding the environmental variable on the command-line:
$ PRINTHTTP=1 rspec
I have created nested form and want to test it from terminal. How can I Make POST request that creates 2 records - one for parent and one for child - at once?
Pry can help. This is not "testing" but more "debugging" in terminal.
gem 'pry'
bundle install
and in the beginning of your action accepting post request, let's say create;
def create
binding.pry
...
end
Browser will not respond but you will get what you want in your terminal.
See this railscast for more info.
HTTP-wise, nested forms are no different than regular forms. Rails uses the naming of the fields to separate parent data from child data. Use your browser's inspector to inspect the HTTP request sent when you fill out the form manually. From there, you can see the name of all the fields used. Then, in terminal, you can typically do something like this:
curl --data "parent[foo]=1&child[bar]=2" http://myapp.dev/parent/create
Just replace the parent[foo] and similar with what you find in the inspector, and it should all work. Tail the dev log if you want to see potential errors in the request.
How about to use rspec testing framework?
I am quite new to Selenium. Currently i am using selenium driver for writing test cases in ruby on rails. In the application, I am required to login and Logout for each test cases. So, I exported each test cases from Selenium IDE to rails 3. I am required to use same browser session for multiple test cases. So I am calling Login test before required test case to be executed in a single ruby file. Is it possible to maintain browser session for consecutive next tests in rails 3 either with Selenium Client or Selenium Webdriver?
I got a solution for this issue for Selenium Client/Webdriver in Ruby on Rails 3. To maintain a session from test script to another script, the only thing you need is session variable. Since I have written different Login script and this script is being called in different other script files, so from this another file I have to access the session variable from Login script.
To access variable from Login script, the code inside is being converted to module.
This is how it worked for me:
----Start-----
------Login.rb-----
module ModuleName
def methodName
----Write particular Login code required through selenium---#
#variable = SELENIUM::CLIENT:DRIVER.new \ #---Create browser instance and store in a variable ---#
return #variable #--Return back the variable from this method
end
end
------File1.rb-----
require Login.rb #---Specify with path---#
include ModuleName
Class File < TestCase #--Extending resp. Test Class
def setup
#local = ModuleName.methodName #--Access Module's method that will return session object.
end
def test_file
--Access this #local in rest of the code--#
end
end
-----End----
This was the tweak to access variable from file1 to file2.
I hope this may help somebody.........