0

I'm trying to test a helper in a Padrino (Sinatra) app. My helper method is itself calling Padrino core helper methods but they are undefined. The error appears only in RSpec, while the app works fine. So the way I'm including my helper in RSpec makes it loose "Padrino scope" but I don't know how to bring Padrino helper's scope properly in my RSpec environment.

My helper:

module AdminHelper
  Sort = Struct.new(:column, :order)

  def sort_link(model, column)
    order = sorted_by_this?(column) ? 'desc' : 'asc'
    link_to mat(model, column), url(:pages, :index, sort: column, order: order)
  end

  def sorted_by_this?(column)
    column.to_s == @sort.column && @sort.order == 'asc'
  end
end

Lenstroy::Admin.helpers AdminHelper

My spec:

describe AdminHelper do
  before(:all) do
    class AdminHelperClass
      include AdminHelper
    end
  end
  subject(:helper) { AdminHelperClass.new }

  describe '#sort_link' do
    context "with :pages and :title parameters" do
      before do
        sort = AdminHelperClass::Sort.new('title', 'asc')
        helper.instance_variable_set('@sort', sort)
      end

      subject { helper.sort_link(:pages, :title) }

      it { should match(/<a href=([^ ]+)pages/) }
    end
  end
end

Results in error:

1) AdminHelper#sort_link with :pages and :title parameters 
     Failure/Error: subject { helper.sort_link(:pages, :title) }
     NoMethodError:
       undefined method `mat' for #<AdminHelperClass:0x007f1d951dc4a0>

Including a helper where mat is defined doesn't work, as one method is dependent on another helper and it goes on and on...

Update
In my spec helper I have:

def app(app = nil, &blk)
  @app ||= block_given? ? app.instance_eval(&blk) : app
  @app ||= Lenstroy::Admin
  @app.register Padrino::Helpers
  @app.register Padrino::Rendering
  @app
end

in my spec I have:

it "returns link to resource with sort parameters" do
  app do
    get '/' do
      sort_link(:pages, :title)
    end
  end
  get "/"
  last_response.body.should =~ /<a href=([^ >]+)pages/
end

And now tests fail, last_response.body is ''.

leemour
  • 11,414
  • 7
  • 36
  • 43

2 Answers2

1

Method #mat is defined in Padrino::Admin::Helpers::ViewHelpers. You can do

class AdminHelperClass
  include Padrino::Admin::Helpers::ViewHelpers
  include AdminHelper
end

Update:

If your methods are really dependent on all these routes and helpers you should consider doing full mockup of your app like this:

def mock_app(base=Padrino::Application, &block)
  @app = Sinatra.new(base, &block)
  @app.register Padrino::Helpers
  @app.register Padrino::Rendering
  # register other things
end

def app
  Rack::Lint.new(@app)
end

mock_app do
  get '/' do
    sort_link(my_model, my_column)
  end
end

get "/"
assert_equal "some test text", body

Here's how it's done in padrino-admin: https://github.com/padrino/padrino-framework/blob/master/padrino-admin/test/test_admin_application.rb

ujifgc
  • 2,215
  • 2
  • 19
  • 21
  • Thanks, I tried this approach but I end up requiring more and more modules and got stuck in the end. As I mentioned in the question, one helper is dependent on another, in this case, `Padrino::Admin::Helpers::ViewHelpers` is dependent on `Padrino::Helpers::TranslationHelpers` and then I also have to include modules for `url` method. So I include `Padrino::Routing` but it's using magic `settings` variable that I couldn't understand in the sources and I don't know how to stub it properly and I'm not sure stubbing it is a good approach... – leemour Mar 06 '14 at 06:18
  • In Padrino tests I saw calls like `app.url_for` and I think I should try similar approach to use Padrino scope. In my tests, `app` is defined by Padrino generator as `def app(app = nil, &blk) @app ||= block_given? ? app.instance_eval(&blk) : app @app ||= Padrino.application end` but calling `app.sort_link` fails with undefined `sort_link` method. – leemour Mar 06 '14 at 06:20
  • After stubbing `settings` with a `Padrino.application` (`Lenstroy::Admin` in my case) I got past this error and got `Padrino::Routing::UnrecognizedException: route mapping for url(:"pages index") could not be found!` so now I need to include controllers. I'm definitely working in the wrong direction – leemour Mar 06 '14 at 09:40
  • Thanks, I'm starting to understand it:) But I got a new error. I updated my question. – leemour Mar 06 '14 at 11:33
1

I was having the same problem (and getting very frustrated tracking down the modules and including them). So far, I've got my specs working by:

1) Explicitly defining my module (as explained in how to use padrino helper methods in rspec)

module MyHelper
  ...
end

MyApp::App.helpers MyHelper

2) Automatically including helpers at the top of my spec. (Right now I only have one helper spec, but in the future I might try to move this into spec_helper.rb.)

describe MyHelper do
  let(:helpers) { Class.new }
  before { MyApp::App.included_modules.each { |m| helpers.extend m } }
  subject { helpers }

  it 'blah' do
    expect(subject.helper_method).to eq 'foo'
  end
end
Community
  • 1
  • 1
srhmgn
  • 23
  • 6