Forum: RSpec [RSpec] Clarification on using shared_examples_for on a Rails Controller

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Stephen G. (Guest)
on 2009-04-22 21:58
(Received via mailing list)
I have a Rails controller that I am using 'before_filter' on certain
actions
to assign some extra variables.  I noticed the 'shared_examples_for'
method
and thought this would be a good way to test that the given actions are
loading what they need.  I wrote the following:

shared_examples_for 'pages showing the yearly archive' do

    it 'should assign a list of yearly archives' do
      Factory.create(:post, :published_at => Time.local(2009,02,01))
      Factory.create(:post, :published_at => Time.local(2009,01,01))
      Factory.create(:post, :published_at => Time.local(2008,01,01))
      Factory.create(:post, :published_at => Time.local(2007,01,01))
      Factory.create(:post, :published_at => Time.local(2001,01,01))

      get :index

      assigns[:years].should == [ 2009, 2008, 2007, 2001 ]
    end

  end

The problem is, it is specific to the 'index' action.  I can't use the
'it_should_behave_like "pages showing the yearly archive"' for other
actions.

Am I just doing this wrong or is there a way to fix this?

- Stephen H. Gerstacker
Mark W. (Guest)
on 2009-04-22 22:23
(Received via mailing list)
On Wed, Apr 22, 2009 at 10:04 AM, Stephen H. Gerstacker
<removed_email_address@domain.invalid> wrote:
>       Factory.create(:post, :published_at => Time.local(2008,01,01))
> The problem is, it is specific to the 'index' action.  I can't use the
> 'it_should_behave_like "pages showing the yearly archive"' for other
> actions.

Assign the action to an instance variable and set it to the desired
value in a before(:all) in each of the sharers. In the shared example,
do get @action.

///ark
David C. (Guest)
on 2009-04-22 22:32
(Received via mailing list)
On Wed, Apr 22, 2009 at 12:04 PM, Stephen H. Gerstacker
<removed_email_address@domain.invalid> wrote:
>       Factory.create(:post, :published_at => Time.local(2008,01,01))
> The problem is, it is specific to the 'index' action.  I can't use the
> 'it_should_behave_like "pages showing the yearly archive"' for other
> actions.
>
> Am I just doing this wrong or is there a way to fix this?

Shared examples don't support parameterization, but macros do. Try
something like this:

module Macros
  def shows_yearly_archive_for(requests={})
    requests.keys.each do |action|
      it "should assign a list of yearly archives on
#{requests[action]}  #{action}" do
        Factory.create(:post, :published_at => Time.local(2009,02,01))
        Factory.create(:post, :published_at => Time.local(2009,01,01))
        Factory.create(:post, :published_at => Time.local(2008,01,01))
        Factory.create(:post, :published_at => Time.local(2007,01,01))
        Factory.create(:post, :published_at => Time.local(2001,01,01))

        send requests[action], action

        assigns[:years].should == [ 2009, 2008, 2007, 2001 ]
      end
    end
  end
end

describe SomeController do
  extend Macros
  shows_yearly_archive_for :index => :get
end

You can also extend with Macros from the config in spec_helper:

Spec::Runner.configure {|c| c.extend(Macros, :type => :controller)}

HTH,
David

ps - completely un-tested - that was off the top of my head
unknown (Guest)
on 2009-04-23 00:18
(Received via mailing list)
----- Original Message ----
> From: David C. <removed_email_address@domain.invalid>

> Shared examples don't support parameterization, but macros do. Try
> something like this:
>
> module Macros
>   def shows_yearly_archive_for(requests={})
[...]
>   end
> end
>
> describe SomeController do
>   extend Macros
>   shows_yearly_archive_for :index => :get
> end


Nice.  This must be newish (I see it in book beta4 - good!).  I'd been
using callbacks defined in the example group next to
it_should_behave_like() to get any relevant parameters.  A bit icky,
I'll admit.  So I can just pass the details from the callback directly
to the macro, when I port it/them.  Sweet.

I've been using a pattern for my shared example groups, similar to one I
correlate (erroneously?) to a Ben M. post.  The original pattern:
do_foo(), where foo is get, post, whatever and the shared example probes
the calling example group to find which one is relevant.

My variation is do_action(), where the example group directly defines
do_action() in whatever way is suitable to the example group (using
instance variables set by before blocks, etc).  This method could be
defined usefully by either a Controller example group or a Model example
group.

I feel like even when using macros, I'd want to continue using my
do_action() pattern.  But maybe I have a hammer and so I'm looking for a
nail.

Is there another approach that gives different/better value when using
macros?

Thanks,

Randy
This topic is locked and can not be replied to.