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.
Related
I have something like this controller:
class ApiApplicationController < ActionController::API
before_action :record_information_from_headers
private
def record_information_from_headers
InformationSet.create(info: request.headers['INFO'])
end
end
All other controllers are inherited from ApiApplicationController
I want to test that my callback works before each method in child controllers. And try to use Anonymous controller
require 'rails_helper'
RSpec.describe ApiApplicationController do
controller(ApiApplicationController) do
def index; end
end
let('INFO') { "some information" }
it 'some' do
get :index
expect(InformationSet.last.info).to eq('some information')
end
end
But, first of all, i have error:
"NoMethodError:
undefined method `controller' for RSpec::ExampleGroups::ApiApplicationController:Class"
And secondly, how do I pass the information to the header ?
I've already read How to test ApplicationController method defined also as a helper method? and Rspec controller test for callback after_save
I would be grateful for any help)
You don't have the type: describe ...Controller, type: :controller do
The Setting request headers section of the docs shows how to set request headers for controller specs.
I have the following code:
def do_something(param1, param2)
"hello" if current_page? param2
end
The application code above works however when I do this in my helper spec:
allow(helper).to receive(:current_page?).and_return(true)
it does not work it says You cannot use helpers that need to determine the current page unless your view context provides a Request object in a #request method
but when I do
allow(self).to receive(:current_page?).and_return(true)
it works. How is this happening? Isn't self in this case the helper spec class? Why can't I refer to the helper explicitly?
I guess you call the expect as below
RSpec.describe ApplicationHelper, type: :helper do
describe "#hello" do
it "returns hello" do
expect(do_something).to eq("hello")
end
end
end
Whenever you describe a test case, you create a RSpec::Rails::{type}ExampleGroup, here type is helper so you create a RSpec::Rails::HelperExampleGroup, this example_group wrap a helper that is your ApplicationHelper. Beside that, this example_group could respond_to all methods of your helper
RSpec.describe ApplicationHelper, type: :helper do
# ...
it "returns hello" do
puts self # RSpec::ExampleGroups::ApplicationHelper::...
puts self.respond_to?(:do_something) # true
puts self.respond_to?(:current_page?)# true
puts self.helper.is_a?(ApplicationHelper) # true
end
Here current_page? is special method which belongs to module ActionView::Helpers::UrlHelper and this is a guy raise the error you've got.
So when you call directly expect(do_something) that you're calling expect(example_group.do_something) and so that the object call the method current_page? inside the method do_something is the example_group and if you're not mock this method on the example_group object, this will raise error. That why your test case will pass when you mock allow(self).to receive(:current_page?).and_return(true).
Now your test case will pass if you mock this method on the helper method and also use the helper to call do_something since helper.do_something equivalent to self.helper.do_something that is actually example_group.helper.do_something
allow(helper).to receive(:current_page?).and_return(true)
expect(helper.do_something).to eq("hello")
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 have a very simple controller:
class ThingsController < ApplicationController
def create
Thing.do_stuff
end
end
…And a very simple spec:
require "rails_helper"
describe ThingsController do
describe "POST #create" do
it "does stuff with things" do
expect(Thing).to receive(:do_stuff)
controller.create # This works
post :create # This does not work
end
end
end
I am not running the direct invocation and the post request at the same time. Invoking the action on the controller directly passes the assertion, but invoking the action through the post method does not. It appears do_stuff is never called on Thing. Why might that be?
I discovered what my issue was.
Invoking the controller directly keeps the spec isolated and ignores things like a before_action in the ApplicationController.
When we start using the post method, it’s really an integrated test and hits things like authentication. I couldn’t hit my controller method because my test user wasn’t signed in.
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.