testing HTML generated in a helper using open

150 views
Skip to first unread message

Moses Hohman

unread,
Jul 11, 2007, 2:46:55 AM7/11/07
to Haml
What's the best way to test helper methods that generate HTML using
Haml::Helpers#open? I want to test the helper method directly without
using it in a view.

thanks, M

wolfmanjm

unread,
Jul 11, 2007, 5:15:37 PM7/11/07
to Haml
I like RSpec as it has the ability to test helpers standalone.

However I have not yet found the magic incantation to get it to work
with a helper that uses open or puts.

I suspect you need to include HAML and setup some context for it to
render to.

Any ideas on how to do that would be appreciated as I had to disable
many of my RSpec helper tests when I started using HAML open.

Nathan Weizenbaum

unread,
Jul 11, 2007, 9:19:59 PM7/11/07
to ha...@googlegroups.com
Do you have a backtrace I can see? I'm too lazy to do it myself :p. In
my defense, it's the hottest day of the year in Seattle...

- Nathan

wolfmanjm

unread,
Jul 12, 2007, 1:13:48 AM7/12/07
to Haml
Sure here you go...

TypeError in 'ApplicationHelper should display flash'
can't convert Symbol into String
/home/morris/work/snowdogsrus/rails/snowdogsrus/config/../app/helpers/
application_helper.rb:15:in `open'
/home/morris/work/snowdogsrus/rails/snowdogsrus/config/../app/helpers/
application_helper.rb:15:in `display_flash'
/home/morris/work/snowdogsrus/rails/snowdogsrus/config/../app/helpers/
application_helper.rb:13:in `each'
/home/morris/work/snowdogsrus/rails/snowdogsrus/config/../app/helpers/
application_helper.rb:13:in `display_flash'
/home/morris/work/snowdogsrus/rails/snowdogsrus/spec/helpers/
application_helper_spec.rb:12:
/home/morris/work/snowdogsrus/rails/snowdogsrus/spec/helpers/
application_helper_spec.rb:10:in `each'
/home/morris/work/snowdogsrus/rails/snowdogsrus/spec/helpers/
application_helper_spec.rb:10:

# application_helper_spec.rb
require File.dirname(__FILE__) + '/../spec_helper'

describe ApplicationHelper do

it "should display flash" do
for name in [:notice, :warning, :error]
flash[name]= "flash #{name.to_s} message"
display_flash.should == "<div class=\"#{name}\">#{flash[name]}</
div>" # Line 12
flash[name]= nil
end
end
end

# application_helper.rb

def display_flash
for name in [:notice, :warning, :error]
if flash[name]
open :div, flash[name], {:class => name} # Line 15
end
end
nil
end

(Note I know this test will not match, but it is meant to fail the
first time ;)
However the error has nothing to do with the test, it is because open
is probably trying to call File::open

I don't believe HAML is even being loaded for this test.

wolfmanjm

unread,
Jul 12, 2007, 4:15:36 PM7/12/07
to Haml
So presuming I can require haml or something and overcome this error,
how would U check the output? Obviously this spec was written
expecting the display_flash helper to return a string (which it used
to do), by using open it now presumably renders directly to the haml
buffer, so how would I retrieve that so I can test it? (Remember this
helper spec runs without using actually using a view).

Thanks

Nathan Weizenbaum

unread,
Jul 12, 2007, 10:31:02 PM7/12/07
to ha...@googlegroups.com
That's really weird. I can't see anywhere that it would be trying to use
a Symbol as a String. However, I do know how to get "open" as a string.
The trick is that "open" and "puts," like "form_for" and the like, write
directly to Haml's output buffer. However, there's a helper that allows
you to take something directly written to the buffer and get it as a
string, called "capture". It works like so:

capture do
open :foo, 'bar'
end

That would return "<foo>\n bar\n</foo>". So you could do "capture {
display_flash }.should == ...".

Try that and see if it works. If it doesn't, let me know.

- Nathan

wolfmanjm

unread,
Jul 13, 2007, 12:03:46 AM7/13/07
to Haml
I get...

undefined method `capture' for [Dynamically generated class for RSpec
example]

>From the spec, what should I require in the spec to get all the HAML
goodness?

Thanks

Hampton

unread,
Jul 13, 2007, 10:49:13 AM7/13/07
to ha...@googlegroups.com
Yeah, the Helpers being tested definitely aren't loading Haml in.

Are they just expecting vanilla Strings back from the calls?

-hampton.

wolfmanjm

unread,
Jul 13, 2007, 2:08:02 PM7/13/07
to Haml
Well they used to :) Now I am trying to use the capture {...} syntax
as Nathan suggests, that would work fine, if it could find the capture
method, and the haml libraries for the open ... method.

it "should display flash" do
for name in [:notice, :warning, :error]
flash[name]= "flash #{name.to_s} message"

