Undefined Method error 'has_content?' with rspec/capybara/rails3 - ruby-on-rails-3

I am getting an undefined method 'has_content?' error on an rspec controller_spec file.
I found a thread with similar issues though that thread said the issue was fixed in rspec2.0beta (it was a fairly old thread) but I'm getting this with a more recent version. Some threads on rspec shows that capybara doesn't work in view specs, but I'm working in the controller specs so that shouldn't be the issue...
My Gemfile info looks like this:
rspec-rails+ dependecies 2.6.0.rc6
capybara 0.4.1.2
rails 3.0.7
I am trying to do a simple assert like
response.body.should have_content("Project A")
Thanks for the response,
Tony

Capybara is only included in Rspec request specs by default. Change this file to a be a request spec (put it in the request specs directory, change the title of it...)
Read the capybara Readme section 'Using Capybara with RSpec'
https://github.com/jnicklas/capybara
Also, if these are the types of asserts you're looking to do, this qualifies as a request spec more than it is a controller spec.

Related

Why does rspec-rails skip the middleware?

I have a Rails app (3.2.12) that I wanted to add locale switching via HTTP Accept-Language header.
What I did to achieve that:
I added rack-contrib to my Gemfile:
gem 'rack-contrib', require: 'rack/contrib'
ran bundle install, added the middleware to my config/application.rb:
config.middleware.use Rack::Locale
and inspect the request env my controller:
puts request.env.keys.select{|v| v=~/rack/ }
The spec I run is a controller spec, it has render_views in it.
My problem:
There's no rack.locale key in the request environment. I double-checked rake middlware, it lists Rack::Locale toward the end, right before run MyApp::Application.routes.
After some debugging I found out that the middleware is never called when I run
rspec spec/controllers/authentication_controller_spec.rb
BUT: Running the same code in script/rails s thin gives me more keys in the request env, namely:
rack.request.cookie_string
rack.locale
rack.request.query_string
rack.request.query_hash
So, I guess the question is: Why does RSpec refuse to pick up a Rack middleware?
Controller specs do not go through the stack, they pretty much call directly on the controller itself. You'll probably want to use Rspec's request type tests for this.

Routing error when updating to Rails 3.2.6 or Rspec 2.11.0

After upgrading to Rails 3.2.6 or Rspec 2.11.0, my specs starts to show routing errors like the following:
4) UsersController GET activate activation code not exist
Failure/Error: subject{ get :activate }
ActionController::RoutingError:
No route matches {:controller=>"users", :action=>"activate"}
There is also a after each hook error
An error occurred in an after(:each) hook
RSpec::Mocks::MockExpectationError: (#<EmailSubscriber[...]>).update_attributes({:enable=>true})
expected: 1 time
received: 0 times
occurred at [...]/spec/controllers/users_controller_spec.rb:75:in `block (3 levels) in <top (required)>'
The application in development mode still runs fine.
Both Rspec 2.11.0 and Rails 3.2.6 uses the latest Journey gem (1.0.4). It has some problems, and by explictly lock it to the previous version the spec error disappears.
gem 'journey', '1.0.3'
UPDATE
I recently updated Rails to 3.2.11 with Journey 1.0.4, and all spec passed. My Rspec is 2.11.0
Therefore there is no need to downlock journey anymore, just update Rails.
It appears that the environment is stricter in functional tests than it is in production or development.
In the latter two, it is unable to "know" the parameter names beforehand as they are determined by looking at the according/matching route definition.
In a test, however, one provides the parameter name explicitly. This allows the environment to be more picky.
As that behaviour drifts away from the principle of having a test-env match a prod-env as closely as possible, I consider it a bug and filed an issue accordingly (https://github.com/rails/journey/issues/59).
In order to work around the problem for now, make sure your parameter names match your routes exactly.
I suggest adding the according routes until an outcome is decided in regards to the filed issue. That way, if it's consired a bug and resolved, you just need to remove the routes again - instead of fiddling with your production logic on controller level (which is working flawlessly already).

Testing the asset pipeline with Capybara

I want to do simple request specs in my Rails 3.1 application with Capybara. The standard cases all work as expected, but when I want to test CSS generated by the asset pipeline, I receive the following error:
Failure/Error: visit '/assets/main.css'
ActionController::RoutingError:
No route matches [GET] "/assets/main.css"
I think the problem is that the test environment does not provide a complete server and so also no Sprockets middleware delivering the assets.
Is there a solution to this problem?
EDIT: Now possible!
We updated to Rails 3.2.12 and Capybara 2.0.2, now the assets are also available in the feature specs.
The Phusion guys blogged about a possibility to render an asset to a string:
MyApp::Application.assets.find_asset('main.css').body
You can also use this in tests. The solution is not ideal and/since Capybara isn't involved anymore, but it helps in my specific case to validate CSS. Better approaches are welcome!

RSpec View testing with Rails3 and RSpec2

RSpec2 does not include an have_tag test helper. Using webrat's have_tag or have_selector matchers instead is not possible because Webrat and Rails 3 are not compatible yet. Is there a way to write useful RSpec view tests? It is possible to use assert_select instead of have_tag, but then one could Test::Unit tests in the first place. Or is it no longer recommendable to write RSpec view tests, because integration tests with Capybara or Cucumber are better?
Actually, Webrat works with Rails 3. I have tested this and I was able to use the have_selector matcher (have_tag didn't work).
You can take a look at this Google group discussion. Basically, you don't need the Webrat.configure block mentioned in the webrat readme, and following the mailing list solution, add these lines in your spec_helper.rb:
include Webrat::Methods
include Webrat::Matchers
As you can see, Webrat is not so updated anymore, so yes, you might be better off with integration testing with Cucumber (+ Capybara).
Webrat caused too much trouble, it is also possible to use Capybara with RSpec. The Capybara DSL (with the functions has_selector?, has_content?, etc.) is available for the following RSpec tests: spec/requests, spec/acceptance, or spec/integration.
If you use the latest version of Capybara (~> 1.0.1) - older versions like 0.4.0 won't support this - and add the following lines to your spec_helper.rb file
require "capybara/rspec"
require "capybara/rails"
then you could write for example the following RSpec request test
require 'spec_helper'
describe "Posts" do
describe "GET /blog" do
it "should get blog posts" do
get blog_path
response.status.should be(200)
response.body.should have_selector "div#blog_header"
response.body.should have_selector "div#blog_posts"
end
end
end

no such file to load -- action_controller/integration - NoMethodError for Rails 3 and Webrat

I'm getting the following failure during RSpec tests..
no such file to load -- action_controller/integration
..using Rails 3, RSpec 2 and Webrat, if I include the Webrat helpers in the following way (the idea was to use Webrat for the have_tag and have_selector methods instead of assert_select).
RSpec.configure do |config|
..
config.include Webrat::HaveTagMatcher
end
Yet apparently Webrat and Rails 3 are not compatible yet. One solution is to avoid the Webrat gem and to use assert_select instead. Has anyone a better solution? How do you avoid the error?
I have not found a solution for this problem, only a work around. You can use the have_selector method of Capybara instead of Webrat, at least in RSpec request tests. There are certain difficulties with RSpec2 and Capybara (page.should have_selector only works if you use Capybara's 'visit' method, and not the RSpec method get '/some/path'), but basically it works.