Sometimes when writing specs, you want to test a high level case multiple times across multiple spec tests. This test may involve asserting multiple things on the page.
There is probably a proper way to do this, like see this gist , or there is my way, which seems way simpler.
So the objective is to be able to express tests as follows:
page.should be_super_awesome page.should have_super_awesomeness
To do this, you need to extend Capybara::Session. So what I do is in spec/support/super_awesome_helper:
module SuperAwesomeHelper module Session def is_super? ... end def has_awesomeness? ... end end end
Notice the grammar. To have a helper that is be_something, the method needs to be is_something? And to have a helper that is have_something, the method should be has_something?.
Then to load this into Capybara::Session
Capybara::Session.send(:include, SuperAwesomeHelper::Session)
This is all neat and dandy, but what about descriptive error messages? Good question, watson! Here’s a sample implementation:
module SuperAwesomeHelper module Session def super_awesome? errors = false errors ||= "Wrong path" unless current_path == super_awesome_path errors ||= "Missing content: You are awesome" unless !errors and has_content?("You are awesome") errors ||= "Missing selector: #awesome-div" unless !errors and has_selector?("#awesome-div") People.all.each{|p| errors ||= "missing person #{p.name}" unless !errors and has_selector?(".person-#{p.name}")} !errors or raise Capybara::ExpectationNotMet, errors return true end end end
The magic line here is:
!errors or raise Capybara::ExpectationNotMet, errors
which is what tells capybara to catch the exception and handle it properly. You’ll notice my pattern here will stop checking for errors(essentially) once you hit the first error(if, at all),
which I think is ideal. But you could implement it differently so it spits back all the error messages.
Thanks for listening.
Pingback: Test your code: unit tests and full stack integration tests. | Smooth Sailing