I have an auth method and want to put it in my application_controller.
class ApplicationController < ActionController::Base
helper_method :check_cred
def check_cred
"within check cred"
end
but if I do this
require 'spec_helper'
describe ApplicationController do
it 'should check_cred', task050: true do
check_cred.should == 'within check cred'
end
end
I get:
undefined local variable or method `check_cred' for #<RSpec::Core::ExampleGroup::Nested_9:0x007ff5e3e40558>
How would I call a method like this to test?
thx
RSpec controller specs wrap ActionController::TestCase::Behavior, which provides some instance variables to be used during tests:
Special instance variables
ActionController::TestCase will also automatically provide the following instance
variables for use in the tests:
#controller:
The controller instance that will be tested.
So you may be able to do the following:
it 'should check_cred', task050: true do
#controller.check_cred.should == 'within check cred'
end
Alternatively, you could move this helper method out into a separate helper module, and use an RSpec helper spec to perform the test, which may prove to be a better way to structure this test.
Related
I tried to google but I find nowhere about this error for ActionView
I am using Minitest (no Rspec)
custom_user_groups_helper_test.rb
class CustomUserGroupsHelperTest < ActionView::TestCase
test "should work custom user" do
response_params = gotta_get
end
end
custom_user_groups_helper.rb
module CustomUserGroupsHelper
def self.gotta_get
return true
end
This test_helper.rb works fine with the controller test, but when I use it for helper test
it throws me this error
Error:
CustomUserGroupsHelperTest#test_should_work_custom_user:
NoMethodError: undefined method `env' for nil:NilClass
I tried another solution too
"undefined method `env' for nil:NilClass" in 'setup_controller_for_warden' error when testing Devise using Rspec
But this seems to be for the controller, none of the solutions is for the helper testing.
What to include for ActionView::TestCase from Devise
I tried to include these
include Devise::TestHelpers
include Devise::Test::IntegrationHelpers
include Devise::Test::ControllerHelpers
As one of the solutions on StackOverflow says
The Devise::TestHelpers should only be included for controller tests, so you need to move it to the ActionController::TestCase by adding this to your test helpers:
Then what to include for Helper test which inherits ActionView::TestCase
How to test helpers in the Minitest framework.
But i suppose include Devise::Test::IntegrationHelpers and include Devise::Test::ControllerHelpers are for controllers for different rails versions.
error
Updated error stack trace
stack trace for test run
CustomUserGroupsHelperTest: test_should_work_custom_user
--------------------------------------------------------
(0.1ms) ROLLBACK
E (0.1ms) BEGIN
You seem to have fundamentially missunderstood both what a helper is in Rails and how you should test them. Which is really understandable as its a really vague term and means different things in different contexts.
Helpers (as in /app/helpers) in a Rails app are just modules that are mixed into the view context and and provide simple helper methods for stuff like generating html or getting the user from the session in the case of Devise.
A test like this:
require 'test_helper'
class CustomUserGroupsHelperTest < ActionView::TestCase
test "should work custom user" do
post :save_custom_groups
assert_equal "save_custom_groups", #controller.action_name
end
end
Is just wrong in every way possible. A helper does not respond to HTTP methods. This is more like the strangest attempt at a controller test ever created.
To test helpers you should just test it like a plain old method. Give it input and test the output:
module ListHelper
def ul(array)
content_tag :ul do
array.each do |obj|
concat content_tag :li, obj
end
end
end
end
class ListHelperTest < ActionView::TestCase
test "should return the user's full name" do
assert_dom_equal %{<ul><li>foo</li><li>bar</li></ul>}, ul(["foo", "bar"])
end
end
If you are testing a helper that relies on a method from Devise like current_user, user_signed_in? etc you should just stub these methods. A helper test is not full stack and thus has no real session.
You can stub other helper methods in ActionView::TestCase by stubbing them on self. If you are using mocha for example you would do:
class UsersHelperTest < ActionView::TestCase
def setup
#user = users(:david)
self.stubs(:current_user).returns(#user)
end
test "should link to the current user" do
assert_dom_equal %{#user.name}, link_to_current_user
end
end
Devise::Test::IntegrationHelpers and Devise::Test::ControllerHelpers are for integration and controller tests where you are actually driving most of the framework and are completely irrelevant for helper tests. These are examples of test helpers which is a behavior that you mix into your tests.
You can of course test helpers indirectly with integration tests that render the view where the helper is used but since helpers are relatively simple it it can be a good idea to test them directly.
I have a controller file:
some_controller.rb:
class SomeController < ActionController::Base
def get_params
# Do something with params
end
end
And a helper file:
module SomeHelper
def modify_params
get_params
end
end
And rspec File for helper:
require 'spec_helper'
describe SomeHelper do
describe 'check_if_param_has_key' do
it "checks if param has key" do
modify_params.should eql(true)
end
end
Here, I am calling controller's method inside helper method. Now I am writing test cases for helper method modify_param.
But it throws error : NoMethodError: get_params
Is there a way to access controller's method inside helper spec?
Is this the right way to do it? Or Am I missing something in this?
Edited:
The controller is ApplicationController, and method inside it return string containing which controller/method was called on page load, by looking at params[:controller], params[:action]
As the author of RSpec has pointed out, helper tests are conceptually unrelated to controllers. So even if there was a way, you'd likely not want to bring the controller into the picture. You can easily stub out the method call in your spec:
describe SomeHelper do
describe "#foo" do
before do
allow(helper).to receive(:bar).and_return("hello")
end
it { expect(helper.foo).to eql("hello") }
end
end
Even if you had a controller, you'd likely have to stub the method call there, to cover the edge case.
Note that this stubbing a method not defined in the helper will fail if you're using verifying doubles.
My problem has been solved by making get request to the page:
describe 'check if the home page by checking params', :type => :request do
it 'return true if page is Home page' do
get "/homepage"
helper.modify_params.should eql(true)
end
end
In above code, after calling get request to homepage, helper method will have access to all the params and controller action it is calling. All my test cases have been passed.
I'm trying to write specs for a Rails helper. This helper calls a method
defined in ApplicationController and exposed through helper_method:
app/helpers/monkeys_helper.rb:
module MonkeysHelper
def current_monkey_banana_count
# current_monkey is defined in ApplicationController
current_monkey.present? ? current_monkey.banana_count : 0
end
end
app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
helper_method :current_monkey
protected
def current_monkey
#current_monkey ||= Monkey.find(session[:monkey_id])
end
end
If I call current_monkey_banana_count from a view and access it through the browser, it works fine. But if I call it from a spec like this:
spec/helpers/monkeys_helper_spec.rb:
RSpec.describe MonkeysHelper, type: :helper do
describe "#current_monkey_banana_count" do
it "returns 0 if there is no monkey" do
expect(helper.current_monkey_banana_count).to eq 0
end
end
end
Then I get this error when I run the spec:
NameError:
undefined local variable or method `current_monkey' for #<#<Class:0x007fe1ed38d700>:0x007fe1e9c72d88>
Rspec documentation says:
To access the helper methods you're specifying, simply call them
directly on the helper object. NOTE: helper methods defined in
controllers are not included.
Any idea how to either mock current_monkey or make it visible from inside current_monkey_banana_count?
Thanks!
I found a (nasty) way to do it, but it works:
spec/helpers/monkeys_helper_spec.rb:
require 'rails_helper'
RSpec.describe CartsHelper, type: :helper do
before do
def helper.current_monkey; end
end
describe "#current_monkey_banana_count" do
it "returns 0 if there is no cart" do
expect(helper).to receive(:current_monkey).and_return(nil)
expect(helper.current_monkey_banana_count).to eq 0
end
it "returns monkey.banana_count if there is a monkey" do
expect(helper).to receive(:current_monkey).and_return(Monkey.create!(banana_count: 5))
expect(helper.current_monkey_banana_count).to eq 5
end
end
end
Maybe you can achieve that by mocking current_monkey in this way (have you tried it already?):
RSpec.describe MonkeysHelper, type: :helper do
let(:monkey) { create(:monkey) }
before do
allow(helper).to receive(:current_monkey_user) { monkey }
end
# your rest of code
end
Cheers!
View can call helper methods defined in controller because controller eval them automatically, please check code here.
But your helper test doesn't call controller, so that current_monkey isn't available on MonkeysHelper module. The best practice is helpers defined in controller call helper defined in helper class but not vice versa. In your case, you can move current_monkey to MonkeyHelper to be able to test it.
I've got a method defined in ApplicationController as a helper method.
helper_method :can_access_participant_contact_data?
I'm trying to write a test for a helper method that resides in a helper file. This helper method makes a call to helper_method :can_access_participant_contact_data?
# In participants_helper.rb
#
def redacted_contact_data participant, attribute_name
attribute = participant.try(:contact_data).try(attribute_name)
return attribute if can_access_participant_contact_data?(participant)
return nil if attribute.blank?
return attribute.gsub(/\S/i, '*') # Asterisked string
end
All I'm doing so far in my test is making a call to redacted_contact_data
require 'test_helper'
class ParticipantsHelperTest < ActionView::TestCase
test "should return an asterisked string with spaces" do
redacted_contact_data(Participant.first, :name)
end
end
When I run my test, I'm getting this message
undefined method `can_access_participant_contact_data?' for #<ParticipantsHelperTest:0x007fd6c7c6d608>
I've been having a look around but I'm not sure how to get around this issue. Do I need to mock can_access_participant_contact_data? somehow? or can I just include the method into the test?
AFAIK (As far as I know), you cannot fix this without stubbing, or doing some change in your code, as essentially a helper file is just a module of itself that should be treated independent of where it's gonna be included. Who knows you might want to include such helper file inside your model files for example, in which incidentally the model file also has a method named can_access_participant_contact_data? but does differently from that one defined in the ApplicationController, therefore you cannot unit test this without specifying the context / base.
Possible Workarounds:
Stubbing:
Use Mocha or rework testing into RSpec
Or manually (maybe there's a better way) by:
test "should return an asterisked string with spaces" do
ParticipantsHelper.class_eval do
define_method :can_access_participant_contact_data? do |arg|
true
end
end
redacted_contact_data(Participant.first, :name)
end
Or, moving all your ApplicationController helper methods into a separate/existing helper file, say inside your already existing ApplicationHelper. Then afterwards, include that helper inside your other helper file that you are testing that is making use of the method/s. i.e.:
# helpers/application_helper.rb
module ApplicationHelper
def can_access_participant_contact_data?(participant)
# YOUR CODE
end
end
# helpers/participants_helper.rb
module ParticipantHelper
include ApplicationHelper
def redacted_contact_data participant, attribute_name
attribute = participant.try(:contact_data).try(attribute_name)
return attribute if can_access_participant_contact_data?(participant)
return nil if attribute.blank?
return attribute.gsub(/\S/i, '*') # Asterisked string
end
end
If using this approach, then two ways to call the helper method inside the controller:
Use Rails helpers method inside a controller:
class ParticipantsController
def show
helpers.can_access_participant_contact_data?(#participant)
end
end
Or, include the helpers directly (I personally prefer the other approach just above)
class ApplicationController < ActionController::Base
include ApplicationHelper
end
class ParticipantsController < ApplicationController
def show
can_access_participant_contact_data?(#participant)
end
end
For the view files, you won't need to update any code.
Another idea is to do "helper test" in "controller test" as follows:
require 'test_helper'
class ParticipantsControllerTest < ActionController::TestCase
setup do
# do some initialization here. e.g. login, etc.
end
test "should return an asterisked string with spaces" do
participant = ...
get :show, id: participant.id
assert_equal '...', #controller.view_context.redacted_contact_data(...)
end
end
Where, #controller is ParticipantsController object already defined by rails controller testing framework (or you can explicitly define it when controller name is different from *ControllerTest), and view_context is the object for helper methods (see https://api.rubyonrails.org/classes/ActionView/Rendering.html#method-i-view_context for more detail).
Helper method often refer controller object and/or method (like session, request) so that it is sometimes difficult to do unit-test only in test/helpers/*. This is the reason why I test helper in controller in such a case.
In my ApplicationController I have a method defined as a helper method:
helper_method :some_method_here
How do I test ApplicationController in RSpec at all?
How do I include/call this helper method when testing my views/helpers?
I'm using Rails3 with RSpec2
You can use an anonymous controller to test your ApplicationController, as describe in the RSpec documentation. There's also a section on testing helpers.
You can invoke your helper methods on subject or #controller in the specification.
I have been looking for a solution to this problem and anonymous controller was not what I was looking for. Let's say you have a controller living at app/controllers/application_controller.rb with a simple method which is not bound to a REST path:
class ApplicationController < ActionController:Base
def your_helper_method
return 'a_helpful_string'
end
end
Then you can write your test in spec/controllers/application_controller_spec.rb as follows:
require 'spec_helper'
describe ApplicationController do
describe "#your_helper_method" do
it "returns a helpful string" do
expect(subject.your_helper_method).to eq("a_helpful_string")
end
end
end
While #controller and subject can be used interchangeable here, I would go for subject as its the RSpec idiomatic way for now.