1

I have the following view which I can't spec out properly in a view spec:

file: "products/index.html.haml"

#products
  = render @products

And this is my view spec:

require 'spec_helper'

describe "products/index.html.haml" do
  let(:products) {[mock_model(Product)]}

  before do
    stub_template "products/product.html.haml" => "" 
    render
  end

  it "should render the products" do
    rendered.should have_selector(#products) do
    rendered.should render_template products
  end
end

The problem here is that have_selector does not accept a block so there is no way to assert that the partial is rendered inside the #products div. Since Capybara matchers don't work within View specs you cannot use within either.

See also this issue: https://github.com/rspec/rspec-rails/issues/387

dwilkie
  • 583
  • 1
  • 4
  • 9

2 Answers2

4

The correct answer is with webrat does take a block, and capybara does not.

Here's the issue in which Jonas Nicklas, the creator of capybara explains why it doesn't and that he's not planning on adding it:

https://github.com/jnicklas/capybara/issues/384

There were some examples using Object#tap to pass blocks to capybara's #find that perhaps once worked, but don't seem to be working any longer.

UPDATE: Confirmation from David that there is no way to do this presently with rspec/capybara:

https://groups.google.com/forum/?fromgroups=#!topic/rspec/HBfznq4Yd0k

Jared
  • 2,885
  • 2
  • 28
  • 31
0

What I do is test for a class or id that the partial renders. And have_selector does accept blocks.

 it "should render the products" do
   rendered.should have_selector('#products') do |products|
     products.should have_select('.product')
   end
   rendered.should render_template 'products'
 end
Thomas R. Koll
  • 3,131
  • 1
  • 19
  • 26
  • One of the main advantages of View specs is to be able to test each individual view in isolation. Your approach links the partial with the view that renders it. Also the block does nothing but pass 'rendered' through. It does not check that .product is inside #products – dwilkie Jun 09 '11 at 04:37
  • Sorry you're wrong, it does not pass the rendered block but only the part that matches the selector thus you can check wether `.product` is inside `#products`. – Thomas R. Koll Jun 09 '11 at 08:00
  • 2
    Sorry you're wrong. Try it yourself. Create a view with the following content:
    where .product is _not_ nested within #products. Then create a view spec like this and watch it pass when it should fail. it "should contain #products" do rendered.should have_selector("#products") do |product| product.should have_selector(".product") end end
    – dwilkie Jun 11 '11 at 06:20
  • Just tested this with Webrat 0.7.3 and RSpec 2.10.0 and it works as advertised, i.e. the test fails if the elements are not nested correctly. – fotos Jul 19 '12 at 12:36
  • 3
    This does not work for me with capybara 2.0.1 and rspec 2.12.0, nothing inside the block gets called. – Jared Dec 14 '12 at 03:41