RSpec and HAML Helpers

Today I faced a problem with specing a helper where I use the haml_tag/puts methods (haml_tag was previously open).

Here’s a solution working with Rails 2.0.2, RSpec 1.0.3 and HAML 1.8.2 :

in spec_helper.rb add :

Spec::Runner.configure do |config|
  ...
  
  # Activate haml to spec helpers
  config.with_options(:behaviour_type => :helpers) do |config|  
    config.include Haml::Helpers  
    config.include ActionView::Helpers  
    config.prepend_before :all do  
       # Update from Evgeny comment, with HAML >= 1.8.2, you can call
       init_haml_helpers

       # Old way for HAML <= 1.8.2
       # @haml_is_haml = true  
       # @haml_stack = [Haml::Buffer.new]  
    end  
  end

  ...
end

then you can write your helper spec like this :

describe ApplicationHelper do
  describe "#top_navigation_menu when logged in" do
    it "returns the menu" do
      @user = mock_model(User)
      capture_haml {
        top_navigation_menu(@user)
      }.should_not be_empty
    end
end

The interesting method is capture_haml, which does the same as Rails builtin capture but for HAML.
haml_tag/puts methods write output directly to the buffer and does not return the generated content as a String, thus we cannot just test on the method output.[…]

Published on Wed, 21 May 2008 19:35

RSpec On Rails and HAML

As my incursion into RSpec continue, I encountered a strange problem on my CC machine. I switched my default layout (aka application.rhtml) to HAML, so the file became application.haml. No problem on my development machine running specs either with spec command or with rake. But the CC machine start sending me error in my specs, telling me application.rhtml does not exists.

I searched some looooong minutes which stack generates this error, four possibilities : RoR, RSpec, Gettext, HAML plugin.

The last thing I did before the specs breaks was to switch a controller spec from view isolation to view integration. So I looked more closely to RSpec On Rails plugin and found something interesting, to run in isolation mode, RSpec on rails stub those methods :

@template.stub!(:file_exists?).and_return(true)
@template.should_receive(:render_template).any_number_of_times.and_return(true) { |*args|
  @first_render ||= args[2]
}
@template.stub!(:find_template_extension_for).and_return("rhtml")
@template.stub!(:read_template_file).and_return("this is fake content generated by rspec")

So it faint Rails about an existing application.rhtml which in fact does not. Rails in its great willingness cache the different template/template extension lookups even in test mode. Then when mixing view integration and view isolation in specs, if those with view integration run after those in isolation, it breaks… or it should, as I can’t reproduce this in my development machine nor can I reproduce this on my CC machine when launching the specs by hand with the spec command (it does occurs only with rake).

About the Rails choice to cache, I fully understand why it is as it is, there should be no template rename during test as it is possible in development mode. So it’s not Rails fault.

But what can we do about this, the simplest solution I came to was to set the template extension caching to off in config/environments/test.rb :

config.action_view.cache_template_extensions         = false

Hope this helps someone else using RSpecOnRails with a custom template system.

[Update]
The difference between my two machine was revealed to me in just after I post this. The rake task on the CC machine, does not sort the controller spec files as my development machine, the problematic file is called addresses_controller_spec.rb so it was the first one evaluate in my development machine and is drowned between others in my CC machine.[…]

Published on Sat, 24 Feb 2007 12:21

RSS