Christopher J. Bottaro
2011-Oct-08 18:30 UTC
[rspec-users] Rails view spec expectations/matchers
>From looking at the RSpec Rails documentation(https://www.relishapp.com/rspec/rspec-rails/docs/view-specs/view-spec) it seems like rendered is just a string and you can''t really do any assert_select type stuff out of the box. After Googling around, it seems that the RSpec authors decided that if you want that functionality, you should just use Capybara or some such... is that correct? If that is the case, can you please look at how I''m writing my view specs and let me know if there is a better/cleaner way? Here goes... *spec/spec_helper.rb* RSpec.configure do |config| config.include RSpec::ViewHelper, :type => :view end *spec/support/view_helper.rb* module RSpec::ViewHelper def page @page ||= Capybara::Node::Simple.new(rendered) end end *spec/views/comments/index.html.haml_spec.rb* require "spec_helper" describe "comments/index.html.haml" do it "should show a proper breadcrumb" do # Assign instance vars # Mock helper methods render page.should have_selector("div.breadcrumb") page.find("div.breadcrumb").tap do |node| node.find_link("Home").should be node.find_link("Blah1").should be node.find_link("Blah1").should be node.find_link("Comments").should be end end end Is there a better way? Including Capybara just for the finders/matchers seems kinda heavy. Also it would be nice if I could write stuff like node.should have_link("Home"), to be more consistent with RSpec matchers (though I guess I could write custom matchers to wrap all the Capybara stuff... has anyone already done this?). Thanks for the help. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20111008/4f1593d9/attachment-0001.html>
On Oct 8, 2011, at 1:30 PM, Christopher J. Bottaro wrote:> >From looking at the RSpec Rails documentation (https://www.relishapp.com/rspec/rspec-rails/docs/view-specs/view-spec) it seems like rendered is just a string and you can''t really do any assert_select type stuff out of the box. > > After Googling around, it seems that the RSpec authors decided that if you want that functionality, you should just use Capybara or some such... is that correct?The `rendered` method is a wrapper around the `@rendered` instance variable, which is provided by Rails: https://github.com/rails/rails/blob/master/actionpack/lib/action_view/test_case.rb#L113 The fact that assert_select doesn''t work on a string is an issue you can (and probably should) report to the rails project.> If that is the case, can you please look at how I''m writing my view specs and let me know if there is a better/cleaner way? > > Here goes... > > spec/spec_helper.rb > RSpec.configure do |config| > config.include RSpec::ViewHelper, :type => :view > end > > spec/support/view_helper.rb > module RSpec::ViewHelper > def page > @page ||= Capybara::Node::Simple.new(rendered) > end > endViewHelper sounds like something to help your views, not your view specs. I''d name this something like RSpec::CapybaraExtensions. I''d also avoid the name "page", which carries different implications in controller and request specs. Suggestions below ...> spec/views/comments/index.html.haml_spec.rb > require "spec_helper" > > describe "comments/index.html.haml" do > > it "should show a proper breadcrumb" do > # Assign instance vars > # Mock helper methods > > render > > page.should have_selector("div.breadcrumb") > page.find("div.breadcrumb").tap do |node| > node.find_link("Home").should be > node.find_link("Blah1").should be > node.find_link("Blah1").should be > node.find_link("Comments").should be > end > end > > end > > Is there a better way?Several! Here''s one: def rendered Capybara.string(@rendered) end it "displays a proper breadcrumb" do render rendered.find("div.breadcrumb a", :text => "Home") rendered.find("div.breadcrumb a", :text => "Comments") end it "displays a proper breadcrumb" do render rendered.find("div.breadcrumb").tap do |form| form.find("a", :text => "Home") form.find("a", :text => "Comments") end end `find` doesn''t look like an expectation, but if the elements aren''t there you get OK feedback: Capybara::ElementNotFound: Unable to find css "div.breadcrumb" You could also make this more expressive like this: def rendered Capybara.string(@rendered) end def within(selector) yield rendered.find(selector) end it "displays a proper breadcrumb" do render within "div.breadcrumb" do |breadcrumb| breadcrumb.should have_selector("a", :text => "Home") breadcrumb.should have_selector("a", :text => "Comments") end end Now you''d get the feedback above if there were no "div.breadcrumb", but you''d get Capy''s matcher feedback if there were no matching anchor tags within "div.breadcrumb", which is not very good right now: expected css "a" with text "Home" to return something There is a github issue to address this, but it''s no small matter to get right (which is why it''s still open): https://github.com/jnicklas/capybara/issues/331> Including Capybara just for the finders/matchers seems kinda heavy.Why? Just load up the parts you want.> Also it would be nice if I could write stuff like node.should have_link("Home"), to be more consistent with RSpec matchers (though I guess I could write custom matchers to wrap all the Capybara stuff... has anyone already done this?).I''d prefer to stick to `have_selector("a", :text => "Home")`. That way it''s the same API for every tag. But that''s me. If you prefer have_link, have_text_field, etc, etc, then you should write them, and maybe even publish them in a gem. HTH, David -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20111011/d2cb7c20/attachment.html>