Rails rspec helper methods not recognised in tests - ruby-on-rails

I have a helper method that hides some buttons depending on user role.
#application_controller
helper_method :current_user, :manager_can_see
def manager_can_see(company)
#if manager can see, company owner can see as well
if current_user
return current_user.has_role?(:manager, company) ||
current_user == company.user ||
current_user.has_role?('superuser')
end
end
Then in my view I have this line:
<% if manager_can_see(#appliance.company) %>
...
<% end %>
This works when I visit that page. But it fails in rspec test saying:
ActionView::Template::Error:
undefined method `manager_can_see'
What can be the reason and solution to this?
Here is my test:
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'admin/show', type: :view do
before(:each) do
#user = assign(:user, FactoryBot.create(:user))
#company = assign(:company, FactoryBot.create(:company, user: #user))
10.times do |i|
FactoryBot.create(:appliance, company: #company, name: "Test object #{i}")
end
session[:user_id] = #user.id
#companies = Company.where(user: current_user)
#appliance = assign(:appliance, FactoryBot.create(:appliance))
end
I18n.available_locales.each do |_locale|
it 'renders attributes in <p>' do
render
end
end
end

Related

Setting a session value through RSpec

My current code looks like this:
/spec/support/spec_test_helper.rb
module SpecTestHelper
def login_admin
user = FactoryGirl.create(:user, type: 0)
session[:user_id] = user.id
end
end
/app/controllers/application_controller.rb
def current_user
if session[:user_id].nil?
render plain: 'Error', status: :unauthorized
else
#current_user ||= User.find(session[:user_id])
end
end
Unfortunately, session is always empty in the current_user method. Is there a way of controlling the session through RSpec?
This will change based on the spec type. For example, a feature spec will not allow you to directly modify the session. However, a controller spec will.
You will need to include the helper methods module into your example group. Say you have a WidgetsController:
require 'support/spec_test_helper'
RSpec.describe WidgetsController, type: :controller do
include SpecTestHelper
context "when not logged in" do
it "the request is unauthorized" do
get :index
expect(response).to have_http_status(:unauthorized)
end
end
context "when logged in" do
before do
login_admin
end
it "lists the user's widgets" do
# ...
end
end
end
You can also automatically include the module into all specs, or specific specs by using metadata.
I often do this by adding the configuration changes into the file which defines the helper methods:
/spec/support/spec_test_helper.rb
module SpecTestHelper
def login_admin
user = FactoryGirl.create(:user, type: 0)
session[:user_id] = user.id
end
end
RSpec.configure do |config|
config.include SpecTestHelper, type: :controller
end

Request in application controller returns nil when testing with rspec

I use
request.subdomain
in my application controller. In develepment mode it works, but when I test it it returns
undefined method `subdomain' for nil:NilClass
I have this test.
describe ApplicationController do
controller do
def index
render text: "hello"
end
end
let(:firm){FactoryGirl.create(:firm, subdomain: "test")}
let(:user){FactoryGirl.create(:user, firm: firm)}
describe "current" do
before(:each) do
#request.host = "#{firm.subdomain}.example.com"
sign_in(user)
get :index, subdomain: "test"
end
it "should current_firm" do
ApplicationController.new.current_firm.subdomain.should == "test"
end
end
end
This is the method in the application controller
def current_firm
#current_firm ||= Firm.find_by_subdomain!(request.subdomain)
end
Why is the request method nil during this test?
it "should current_firm" do
#request.host = "#{firm.subdomain}.example.com"
sign_in(user)
get :index, subdomain: "test"
assigns(:current_firm).subdomain.should == "test"
end

Rails url helpers not working in Rspec

I am new to programming, this is my first application.
While creating an application in Rails, i have two models. User&list,nested.
resources :users do
resources :lists
end
These are the following routes i obtain with this setting:
user_lists GET /users/:user_id/lists(.:format) lists#index
POST /users/:user_id/lists(.:format) lists#create
new_user_list GET /users/:user_id/lists/new(.:format) lists#new
edit_user_list GET /users/:user_id/lists/:id/edit(.:format)lists#edit
user_list GET /users/:user_id/lists/:id(.:format) lists#show
PUT /users/:user_id/lists/:id(.:format) lists#update
DELETE /users/:user_id/lists/:id(.:format) lists#destroy
With regards i have created the views with the following links.
<div class="stats">
<a href="<%= user_lists_path(current_user) %>">
<%= pluralize(current_user.lists.count, 'List') %>
</a>
</div>
<div class="list">
<%= link_to 'Create List', new_user_list_path(current_user) %>
</div>
These work as expected, however when i use the same url helpers in testing i get an error.
describe "List create page" do
let(:user) { FactoryGirl.create(:user) }
before do
user.save
visit new_user_list_path(user)
end
it { should have_selector('title', text: 'SocialTask | List') }
it { should have_selector('h1', text: 'Create list') }
describe "invalid list creation" do
before { click_button 'Create list' }
it { should have_content('Error in creating list') }
end
end
This causes the tests to have an error.
Failure/Error: visit new_user_list_path(user)
NoMethodError:
undefined method `lists' for nil:NilClass
I have tried playing around with the url that did not work.
I tried updating rspec/capybara that did not work either.
I have also checked the inclusion of
config.include Rails.application.routes.url_helpers
in the spec helper.
How do i get the helpers to work? Or am i missing some minor detail?
Thanks in advance.
Helper Methods.
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def signed_in?
!current_user.nil?
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
def current_user?(user)
current_user == user
end
end
The rspec helper to sign in.
support/utilities.rb
include ApplicationHelper
def sign_in(user)
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
cookies[:remember_token] = user.remember_token
end
Without seeing the stack trace, I think your problem is in the view on this line:
<%= pluralize(current_user.lists.count, 'List') %>
It seems like current_user is nil. Normally you should define some kind of helper method in your RSpec suite to simulate a user logging in. That way, current_user will return the user that you stub out in the test.
Here's an example:
# spec/support/session_helper.rb
module SessionHelper
def login(username = 'admin')
request.session[:user_id] = User.find_by_username(username).id
end
end
Yours will differ depending on how you authenticate your users. For example, Devise publishes its own set of test helpers, so you can simply include its helpers directly:
# spec/support/devise.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
Seems it's getting an error because the user doesn't exists. Try to change user.save to user.save! then you'll catch the error on creation I think..

How to stub current_user method in Rspec

I have a simple user login system:
module SessionsHelper
def logged_in?
current_user.present?
end
def current_user
#current_user ||= begin
if session[:current_user_id]
User.find(session[:current_user_id]) rescue nil
end
end
end
end
which I include in ApplicationController:
class ApplicationController < ActionController::Base
include SessionsHelper
helper SessionsHelper
I am trying to test the banners controller:
require 'spec_helper'
describe Admin::BannersController do
describe 'POST create' do
let(:user){ create(:user_admin) }
before do
controller.stub(:current_user){ user }
end
it "create action should render new template when model is invalid" do
Banner.any_instance.stubs(:valid?).returns(false)
post :create
response.should render_template(:new)
end
:user_admin is the properly set up Factory Girl admin user.
However the test still says: You are not authorized to access this page.
This is from Cancan.
Did I not stub it properly? Thanks.
def fake_user
user = FactoryGirl.build(:user, :id => 100000 + rand(100000))
stub(controller).current_user { user }
user
end

Can I have some feedback with rspec when writing controllers specs?

I was wondering if i could have some feedbacks with the controller spec bellow. In fact i'm new when writing specs and controller's spec are way different from model's spec ! So i'm wondering if i may not go in the wrong direction...
subjects_controller.rb
def show
#subject = Subject.find(params[:id])
if #subject.trusted?(current_user)
#messages = #subject.messages
else
#messages = #subject.messages.public
#messages = #messages + #subject.messages.where(:user_ids => current_user.id)
#messages.uniq!
end
# sort the list
#messages = #messages.sort_by(&:created_at).reverse
if !#subject.company.id == current_user.company.id
redirect_to(subjects_path, :notice => "Invalid subject")
end
end
subjects_controller_spec.rb
require 'spec_helper'
describe SubjectsController do
before(:each) do
#subject = mock_model(Subject)
end
context "for signed users" do
before(:each) do
#current_user = sign_in Factory(:user)
end
context "GET #show" do
before(:each) do
Subject.stub!(:find, #subject).and_return(#subject)
end
context "when current_user is trusted" do
before(:each) do
messages = []
company = mock_model(Company)
#subject.should_receive(:trusted?).and_return(true)
#subject.should_receive(:messages).and_return(messages)
#subject.should_receive(:company).and_return(company)
end
it "should render success" do
get :show, :id => #subject
response.should be_success
end
end
context "when current_user is not trusted" do
before(:each) do
messages = []
company = mock_model(Company)
#subject.should_receive(:trusted?).and_return(false)
#subject.should_receive(:messages).and_return(messages)
messages.should_receive(:public).and_return(messages)
#subject.should_receive(:messages).and_return(messages)
messages.should_receive(:where).and_return(messages)
#subject.should_receive(:company).and_return(company)
end
it "should render success" do
get :show, :id => #subject
response.should be_success
end
end
context "when subject's company is not equal to current_user's company" do
# I have no idea of how to implement ==
end
end
end
end
Factories.rb
Factory.define :user do |u|
u.first_name 'Test User' #
u.username 'Test User' #
u.surname 'TheTest' #
u.email 'foo#foobar.com' #
u.password 'please' #
u.confirmed_at Time.now #
end
As far as I can tell you're on the right path. The basic idea is to completely isolate your controller code from model and view in these tests. You appear to be doing that--stubbing and mocking model interaction.
Don't write RSpec controller specs at all. Use Cucumber stories instead. Much easier, and you get better coverage.

Resources