NoMethodError: undefined method 'customer_details' for nil:NilClass in RSpec - ruby-on-rails

My RSpec test failed but I couldn't figure out how I could fix that. Calling .all method on the Class pass but it fails with associations.
Error Message
0) CustomerDetail #index when logged in should render customer details index page
Failure/Error: #customer_details = current_shop.customer_details.load
NoMethodError:
undefined method `customer_details' for nil:NilClass
# ./app/controllers/customer_details_controller.rb:9:in `index'
ApplicationController
class ApplicationController < ActionController::Base
layout 'embedded_app'
def current_shop
#current_shop ||= Shop.find_by(shopify_domain: cookies[:shopify_domain])
end
end
Here is the Controller
class CustomerDetailsController < ApplicationController
before_action :authenticate_user!
def index
# This failed the test below and complains that NoMethodError: undefined method 'customer_details' for nil:NilClass
#customer_details = current_shop.customer_details.load
#This pass the test below
#customer_details = CustomerDetail.all.load
end
end
Models
class Shop < ActiveRecord::Base
include ShopifyApp::SessionStorage
has_many :customer_details
def api_version
ShopifyApp.configuration.api_version
end
end
class CustomerDetail < ApplicationRecord
belongs_to :shop
end
RSpec
context 'when logged in' do
before do
#shop = create(:shop)
#user = create(:user)
sign_in #user
end
it 'should return a 200 response' do
get customer_details_index_path
expect(response).to have_http_status '200'
end
it 'should render customer details index page' do
get customer_details_index_path
expect(response).to render_template(:index)
end
end
Any help will be appreciated.

current_shop is nil in your controller. It's not enough that you set shop in your spec code. Instance variables from specs are not shared with a controller under test.
Ensure that the shop you're creating in
#shop = create(:shop)
has field shopify_domain set to whatever value has cookies[:shopify_domain] in your test request.

Related

Protected action defined in parent class not found during test

My Employer::ShiftsController calls: before_action :authenticate_request!
class Employer::ShiftsController < Employer::ApplicationController
before_action :authenticate_request!
...
end
which is defined in the parent, Employer::ApplicationController
class Employer::ApplicationController < ActionController::Base
protected
def authenticate_request!
...
end
end
This API works when I send it data, but when I run our test:
class Employer::ShiftsControllerTest < ActionController::TestCase
test "index should return a list of shifts at a given date" do
xhr :get, :index, date: '2015/9/8'
assert_response :success
end
end
I am getting an error:
NoMethodError: NoMethodError: undefined method `authenticate_request!' for #<Employer::ShiftsController:0x007fa2dab0ff70>

functional test: NomethodError

i'm a beginner in ruby on rails(and english :)), and i'm trying to use functional test but i had an error at fist
1)Error:
test_should_get_new(MicropostControllerTest)
NoMethodError: undefined method 'microposts' for nil:NilClass
My micropost_controller_test.rb
require 'test_helper'
class MicropostControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end
end
My micropost_controller.rb
class MicropostController < ApplicationController
def new
#post = Micropost.new
#posts = current_user.microposts.all
end
def create
#post = current_user.microposts.create(:content => params[:content])
logger.debug "New post: #{#post.attributes.inspect}"
logger.debug "Post should be valid: #{#post.valid?}"
if #post
redirect_to micropost_new_path
else
end
end
end
I tried to put something in microposts.yml but it didn't work.
So, where i can find microposts method for functional test and how do i fix that?? Please help me?
p/s: My app still work in localhost
If you are using Devise for user authentication then you need to authenticate and set current_user in your MicropostController, by for instance having a before_action as follows:
class MicropostController < ApplicationController
before_action :authenticate_user!
def new
#post = Micropost.new
#posts = current_user.microposts.all
end
# rest of the code
end
In your test you need to import devise test helpers as follows, if you haven't done it in your test_helper
class MicropostControllerTest < ActionController::TestCase
include Devise::TestHelpers
end
You can then use the sign_in method to sign in a user using Fixtures in your test. search for some tutorials on that or check the response here to get some clue: Functional testing with Rails and Devise. What to put in my fixtures?

undefined method `update' for nil:NilClass

Anyone know how I can fix this error? Here's more information -
error message:
NoMethodError in PostsController#create
undefined method `update' for nil:NilClass
The PostsController create:
class PostsController < ApplicationController
def create
#twitter_user.update(#post.content)
end
Here's how #twitter_user is defined in my user.rb model
def twitter
unless #twitter_user
provider = self.authentications.find_by_provider('twitter')
#twitter_user = Twitter::Client.new(:token => provider.token, :secret => provider.secret) rescue nil
end
#twitter_user
end
Thanks
If #twitter_user is defined in your User model you can't access it in the controller. A variable in a method with an # prefix belongs to an instance of that class.
If you want to access #twitter_user in the controller, perhaps move that twitter method to the application controller:
class ApplicationController
def twitter
unless #twitter_user
provider = User.find_by_provider('twitter')
#twitter_user = Twitter::Client.new(:token => provider.token, :secret => provider.secret) rescue nil
end
#twitter_user
end
end
Then you can access it in any controller method with twitter:
class PostsController < ApplicationController
def create
twitter.update(#post.content)
end
The model and the controller don't share instance variables, so #twitter_user inside PostsController is not the same as the one inside the User class (which I suppose derives from ActiveRecord::Base). You have to initialize #twitter_user inside the controller.
You can refactor your code like this:
class User < ActiveRecord::Base
def twitter_user
provider = self.authentications.find_by_provider('twitter')
Twitter::Client.new(:token => provider.token,
:secret => provider.secret)
rescue
return nil
end
end
class PostsController < ApplicationController
def create
# I suppose your User instance is accessible
# through the method current_user
#twitter_user = current_user.twitter_user
#twitter_user.update(#post.content)
end
end

How to write a CanCan rspec for a modeless controller?

I have a model group.rb and then a controller group_invitations.rb which is modeless.
GroupInvitationsController
before_filter :find_group_by_group_id
before_filter :authenticate_user!
before_filter :current_ability
authorize_resource :class => false
def current_ability
#current_ability ||= Ability.new(current_user, #group)
end
When I write a rspec for this:
it "should be able to create" do
ability = Ability.new(nil)
ability.should be_able_to(:create, GroupInvitation.new)
end
rspec then errors with:
NameError:
uninitialized constant GroupInvitation
How do I setup rspec to test this modeless controller? Thanks
You need to call #ability.should be_able_to(:create, :group_invitation). You can read about what is authorized when using a model-less controller in the documentation.
This is the relevant section:
class ToolsController < ApplicationController
authorize_resource :class => false
def show
# automatically calls authorize!(:show, :tool)
end
end

RSpec: stub a controller method in the view

View spec failing because the ApplicationController method, logged_in?, wants a user to be returned.
Not sure how to spec this. Currently in before(:each) I have:
controller.stub!(:logged_in?).and_return(FactoryGirl.create(:active_user))
#ballots = FactoryGirl.create_list(:full_ballot, 2)
which isn't working:
Failure/Error: render
ActionView::Template::Error:
undefined method 'logged_in?' for #<#<Class:0x007f9c908e4b10>:0x007f9c90873b68>
FWIW: :active_user is the user factory for the user that is attached to the :full_ballot
Update: As requested:
class ApplicationController < ActionController::Base
...
def current_user
#current_user ||= User.find(cookies[:id_token]) if cookies[:id_token]
end
def logged_in?
current_user
end
...
end
See how devise test helpers do it. It looks like you can define this method before tests and it should work:
def logged_in?
FactoryGirl.create :active_user
end

Resources