RSpec testing in Rails and 304 HTTP status code - ruby-on-rails

Using Devise for authentication. On a controller that has:
before_filter authenticate_user!, :except => [ :index, :show ]
I always get 304 Not Modified status code instead of 200 OK on the authenticated actions, even in the browser while signed in. The views render and work just fine.
It's stopping my tests from passing:
describe 'GET index' do
it 'should be successful' do
get 'index'
response.should be_success # Fails due to 304 status code
end
end
I thought it was my controller's fault at first, but besides the before_filter and decent_exposure, the controller couldn't be any more common.
What could possibly be the root of this issue?

304s are a good thing. In this case, it is what is expected (and desired) even though it may be giving some of your tests trouble. A 304 means that your webserver and client are communicating in a way to allow caching of the webserver's response.
I'm not entirely familiar with Rails, but I'd suspect there is a built in mechanism which is caching your responses. Here is a Rails article on caching:
http://guides.rubyonrails.org/caching_with_rails.html
And here is what looks like a way to disable caching on the Controller/Action level (ignore the parts about iframes... also this might not be the best way):
http://arjunghosh.wordpress.com/2008/04/29/how-to-force-the-browser-to-not-cache-in-rails/

The tests were failing because I was using Devise for authentication with the confirmable module and was not using confirmed users.
After setting the confirmed_at attribute in the factory, all tests passed.

Related

Do I need to generate a controller for a Ruby on Rails Controller call?

I'm setting a session variable to a user's geographical state. I have to use a session variable because I run code on the server specific to that user on page load and I need to know where they are. This code is set up to just update the session variable.
states_controller.rb
class StatesController < ApplicationController
def loc
session[:location] = params[:location]
end
end
routes.rb
post "states/loc" => "states#loc"
The code routes properly and the session variable is updated.
However, when the process is complete I get a 500 error in the console "Missing Template" in the views directory. I haven't seen any tutorials tell users to call the command "rails generate controller" and I'm in the unique situation where I can't call this command.
What possible side effect are there to ignoring this 500 error?
*I'm running an older version of ruby and rails.
What possible side effect are there to ignoring this 500 error?
Each request is crashing your rails server. Thats not good. Since it means that some cases it may have to restart after every failed request - that eats resources like Homer Simpson at a buffet.
Your app should not be raising uncaught exceptions that cause 500 errors - thats just decent professional practice.
So how do I fix it?
Simple, if you don't want the default behavior of rendering a view tell rails to do something else:
class StatesController < ApplicationController
def loc
session[:location] = params[:location]
head :created
end
end
This sends an empty response with the 201 - CREATED http header.
See Rails Guides - Layouts and Rendering in Rails

Is it possible to call GET in a Capybara/Rspec integration test?

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.

Write a failing test for an action that has no route, even with asset pipeline turned on

I'm on rails 3.2 with the asset pipeline turned on. I'm testing for an action that I haven't built yet (TDD; trying to get the test to fail first). When I initially run the test, I get a failure as expected.
class AccountsControllerTest < ActionController::TestCase
def test_my_path
get :my_path
puts #response.body
assert_template :my_path
end
end
#=> test_my_path(AccountsControllerTest): AbstractController::ActionNotFound: The action 'my_path' could not be found for AccountsController
When I add the corresponding view (app/views/my_path.html.erb), I still expect the test to fail since I haven't specified a route for this action. It passes though, and I think it's because the page is being rendered by the asset pipeline. In the view I call <%= request.fullpath %> and that spits out /assets?action=my_path from the puts #response.body call.
When I try to access accounts/my_path in the browser, I see "No route matches [GET] "/accounts/my_path"", so I want to make sure I have a test that's failing too. Why is this happening and how should I fix the test? Should I instead be testing the route separately with assert_recognizes? For the sake of narrowing down the source of the problem, my routes file is currently empty.
Firstly, Rails controller renders existing template even if there is not corresponding action defined ( http://guides.rubyonrails.org/layouts_and_rendering.html#rendering-by-default-convention-over-configuration-in-action ) . This is why your test passed after you added template.
Functional tests call the controller action directly and don't go through the router. So the tests pass even if route is not defined, and does not work in browser. Use separate test cases for routes testing (or test routes in integration tests).

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