23

I have been writing specs for controllers and models, but I have never written a helper spec. I have no idea where I start.

I have the following snippet in application_helper.rb

  def title(page_title)
    content_for(:title) { page_title }
  end
  • How should I write a helper spec on the code?
  • Also if there's any open-source Rails app to show good helper testing/specing, do let me know.
TK.
  • 27,073
  • 20
  • 64
  • 72

5 Answers5

21

From the rspec-rails docs on Helper Specs:

Helper specs live in spec/helpers, and mix in ActionView::TestCase::Behavior.

Provides a helper object which mixes in the helper module being spec'd, along with ApplicationHelper (if present).

require 'spec_helper'
describe ApplicationHelper do
  describe "#title" do
    it "displays the title" do
      # helper is an instance of ActionView::Base configured with the
      # ApplicationHelper and all of Rails' built-in helpers
      expect(helper.title).to match /Some Title/
    end
  end 
end
plainjimbo
  • 7,070
  • 9
  • 41
  • 55
11

It is possible to use this syntax when spec'ing helpers

Suppose this is your helper

module ApplicationHelper
  def page_title
    @title || nil
  end
end

Then you can spec it with this syntax

require "spec_helper"

describe ApplicationHelper do
  describe "#page_title" do
    it "returns the instance variable" do
      assign(:title, "My Title")
      helper.page_title.should eql("My Title")
    end
  end
end
Fabio
  • 18,856
  • 9
  • 82
  • 114
10

It is also possible to include your helper inside the test class as follows:

 describe ApplicationHelper do
   helper ApplicationHelper

   it "should work" do
     my_helper_method("xyz").should == "result for xyz"
   end
 end

Worked for me with Rails 3.

viphe
  • 689
  • 8
  • 16
7

RSpec should automatically load classes and modules from your rails environment when you 'describe' them, so a valid helper spec could be:

#deleted

But remember that bdd is not testing every single method but the behaviour of your application.

edit:

as @Ken said, my spec was not correct, It was definately the wrong way to do it. So I came out with a Request spec solution that I like more than an Helper spec.

# inside your helper
def title=(page_title)
  content_for(:title) { page_title }
end

# views/resource/index.html.erb
<% title = "foo" %>

# views/layouts/application.html.erb
<%= yield :title %>

# request spec
require 'spec_helper'

describe YourResource do
  it "should output content for title"
    get "/resource"
    response.body.should =~ /<title>foo<\/title>/
  end
end

otherwise, if you want to test only the helper behavior (because it's critical or because you don't have any views) @Ken's solution is better.

makevoid
  • 3,276
  • 2
  • 33
  • 29
  • Thanks so much for your example. Right BDD is not about covering every method. Most helper methods are touched by Cucumber/Rcov coverage. – TK. Jan 03 '10 at 23:57
  • 4
    This doesn't test much since content_for returns nil. You should render a page and assert_select "title" contains what you expect. – Ken Mayer Apr 17 '10 at 01:01
  • 1
    This isn't testing a helper, this is testing something else, based on your example it looks like it's testing a view file (e.g. index.html.erb). The helper test should just test the ApplicationHelper#title method itself, without any dependencies on a view or a route/controller. – Percy Apr 16 '13 at 23:53
  • I usually don't test simple view helpers, I prefer request specs because they test behaviour over a single functionality. @KenMayer, I've corrected the code. – makevoid Apr 21 '13 at 10:08
1

Parsing html with regular expressions is really reinventing the wheel. That's way too much work for me: too inflexible, and too error prone. (See this sarcastic but hilarious and accurate SO answer about the reasoning)

If you need to parse the html output by your helpers, you might try the gem rspec-html-matchers. Unlike webrat, it seems to play well with RSpec 3.

Then you can:

expect(helper.title).to have_tag('title', text: 'What you expect')
Community
  • 1
  • 1
Loren
  • 3,476
  • 3
  • 23
  • 15