Is it possible to call GET in a Capybara/Rspec integration test? - ruby-on-rails

I have a Rails 4.2 application....I was adding content compression via this thoughtbot blog post, but I get an error such as:
undefined method `get' for #<RSpec::ExampleGroups::Compression:0x00000009aa4cc8>
Perusing over the capybara docs, it seems like you shouldn't be using get. Any idea how to test the below then in Rails 4?
# spec/integration/compression_spec.rb
require 'spec_helper'
feature 'Compression' do
scenario "a visitor has a browser that supports compression" do
['deflate','gzip', 'deflate,gzip','gzip,deflate'].each do|compression_method|
get root_path, {}, {'HTTP_ACCEPT_ENCODING' => compression_method }
response.headers['Content-Encoding'].should be
end
end
scenario "a visitor's browser does not support compression" do
get root_path
response.headers['Content-Encoding'].should_not be
end
end

In a capybara test you would use visit not get (as described here), but that answer won't actually help you because the test you've written above is not an integration test, it's a controller test.
Move it to spec/controllers and use the controller-specific helpers describe/context/it etc. to construct your tests for your controller. You can set the headers and do the sorts of checks that you're doing in the code you're showing.

Related

using VCR with Rspec in feature scenarios

I have a Rails 4 app that uses a custom authentication gem that authenticates users against a third-party API. The app requires authentication for most actions on the site (visitors can do very little).
I am trying to use VCR to record the api request made during authentication for all of the integration tests, but all examples that I can find on SO and the Relish documentation only cover how to do this with Rspec in a 'describe do' spec, as referenced here:
https://www.relishapp.com/vcr/vcr/v/1-6-0/docs/test-frameworks/usage-with-rspec
Since no customers are involved on this project, I am writing integration tests with Rspec and Capybara instead of Cucumber, so my tests are using the 'feature/scenario' format like so:
feature 'posts' do
scenario 'a user can log in' do
# use vcr for api request
sign_in_user # refers to a method that handles the api call to log in a user, which is what I would like VCR to record.
expect(page).to have_content("User signed in successfully")
end
end
Using the command described in the documentation:
use_vcr_cassette
inside of the 'scenario' block, returns an error:
Failure/Error: use_vcr_cassette
undefined local variable or method `use_vcr_cassette' for #<RSpec::ExampleGroups::Posts:0x007fb858369c38>
I followed the documentation to setup VCR in my spec/rails_helper.rb (which is included by the spec/spec_helper.rb)... which basically looks like this:
require 'vcr'
VCR.configure do |c|
c.cassette_library_dir = 'support/vcr_cassettes'
c.hook_into :webmock
end
Obviously added gem 'vcr' to my Gemfile development/test group and it is a thing in console and binding.pry from inside of a test.
Has anyone used VCR inside of a Rspec feature? or have any suggestions on what I might do as a workaround?
Thanks in advance
Solution: Taryn East got me to the solution, but it is slightly different than the link posted for anyone trying to do this moving forward.
here is the most basic config in spec/rails_helper.rb or spec/spec_helper.rb:
require 'vcr'
VCR.configure do |c|
c.cassette_library_dir = 'spec/cassettes'
c.hook_into :webmock
c.configure_rspec_metadata!
end
using c.configure_rspec_metadata! is required for Rspec to handle the :vcr tag.
And in an Rspec Feature spec:
feature 'users' do
scenario 'logged in users should be able to do stuff', :vcr do
# authenticate user or make other http request here
end
end
Oddly enough, in my tests - VCR is recording the response and if passes the first time, but fails the second time. I traced this to the response being stored differently than it is received.
On a normal request (using excon) like so:
resp = Excon.post(url, :body => data, :headers => { "Content-Type" => "application/x-www-form-urlencoded", "Authorization" => authorization_header })
The response has a header that is accessible in this format:
resp.headers["oauth_token"]
which returns an oauth token.
In the VCR response, it is being stored differently and only accessible as:
resp.headers["Oauth-Token"]
Which is weird, but workable. This may be a bug with VCR or some issue with Excon... too busy to figure that one out right now, but just a heads up in case anyone else uses this setup and gets a passing test with the live http request and a failing test when using the VCR cassette. A quick workaround is to either change the VCR cassette data to match what your code expects, or modify your code to accept either available value.

