0

We have some helper_methods in our controllers that are used across both the controller and the view they render.

For example:

helper_method :example_method
def example_method
  @example_method ||= nil
end

However when it comes to testing our views in Rspec we have hit errors that those methods don't exist (likely because the views are tested in isolation from the controller).

ActionView::Template::Error:
       undefined local variable or method `example_method' for #<ActionView::Base:0x0000000003b060>

We've tried mocking the methods in the specs like:

allow(view).to receive(:example_method).and_return(nil)

But that doesn't resolve the issue.

I know Devise solved this with their controller helpers: https://github.com/heartcombo/devise/blob/fec67f98f26fcd9a79072e4581b1bd40d0c7fa1d/lib/devise/test/controller_helpers.rb and then including them into the Rspec setup:

config.include Devise::Test::ControllerHelpers, type: :view

Which means your views can access current_user, etc.

But it's not clear how to replicate this for our custom helper methods.

7
  • 1
    You have completely misunderstood the purpose of Devise::Test::ControllerHelpers. Devise is based on the Warden middleware and the helper methods it generates do not work outside of the context of a HTTP request going through the middleware stack. Controller tests/specs (which you should not be using) don't, and the same applies to view specs. What the module provides is stubs. Despite the name the things are not connected. Commented Feb 6 at 17:38
  • I would argue that if you're testing the view in isolation it seems a bit stinky to expect a method lazily declared in some controller to be injected into the view context. It's not like there aren't other ways around it. Commented Feb 6 at 17:39
  • helper_method :example_method simply adds controller.send(:example_method,...), so since your view does not technically have a Controller this is going to be very difficult to test "in isolation", without completely mocking the entire concept, which you could do by simply defining a method (or if you need more methods creating your own module and including it) in the view eigenclass. Commented Feb 6 at 17:49
  • @engineersmnky that's really complicated compared to just putting the method in a helper module and calling it with helpers.method_name in the controller. Commented Feb 6 at 17:58
  • 2
    @LesNightingill 1 word: "abuse". Helpers and Concerns are substantially over used and mismanaged leading to leaky abstraction and tight coupling. I fully agree with separations of concerns and code reuse through modules and formal PORO objects but throw it in a "Helper" that is automagically include here there and everywhere, has always seemed like the nuclear approach to me. I find that people use both Helpers and Concerns as a cheap cop out to Presenters, Service Objects, functionesque Modules, and actual reusable code. Commented Feb 6 at 22:03

1 Answer 1

0

So I managed to solve this by wrapping the stub with: without_partial_double_verification like so:

  before do
    without_partial_double_verification {
      allow(view).to receive(:example_method).and_return(nil)
    }
  end
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.