I have the following RSpec example which is passing:
describe UsersController do
it "should render new template on new action" do
get :new
response.should render_template("users/new")
end
end
The problem is I have not implemented the 'new' action on the UsersController.
Can anyone tell me why this test is passing?
I am new to RSpec, so any tips would be greatly appreciated!
When requesting an action for which a view exists, but the action is not defined, Rails will simply render the view. Therefore your spec (correctly) passes.
In addition to this spec, you may want to test for the assignment of particular instance variables. Example:
it "should assign the found articles for the view" do
assigns[:article].should == [#article]
end
Related
I am somewhat new to testing in rails, and I'm wondering if this is a sufficient test for my new controller.
test "should get new" do
get :new
assert_response :success
end
Controller:
def new
#question = Question.new
end
Because the new action stores the controller in memory and does not write it to the DB, nor does it validate it. This seems sufficient to me. Any thoughts?
Controller testing should generally assert a few things
Controller rendered the correct template
You redirected to the right place
The instance variable has the correct data
Sometimes I also send some extra post variables in to make sure someone isn't goin to be able to curl themselves into an admin.
In our rails 3.1.4 app, rspec is used to test the public method require_signin in application controller. Here is the method require_signin:
def require_signin
if !signed_in?
flash.now.alert = "Log in first!"
redirect_to signin_path
end
end
Here is the rspec code:
it "should invoke require_signin for those without login" do
controller.send(:require_signin)
controller {should redirect_to signin_path}
end
The above rspec generates gigantic multi pages error starting like the below:
RuntimeError:←[0m
←[31mActionController::RackDelegation#status= delegated to #_response.status=, but #_response is nil: #<ApplicationController:0x3
a67f10 #_routes=nil, #_action_has_layout=true, #_view_context_class=nil, #_headers={"Content-Type"=>"text/html"}, #_status=200, #_reques
t=#<ActionController::TestRequest:0x3a68720 #env={"rack.version"=>[1, 1], "rack.input"=>#<StringIO:0x34fad60>, ........
What could be wrong with the rspec code? Thanks so much.
I came across this errror and realized I was triggering a redirect on the controller by calling a helper method I wanted to test, but I hadn't actually instantiated a test request yet. Calling get :index before calling the expectation got rid of the error.
it "redirects if some condition" do
subject.send(:helper_method)
get :action # <= Need this before setting expectation below
response.should redirect_to("/somewhere")
end
If you want to check action mechanics, you should use should_receive before a send call like this
it "should redirect to signin_path" do
controller.should_receive(:redirect_to).with(signin_path)
controller.send(:require_signin)
end
Might not be entirely useful, but I came here after getting the same error. I started with a passing test suite, made some changes, and then started getting errors like:
RuntimeError:
ActionController::RackDelegation#status= delegated to #_response.status=, but #_response is nil:
...many lines...
After taking a closer look at the error, I noticed that it said somewhere:
#flashes={:alert=>"You have to confirm your account before continuing."}
I had just added the :confirmable option in Devise, and realized that all users that I created that I was trying to sign in as were unconfirmed, and as such could not successfully log in. I needed to add confirmed_at Time.now to my factory/fixture creation for users. In your example though, it seems like you are trying to test when not logged in, so I'm not sure this is necessarily applicable.
I'm trying to switch from using respond_to to respond_with in Rails controllers. Everything's going smoothly, except for testing invalid saves in controller specs. Here's an example:
describe MyController do
...
describe "PUT update" do
context "with invalid attributes" do
it "should re-render the edit page" do
style = stub_model(Style)
Style.stub(:find) { style }
Style.any_instance.stub(:save).and_return(false)
put :update
response.should render_template(:edit)
end
end
end
end
This works just fine with my old respond_to style update action, but with respond_with, I get
Failure/Error: response.should render_template("edit")
So, in short - how do I test this? ...Or should I just assume render_with knows what it's doing and not test at all? Any general suggestions?
Cheers in advance
PS: The update action:
def update
#style = Style.find(params[:id])
flash[:notice] = "Style updated" if #style.update_attributes(params[:style])
respond_with(#style)
end
I've been looking into this exact thing (how I found this topic) - so far I have the following:
Location.any_instance.stub(:valid?).and_return(false)
Location.any_instance.stub(:errors).and_return('anything')
(where Location is my model that uses respond_with)
however I believe there must be a nicer way to do it - if I find it, I'll be sure to post it!
Note: I'm also using the responders gem so one of these lines may not be necessary for you if you're not using it!
I have a check_user_access_control before_filter in my ApplicationController that checks the logged user's roles and permissions before it lets him through. I am trying to write some tests on it and I can't find a good way of doing it.
For simple index actions I simply do:
it "allows access to mod" do
login_as(Factory(:mod)) # this is a spec helper
get :index
response.code.should == "200"
end
and it works just fine. For edit/show/create and other actions that need some params, interactions with the database and possible redirect after they run, it needs too many other stuff to be stubbed.
Is there a way to test if a specific action has been called after the before_filters? I am looking for something like controller.should_receive(:action_name) (which doesn't work) to replace the response.code.should == "200" line with.
versions: rails 3.0.4 and rspec 2.5
I tried another approach. We have a method in ApplicationController called redirect_to_login that I am now checking for with controller.should_receive(:redirect_to_login) and works.
While it detects correctly if the user is allowed or not, it stubs the method, which means that the controller action is run whether or not the user is allowed. Moreover the action depends on params and database and we don't want that.
If now I stub the action method with controller.stub!(:action_name), the action is not run but RSpec is still looking for the template. Well, some actions don't have templates, they just end with a redirect_to :action => :somewhere_else or render :text => "foobar" which at this point we don't care about.
In sort, what I need now is to find a way to make RSpec NOT worry about the template's existence.
When stubbing, you could still give a dummy implementation. Inside that implementation you could then raise an error, to make sure all execution is halted, or you do a redirect anyway.
E.g.
controller.should_receive(:redirect_to_log) { redirect_to login_url }
or
controller.should_receive(:redirect_to_log) { raise StandardError.new('login error') }
expect { get :index }.to raise_error
For more information check out the awesome rspec documentation.
Hope it helps.
To extend #nathanvda's answer:
When stubbing, you could still give a dummy implementation. Inside that implementation [...] do a redirect anyway.
You need to specify controller in the block:
expect(controller).to receive(:redirect_to_log) { controller.redirect_to login_url }
RSpec has a matcher that is also called redirect_to that takes precedence when looking up the method. Calling it directly on the controller works around that.
Final solution, with thanks to nathanvda:
it "allows access to moderator" do
login_as(Factory(:mod))
controller.stub!(action) { raise "HELL" }
controller.should_not_receive(:redirect_to_login)
expect { get action }.to raise_error(/HELL/)
end
it "denies access to user" do
login_as(Factory(:user))
controller.should_receive(:redirect_to_login) { raise "HELL" }
expect { get :index }.to raise_error(/HELL/)
end
posted on https://gist.github.com/957565
I'm using RSpec + Shoulda to test my RESTful controller in Rails 3. I'm having trouble figuring out how to test the create action's redirect. The standard RESTful controller should redirect to the show action for the new post. For example, if I have a ProjectsController for a Project model, then upon successful create, that action should:
redirect_to project_url(#project)
Shoulda provides a handy redirects_to macro for handling this. Here is what I have tried:
describe ProjectsController, '#create' do
context "Anonymous user" do
before :each do
#attrs = Factory.attributes_for(:project_with_image)
post :create, :project => #attrs
end
it { should assign_to(:project) }
it { should respond_with(:redirect) }
it { should redirect_to(#project) }
end
end
(Yes, I'm using FactoryGirl, but since I'm only using it for attributes in this case, it shouldn't matter. I think.)
How do I specify the last test there? It should redirect_to(...) what? I've tried #project, project_url(#project).. But I can't figure it out.
Looking at the Shoulda matcher code, I noticed that the redirect_to matcher can accept a block. But I'm not sure how to access the newly created #project object in that block...
Any thoughts?
Haven't tried it, but the problem probably is, that #project is not available in your spec. How about it {should redirect_to(Project.last) } or it {should redirect_to(assigns(:project)) }?