Cucumber + Capybara testing: AJAX RequestForgeryProtection trouble since Rails 4.1

After updating to Rails 4.1, I got an interesting problem with Cucumber and Capybara in a new project.
Inside a view I placed some thumbnail portraits. The user is supposed to click on a thumbnail image link to receive more information about the person he has chosen. Through the magic of AJAX the information then appears below the thumbnails. Here's how i did it in the view:
<%= link_to( image_tag( ... ), "/controller/action.js&person=#{#person.nickname}", id: #person.thumb_id , remote: true) %
The controller follows the usual proceeding for cases like this with
respond_to do format.js end
etc.
Works perfectly in the browser and I love it.
However, Cucumber and Capybara don't work so smoothly. Here's the Capybara line that's giving me a lot of headache:
When(/^I click on one of the portraits to display the person's stuff$/) do
click_link("jack_sparrow_THUMB") # #user.thumb_id
end
Running the scenario with Cucumber, I receive this error message for the statement above:
Security warning: an embedded <script> tag on another site requested protected
JavaScript. If you know what you're doing, go ahead and disable forgery protection
on this action to permit cross-origin JavaScript embedding.
(ActionController::InvalidCrossOriginRequest)
The problem must have to do with this
http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
Just have a look at the CROSS_ORIGIN_JAVASCRIPT_WARNING provided ... :(
Is there anything I can do to make my tests run again without downgrading to rails < 4.1 or even turning off Request Forgery Protection in general? Help would be very much appreciated.
As per "CSRF protection from remote tags " from the rails guide:
In the case of tests, where you also doing the client, change from:
get :index, format: :js
To:
xhr :get, :index, format: :js
http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#csrf-protection-from-remote-script-tags

Unable to stub current user using restful authentication plugin

I'm working on a Rails 2.1 app. This app uses 'rspec', '1.2.9' and 'rspec-rails', '1.2.9' . This app uses restful authentication plugin. There is a :login_required before filter method that I have in my Application Controller which basically does the authentication check before allowing access to controller method.
I referred to some older stack overflow(so) questions where users had similar issues, PFB the errors that I got when I tried each of the recommended solutions with respect to those questions.
1 How to stub Restul-authentication's current_user method?
The error I got -
undefined method `stub!' for #<User:0xf5a9c07c>
2 Rails, Restful Authentication & RSpec - How to test new models that require authentication
With respect to this question, I added the below line of code as given in the second answer to the same.
The error I got when I added the above line is -
controller.stub!(:authenticate).and_return(true)
undefined method `stub!' for Controller_NameController:Class
On closer observation, I find that something's wrong with why my test cases aren't able to pick up the stub method.
Here's my code below that I've written to call a specific action within a controller.
Here Controller_Name refers to a controller name like Users controller and in that sense the Controller_NameController basically will stand for UsersController.
require 'spec_helper'
describe Controller_NameController do
describe "What action to test" do
describe "what specific field to update as part of action" do
before do
#Controller_NameController.stub!(:login_required).and_return(true) #this line throws error wrt point 2
#does some stuff
end
it "should update the flag by calling the update method" do
##user_session = login_as(stub_model(User))
#UserSession.stubs(:new).returns(#user_session) - these two lines throws errors wrt point 1
put :update_flag, :id => #obj.id, :obj => {:flag_name => 1}
#obj.updated_at.hour.should == Time.now.hour
end
end
end
end
I'm not sure what's exactly wrong here. Any pointers on how to get this working would be very helpful.
Thank you.

Why doesn't get '/foo' work in functional test in Rails 3?

Looking at the Rails Guides http://guides.rubyonrails.org/testing.html#integration-testing-examples and this SO question Rails Functional Test of Arbitrary or Custom URLs, the following should work in a test:
require 'test_helper'
class ApplicationControllerTest < ActionController::TestCase
test "test authentication" do
get "/dash"
assert_response :success
end
end
But I get an error: ActionController::RoutingError: No route matches {:controller=>"application", :action=>"/dash"}
My route is set up and works at the following URL: http://localhost:3000/dash
This is the route:
dash /dash(.:format) {:action=>"population", :controller=>"dashboard"}
Why wouldn't a get with a URL work?
I am running this test from class ApplicationControllerTest < ActionController::TestCase, which is different from dashboard controller. Do you have to run it from the functional test of the same name as the controller?
Working in Rails 3.07 using Test::Unit.
Yes, you do have to run it from the functional test for that particular controller. Rails is trying to be helpful, so it automatically picks what controller it sends the request to based on the test class's name.
You'll probably also need to heed Marian's advice and use the action name rather than the URL:
get :population
And note that the get / post / etc. helper functions behave completely differently in integration tests (I believe your code would be correct there) - that's probably where you're getting hung up. I find this inconsistency irritating as well...
Hope that helps!

Testing RESTful API with Cucumber in a front end less application

Hi I do not have any front end in my app. I am willing to release just a RESTful API which can be used by different clients. Any pointers how should I proceed towards testing it with cucumber? Every action in the controller generates XML feed only. Any pointers or suggestions?
The visit function of webrat accepts a http_method as a second parameter. You can also test your api like in the following cucumber rule:
When /^I restfully delete (?:|the )user "([^\"]*)"$/ do |login|
visit(path_to("user \"#{login}\" page"), :delete)
end
I think Webrat is more than what you need.
For XML feed testing, you don't need a browser simulator like Webrat which would load pages and analyse all the markup (links, forms etc.) when you really don't have any HTML pages.
You rather need something like Curl (http://curl.haxx.se) or Curb (on rubyforge, which are ruby bindings for Curl), or Patron (on rubyforge).
These libraries can make a request header as per your liking (e.g. setting Content-Type, choosing among GET PUT POST DELETE HEAD etc.) and obtain the response, and probably follow 302 redirections when needed.
The response returned, can be then turned into XML object, and XML parsers available for Ruby can be used to test the output. Also, you can write XMLMapping classes (on rubyforge) to convert XML output into Ruby objects and test their attributes etc. This is much cleaner, IMHO.
jayzes has shared his cucumber test steps examples using Rack::Test::Methods, JSONpath, Nokogiri etc to write test for json/xml API, you might want to refer and create more for your own steps.
https://github.com/jayzes/cucumber-api-steps
Once you've set up your RESTful routes, you should be able to use Webrat to visit the different routes. You can then test that each route returns XML which meets your expectations.
Here's a blog post that describes how to test XML output in RSpec:
Testing XML output
Webrat is a headless browser, which simply means that you can simulate a browser without having to open a real browser like FireFox on your development machine. This means that you can simply type something like "visit 'users/'" into your defined steps and simulate a user accessing your application.
Finally the Pragmatic book on RSpec (still in beta), is a great resource on how to use Cucumber, Webrat and RSpec together and drive your application development with BDD.
I was trying to do that and got stuck in a major problem with restful_authentication (using AASM, one of the internal model of restful_auth it seems) and got to that solution to log in:
Given /^I am logged in with a new account$/ do
login = "test"
#current_user = User.new(
:login => login,
:password => 'generic',
:password_confirmation => 'generic',
:email => "#{login}#example.com",
:state => "active"
)
#current_user.save
x = User.find_by_login(login)
x.state = "active"
x.save!
visit "/login"
fill_in("login", :with => login)
fill_in("password", :with => 'generic')
click_button
response.body.should =~ /Logged in successfully/m
end
Modularize it for cleaner testing corpus, this is to demo the concept I found.

Resources