Writing a spec for helper with Ruby on Rails and RSpec

16,459

Solution 1

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.

Solution 2

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

Solution 3

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

Solution 4

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.

Solution 5

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')
Share:
16,459

Related videos on Youtube

TK.
Author by

TK.

Looking for a job.

Updated on July 18, 2020

Comments

  • TK.
    TK. almost 4 years

    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.
    TK. over 14 years
    Thanks so much for your example. Right BDD is not about covering every method. Most helper methods are touched by Cucumber/Rcov coverage.
  • Ken Mayer
    Ken Mayer about 14 years
    This doesn't test much since content_for returns nil. You should render a page and assert_select "title" contains what you expect.
  • Percy
    Percy about 11 years
    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.
  • makevoid
    makevoid about 11 years
    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.