capture{
display_flash
}.should == "<div class=\"#{name.to_s}\">#{flash[name]}</div>"


flash[name]= nil
end
end

Gives me and error...
undefined method `capture'


On Jul 13, 7:49 am, Hampton <hcat...@gmail.com> wrote:
> Yeah, the Helpers being tested definitely aren't loading Haml in.
>
> Are they just expecting vanilla Strings back from the calls?
>
> -hampton.
>

Sean Cribbs

unread,
Jul 13, 2007, 3:12:06 PM7/13/07
to ha...@googlegroups.com
You might be able to mock that out. It looks like your spec bleeds too much into Haml and ActionView's domain.  Here's what I might do:


it "should display flash" do
  [:notice, :warning, :error].each do |name|
    message = "flash #{name.to_s} message"
    flash.should_receive(:[]).with(name).and_return(message)
    MyHelper.should_receive(:open).with(:div, message, :id => name.to_s) # change to match your helper name
    display_flash
  end
end

Now, you may want to do something with the MyHelper.should_receive line and have it return something, which you could verify after the call.

Sean Cribbs

wolfmanjm

unread,
Jul 13, 2007, 3:21:59 PM7/13/07
to Haml
That is correct, and well within the paradigm that RSpec sets out, so
I agree that would be the best solution to test this helper.

However the original question at the top of the page was how to test
the actual HTML generated by Haml#open. presuming you don't trust Haml
to do the right thing ;) it would be nice to know how to test a helper
end to end through Haml to the generated HTML.

I would certainly like to know how to do it.

Another way to test end to end (and may go against RSpec methodology,
but does work well) is to simply test a view that uses the helper, and
test the generated HTML, which I have done and it works well. But a
more focused test on a specific helper would also be a nice tool in my
toolbox.

wolfmanjm

unread,
Jul 13, 2007, 4:56:10 PM7/13/07
to Haml
Ok I'm making progress :) Now I can actually post an error from within
HAML!

So I added this to my spec, which cleared up most of the previous
errors...

describe ApplicationHelper do
include ActionView::Helpers
include ActionView::Helpers::CaptureHelper
include Haml::Helpers
...

It now finds HAML and calls HAML#open it also can find capture.

Now I get this error, presumably because the HAML buffer has not been
initialized. So is there a call I shol dmake to initialize HAML in the
spec test?

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
/home/morris/work/snowdogsrus/rails/snowdogsrus/config/../vendor/
plugins/haml/lib/haml/helpers.rb:276:in `buffer'
/home/morris/work/snowdogsrus/rails/snowdogsrus/config/../vendor/
plugins/haml/lib/haml/helpers.rb:259:in `open'


/home/morris/work/snowdogsrus/rails/snowdogsrus/config/../app/
helpers/application_helper.rb:15:in `display_flash'

Nathan Weizenbaum

unread,
Jul 14, 2007, 5:03:15 AM7/14/07
to ha...@googlegroups.com
This should work:

before :each do
@haml_is_haml = true
@haml_stack = [Haml::Buffer.new(:attr_wrapper => "'")]
end

However, because this is so useful, I've added it as a helper in trunk.
It would be easier to grab that and just run

before(:each) { init_haml_helpers }

Note that capture still won't work, due to some strange interactions (or
the lack thereof) between Haml and ActionView. Use capture_haml instead;
it does the same thing, but will work.

Let me know if this doesn't work.

- Nathan

wolfmanjm

unread,
Jul 14, 2007, 6:53:30 PM7/14/07
to Haml
Excellent Thank you!! That worked like a charm...

So to answer the persons original question...

Use RSpec and this is an example of a complete helper rspec that tests
the HTML generated...

require File.dirname(__FILE__) + '/../spec_helper'

describe ApplicationHelper do
include ActionView::Helpers

include Haml::Helpers

it "should display flash" do


@haml_is_haml = true
@haml_stack = [Haml::Buffer.new(:attr_wrapper => "'")]

for name in [:notice, :warning, :error]
flash[name]= "flash #{name.to_s} message"

capture_haml{
display_flash
}.should =~ /<div class='#{name.to_s}'>\s+#{flash[name]}\s+<\/
div>/


flash[name]= nil
end
end
end

for something in application_helper.rb...

def display_flash
for name in [:notice, :warning, :error]
if flash[name]

open :div, flash[name], {:class => name.to_s}
end
end
nil
end

wolfmanjm

unread,
Jul 14, 2007, 7:54:26 PM7/14/07
to Haml

Steven R. Baker

unread,
Jul 15, 2007, 8:18:35 PM7/15/07
to Haml
> What's the best way to test helper methods that generate HTML using
> Haml::Helpers#open? I want to test the helper method directly without
> using it in a view.

If the helper was arrived at by extraction[1], it's already been
covered elsewhere and you don't need to test it again.

-Steven

1. If it wasn't, you're overengineering. Stop it.

Reply all
Reply to author
Forward
0 new messages