I normally do not do a lot of view specs, but at least I want to make sure that my view renders without errors. And sometimes I really need to make sure that some link is shown or hidden depending on e.g. the role of the user or linked objects.

For example,

  describe "posts/show.html.haml" do
    context "without any comments" do
      it "displays no comments" do
        @post = Factory(:post)
        render
        rendered.should contain(I18n.t('posts.show.no_comments'))
      end
    end
  end

So we check the rendered result, whether it contains a specific text.

But what happens if your view is rendering different yield regions? Like a body (the default region) and a sidebar.

Let’s use a view like this :

  =show_for @post do |p|
    = p.attribute :title
    = p.attribute :content  

  - if @post.comments 
    = render :partial => 'comments'
  - else
    = t('posts.show.no_comments')

  =content_for :sidebar do
    = link_to 'Edit', edit_post(@post) if is_allowed_to?(:edit)

It renders the attributes using the show_for gem, and then renders inside the sidebar a link if the current user is allowed to edit it.

Now I want to test what is rendered into the sidebar. To my dismay I found that neither content_for or content_for?
worked at all inside rspec. And rendered does not contain the data for the other regions.

So somehow I would want to get to the content for :sidebar.

It appears that the different regions are actually stored inside an instance variable of the view. Once I figured that out, the rest was easy:

  describe "posts/show.html.haml" do
    def rendered_content_for(name)
      view.instance_variable_get(:@_content_for)[name]
    end

    context "with enough rights" do
      it "displays a link to edit the post" do
        @post = Factory(:post)
        view.stub(:is_allowed_to?) { true }
        render
        rendered_content_for(:sidebar).should contain('Edit')
      end
    end
    context "with no rights" do
      it "does not display a link to edit the post" do
        @post = Factory(:post)
        view.stub(:is_allowed_to?) { false }
        render
        rendered_content_for(:sidebar).should_not contain('Edit')
      end
    end
  end

Hope that this helps somebody. Or did you find a better way?