Question

In the following test, I'm expecting a visitor to my page who is not logged in to get '404' and for the content-type of the response to be html, which I've expressed like this:

require 'spec_helper'
require 'rspec-rails'
#require 'shoulda'
#require 'shoulda-matchers'
#require 'shoulda/matchers/action_controller'
describe StaticPagesController do
  context "home page without being logged in" do
    before { visit root_path }
    it { should respond_with :missing }
    it { should respond_with_content_type :html }
    it { should_not render_template :application }
    it { should_not render_with_layout }
    it { should_not set_the_flash }
  end
end

This is the controller under test:

class StaticPagesController < ApplicationController
  def home
    if signed_in?
      redirect_to user_path
    else
      render layout: false,
             file: %Q(#{ Rails.root }/public/404),
             formats: [:html],
             status: '404'
    end
  end
end

When I execute the test, the respond_with and respond_with_content_type matchers fail with

NoMethodError: undefined method `content_type' for nil:NilClass
/home/rev/.rvm/gems/ruby-1.9.3-p194/gems/shoulda-matchers-\
1.4.2/lib/shoulda/matchers/action_controller/\
respond_with_content_type_matcher.rb:59:in `response_content_type'

and

NoMethodError: undefined method `response_code' for nil:NilClass
/home/rev/.rvm/gems/ruby-1.9.3-p194/gems/shoulda-matchers-\ 
1.4.2/lib/shoulda/matchers/action_controller/respond_with_matcher.rb:57:
in `response_code'

which is odd, to me, because those methods are:

    def response_content_type
      @controller.response.content_type.to_s
    end

and

    def response_code
      @controller.response.response_code
    end

and that would mean that @controller's response is empty or @controller is nil, which is possible, but doesn't reflect the behavior I see in the browser.

My guess, given that I'm a complete n00b at this (Ruby/Rails/RSpec/etc/MVC development generally), is that I've forgotten a gem or two, or maybe I've done something else stupid, but I can't guess what, and a couple of days of searching haven't turned up any useful clues. Here's the current gem environment:

 thor (0.16.0)
 bundler (1.2.1)
 childprocess (0.3.6)
 sprockets (2.2.2)
 rspec-mocks (2.12.1)
 rspec (2.12.0)
 selenium-webdriver (2.27.2)
 actionmailer (3.2.11)
 rdoc (3.12)
 polyglot (0.3.3)
 shoulda-matchers (1.4.2)
 mocha (0.10.5)
 rack-ssl (1.3.2)
 metaclass (0.0.1)
 shoulda-context (1.0.2)
 bcrypt-ruby (3.0.1)
 mime-types (1.19)
 websocket (1.0.6)
 rspec-rails (2.12.2)
 rspec-expectations (2.12.1)
 rack-test (0.6.2)
 lumberjack (1.0.2)
 treetop (1.4.12)
 stream (0.5)
 sass (3.2.5)
 listen (0.7.2)
 guard-rspec (2.4.0)
 bourne (1.1.2)
 xpath (1.0.0)
 uglifier (1.3.0)
 mail (2.4.4)
 nokogiri (1.5.6)
 activeresource (3.2.11)
 journey (1.0.4)
 rails (3.2.11)
 i18n (0.6.1)
 coderay (1.0.8)
 activemodel (3.2.11)
 activerecord (3.2.11)
 libwebsocket (0.1.7.1)
 rack-cache (1.2)
 builder (3.0.4)
 guard (1.6.1)
 rake (10.0.3)
 bootstrap-sass (2.2.2.0)
 coffee-script-source (1.4.0)
 slop (3.4.3)
 active_attr (0.7.0)
 rack (1.4.4)
 debugger-ruby_core_source (1.1.6)
 debugger (1.2.3)
 columnize (0.3.6)
 coffee-script (2.2.0)
 ffi (1.3.1)
 shoulda (3.3.2)
 sass-rails (3.2.6)
 arel (3.0.2)
 jquery-rails (2.1.4)
 debugger-linecache (1.1.2)
 tilt (1.3.3)
 coffee-rails (3.2.2)
 hike (1.2.1)
 actionpack (3.2.11)
 rb-inotify (0.8.8)
 railties (3.2.11)
 pry (0.9.11.2)
 rspec-core (2.12.2)
 rgl (0.4.0)
 diff-lcs (1.1.3)
 activesupport (3.2.11)
 addressable (2.3.2)
 libnotify (0.5.9)
 capybara (2.0.2)
 json (1.7.6)
 erubis (2.7.0)
 guard-spork (1.4.1)
 execjs (1.4.0)
 multi_json (1.5.0)
 tzinfo (0.3.35)
 spork (0.9.2)
 sqlite3 (1.3.7)
 method_source (0.8.1)
 rubyzip (0.9.9)

If I'm missing any useful information above, please let me know.

Any suggestions as to how to identify why either @controller or @controller.response should be nil here? My cursory attempt to trace the execution was not fruitful.

Thanks in advance,

Derrell

Was it helpful?

Solution

Try replacing before { visit root_path } with before { get :home }.

The "visit" syntax is commonly used with full stack acceptance specs, provided by libraries like Capybara and Webrat. RSpec provides a special context and helper methods for executing a single action in controller specs, which you can read more about here: https://www.relishapp.com/rspec/rspec-rails/v/2-12-2/docs/controller-specs. Calling get(:home) will simulate a GET request to the "home" action of the controller under test. I believe this will set @controller under the hood, as expected by your shoulda matcher.

You may also need to simulate logging the user in to test true and false cases for user_signed_in? in your controller action. If you're using Devise, the Devise wiki has a good walkthrough on setting up RSpec controller specs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top