Sunday, April 17, 2011

Testing content_tag in Rails 2.3.5 with RSpec

I'm working on a codebase that's still on Rails 2.3.5, and recently I added a group of radio buttons for users to estimate their expertise level when answering a question. I wanted to play with content_tag() more than I have, so here is the view helper:

module AnswersHelper
  # Creates the markup for displaying the expertise choices for an answer.
  def expertise_choices(answer)
    content_tag(:div, :id => 'choices') do
      content_tag(:span, :class => 'clarification') { 'Not at all' } +
      collect_expertise_choices(answer) +
      content_tag(:span, :class => 'clarification') { 'Very Much So' }
    end
  end

  private

  # Creates 5 radio buttons and selects the one with the value of the answer's
  # expertise value if it exists.
  def collect_expertise_choices(answer)
    (1..5).collect do |i|
      checked = (i == answer.expertise) ? { :checked => 'checked' } : {}
      radio_button('answer', 'expertise', i, checked)
    end.to_s
  end
end

Nothing difficult to get through, but some small notes of interest:

content_tag() can nest within other content_tag() calls, and you can append markup to each other to get everything you need to display properly. Also, don't forget to call to_s() to get a string, not an array, of the radio buttons.

Here is the partial that calls the helper:

#expertise
  Are you an expert on this topic?
  %br
  #choices
    %span.clarification Not at all
    = expertise_choices(answer)
    %span.clarification Very Much So

Finally, here are the accompanying tests:

require 'spec_helper'
include AnswersHelper

describe AnswersHelper do
  describe "#expertise_choices" do
    it "should display five radio buttons" do
      answer = mock_model(Answer, :expertise => nil)
      results = expertise_choices(answer)
      (1..5).each do |i|
        results.should have_tag('input', :id => "answer_expertise_#{i}", :type => 'radio', :value => i)
      end
    end

    it "should have a #choices div" do
      answer = mock_model(Answer, :expertise => nil)
      results = expertise_choices(answer)
      results.should have_tag('div#choices')
    end

    it "should have two .clarification spans" do
      answer = mock_model(Answer, :expertise => nil)
      results = expertise_choices(answer)
      results.should have_tag('span.clarification', :minimum => 2)
    end

    context "when editing" do
      it "should check the existing choice" do
        answer = mock_model(Answer, :expertise => 4)
        results = expertise_choices(answer)
        results.should have_tag('input[checked="checked"]', :type => 'radio', :value => 4)
      end
    end
  end
end

Again, nothing difficult to understand, but you can see how cool and powerful have_tag() is. Unfortunately, when we upgrade to RSpec 2, we'll need to change these tests to use webrat's have_selector(). But for now, let's just enjoy the time we have together, okay?

No comments:

Post a Comment