Fork me on GitHub

Kernow Soul

Ruby, Rails and JavaScript Consultant

Shoulda Macro Should_render_a_form_to

| Comments

I’ve been writing a fair number of functional tests recently, one thing that kept cropping up was the need to check if a form had been rendered and that it is going to perform a particular action. Shoulda has a should_render_a_form macro, unfortunately it’s been depreciated and doesn’t do anything other than check a form element has been rendered in the view.

I decided to come up with my own macro that checks the specifics of a form element, enter should_render_a_form_to. This takes three arguments, a description, an options hash and a block that contains the expected url. You can use the macro as follows…

Check there is a form posting to the new_user_post_path:

1
should_render_a_form_to("create a new post", {:method => "post"}) { new_user_post_path(@user.id) }

Check there is a form putting to the user_post_path and that the form has the id of ‘post_edit_form’:

1
should_render_a_form_to("update a post", {:method => "put", :id => "post_edit_form"}) { user_post_path( :user_id => @user.id, :id => 1) }

The macro code is available on github with test coverage. If you just want to cut and paste into your own macro’s file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def should_render_a_form_to(description, options = {}, &block)
  should "render a form to #{description}" do
    expected_url  = instance_eval(&block)
    form_method   = case options[:method]
      when "post", "put", "delete" : "post"
      else "get"
      end
    assert_select "form[action=?][method=?]",
                  expected_url,
                  form_method,
                  true,
                  "The template doesn't contain a <form> element with the action #{expected_url}" do |elms|

      if options[:id]
        elms.each do |elm|
          assert_select elm,
                        "##{options[:id]}",
                        true,
                        "The template doesn't contain a <form> element with the id #{options[:id]}"
        end
      end

      unless %w{get post}.include? options[:method]
        assert_select "input[name=_method][value=?]",
                      options[:method],
                      true,
                      "The template doesn't contain a <form> for #{expected_url} using the method #{options[:method]}"
      end
    end
  end
end

The macro checks both the forms action attribute as well as the hidden input rails uses to specify the method where necessary. I’ve also been playing with creating a macro to check for a form with specific fields such as should_render_a_form_with_fields. This is proving to be slightly more difficult than I originally anticipated and defining a nice interface to the method has been rather tricky.

Comments