view.stub in rails partial rspec gives 'undefined method view_context' - ruby-on-rails

using Rails 3.2.11
I have a couple of view rspec tests where I need to stub the 'current_user' call.
I've used this successfully in a regular view test like so:
require 'spec_helper'
describe "projects/_my_project.html.erb" do
before(:each) do
#client = FactoryGirl.create(:user)
view.stub(:current_user) { #client }
end
describe "new proposals notice" do
it "does not display new_propsals if in state posted and clicked after last submitted" do
#my_project = FactoryGirl.build(:project, status: "posted", last_proposals_click: "2012-02-02 14:01:00", last_proposal_submitted: "2012-02-02 14:00:00")
render :partial => "/projects/my_project", :locals => { :my_project => #my_project }
rendered.should_not have_content "You received new proposals"
end
end
end
Current_user is defined by Devise in controllers/helpers.rb (in the gem). I use it all over the place as current_user (as a method, not instance) in the view or controller.
The problem seems to be around view in view.stub being nil here, is there another object that is used in case of partials?? I simply don't understand why this works perfect in a regular view and not in a partial.
I get:
Failure/Error: view.stub(:current_user) { #client }
NoMethodError:
undefined method `view_context' for nil:NilClass
Here is the line from the view where current_user is used for completeness:
<% if my_project.user_id == current_user.id %>
Does anyone know how I can get it to stub current_user successfully, I'm at a loss here...
thanks

Turns out that moving view.stub(:current_user) { #client } into each 'it' block solved the problem; it does not seem to work if it is in the 'before:each/all' block.

Related

how to test partial with instance variables

so i need to test a partial. the partial is rendered by specific action, its something like messages box in facebook. my test looks like this:
describe 'partials/_partial.js.erb' do
it 'displays stuff' do
render
end
end
i run it, and i know it does what i want because i immediately get
Failure/Error: if #items.count > 0
ActionView::Template::Error:
undefined method `count' for nil:NilClass
i do not need to hear that it is a bad practice to use instance vars in a partial, it is already there and i need to work with it. so how do i set #items here...?
UPDATE:
controller action looks like this:
def controller_method
#items = items_method
render_version(:partial => "partials/_partial.js.erb")
end
It looks like you're using rspec. In that case, any instance variables you define during your test will be available for your views (regardless if it's a partial or not).
describe "users/_messages" do
before(:each) do
# This is available in your view.
#items = []
end
it "renders without error when #items is empty" do
# Will pass, #items is available
expect { render }.to_not raise_error
end
it "shows a count of how many messages there are" do
# You can modify it before rendering
#items << Message.new
render
expect(rendered).to have_content "You have 1 message"
end
end

rspec 'allow' stub isn't setting variables

I have a controller function:
def update
#simulation = Simulation.find(params[:id])
#simulation.next
puts "--"
puts #simulation.dirty?
puts #simulation.save
if (#simulation.save && #simulation.dirty?)
render :partial => 'show', :object => #simulation
end
end
And an rspec test:
it "should render a partial when the record is dirty" do
allow(#simulation).to receive('dirty?') { true }
put :update, :id => #simulation.id, :format => 'js'
expect(response).to render_template( :partial => 'show' )
end
The test is failing to render the view because the if check isn't passing because it won't return true for #simulation#dirty? even though the function is stubbed. I can see this because of the puts in the controller. Any ideas why it's not working?
The instance variable #simulation you are stubbing does not belong to the controller instance, but to the rspec test case class instance. Try #simulation.dirty? within it block of rspec, after the allow method call. I guess it returns true. The #simulation in the controller is not stubbed, though. They are two different objects.
If you want to stub #simulation in the controller's update method, you should stub all the instance of the Simulation class. Try using allow_any_instance_of instead of allow(#simulation).
allow_any_instance_of(Simulation).to receive(:dirty?).and_return(true)
https://github.com/rspec/rspec-mocks#settings-mocks-or-stubs-on-any-instance-of-a-class

Rspec Test controller render partial with locals

I have controller action like
def get_status
status_name = current_user.status
status_updated_time = current_user.updated_at
render :partial => 'show_status', :locals => {status_name: status_name, status_updated_time: status_updated_time}
end
here I am planning to test local variable values which are passing via render partial. i.e
status_name, status_updated_time.
Could you please let me know how to write rspecs for render partial with locals in controller.
I would move variable logic into a separate method:
def get_status
render partial: 'show_status', locals: get_status_from(current_user)
end
protected
def get_status_from(user)
{ status_name: user.status, status_updated_time: user.updated_at }
end
and test that method instead.
I would say that to test the controller, what you're after is a basic feature/integration spec wherein you can simply look for the content held by your partial.
feature 'SomeController' do
background do
# setup data
# and anything else you need for authentication, etc. as your site dictates
end
scenario 'viewing the get status page' do
visit some_controller_get_status_path
expect(page).to have_text('WHATEVER IS IN THE LOCAL VAR')
end
end
I prefer to use feature specs over controller specs as I seek (but often fail!) to keep my controllers so simple that there is not really much to test in them. With feature specs, I feel like I'm getting more from the test in terms of how my app works, etc.
EDIT: sorry ... hit enter too early :).
For a controller, you could directly test the var value along the lines of:
describe "Your Controller", :type => :controller do
describe "GET get_stuff" do
it "assigns a value to status_name" do
get :get_status
expect(assigns(:status_name)).to eq(['VALUE'])
end
end
end
That may not be 100% spot-on for a controller spec (again, I don't use them a lot) but I think it should get you on your way should you go controller spec over feature/integration spec.
you could do something like
it "should render correct partial for get_status" do
controller.should_receive(:render).with({
:partial => '_show_status', #here you will have to give the full path like <controller_name>/_show_status
:locals => {status_name: <name>, status_update_time: <time>}
})
get 'get_status'
end

How do I stub out a current user's attributes in a view spec

I have a view spec where I'm testing conditional output. How do I get the spec to return the user I've mocked out?
View file:
.content
- if #current_user.is_welcome == true
Welcome to the site
View spec:
before(:each) do
#user = mock_model(User)
#user.stub!(:is_welcome).and_return(true)
view.stub(:current_user).and_return(#user)
end
it "show content" do
#assign(:current_user, stub_model(User, dismiss_intro: true))
render
rendered.should have_content("Welcome to the site")
end
Running the spec returns undefined method is_welcome for nil:NilClass
You have stubbed the method named current_user, not the instance variable #current_user.
view.stub(:current_user).and_return(#user)
That means, in the view, you should be using:
.content
- if current_user.is_welcome == true
Welcome to the site
Notice that it calls the method current_user instead of getting the #current_user instance variable.
If you need an instance variable, it is recommended that you have create a method current_user, which gets the instance variable and returns it.
I ended up doing this which let me keep the #current_user variable in my view and made the spec pass:
before :each do
#user = stub_model(User, is_welcome: true)
assign(:current_user, #user)
end
Then to test the conditionality, just ran another spec in a context with a different before block:
before :each do
#user = stub_model(User, is_welcome: false)
assign(:current_user, #user)
end

Rspec controller test, trying to create a test for a 'processlogin' action

My create user method in the users_controller.rb looks like:
def process_login
is_login_valid(params[:user][:user_name], params[:user][:password])
if logged_in?
redirect_to root_url
else
#user = User.new(params[:user][:user_name]
redirect_to :action => 'login'
end
What I have currently:
describe UsersController do
describe "Post 'process_login'"
it "should be successful" do
post 'process_login'
response.should be_success
end
end
end
The methods is_login_valid and logged_in? are all included in the application_controller, and are methods from a ruby class I have in my /lib folder called LoginSystem.rb
My test is failing since it isn't mocking things correctly, this is my first time doing this so hoping someone can help me out.
Error message:
UsersController POST 'process_login' should be successful
Failure/Error: post 'process_login'
NoMethodError:
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
# ./app/controllers/users_controller.rb:11:in `process_login'
# ./spec/controllers/users_controller_spec.rb:21
Aah, Thanks for the error message. I'm assuming that line 11 is is_login_valid(params[:user][:user_name], params[:user][:password]).
As you're not sending any params in your test post params[:user] is nil hence the nil.[] error (when the controller is looking for params[:user][:user_name]), you set params by passing them as a hash as the 2nd parameter to post in your test.
I think you actually need
controller.stub(:logged_in?) { true }
Or if you want to test that the logged_in method is actually being called
controller.should_receive(:logged_in?).and_return(true)
The 2nd version will cause the test to fail unless the method logged_in? is called once and only once
You may also need the controller.stub(:is_login_valid} { true } as suggested by #jaydel if you're getting an error message about this method being missing as well
I believe:
controller.stub(:is_login_valid} { true }
should get you where you want to go, if I understand correctly.

Resources