{"id":2804,"date":"2012-06-12T10:25:39","date_gmt":"2012-06-12T13:25:39","guid":{"rendered":"http:\/\/blog.plataformatec.com.br\/?p=2804"},"modified":"2012-06-12T10:25:39","modified_gmt":"2012-06-12T13:25:39","slug":"improving-the-integration-between-capybara-and-rspec","status":"publish","type":"post","link":"https:\/\/blog.plataformatec.com.br\/2012\/06\/improving-the-integration-between-capybara-and-rspec\/","title":{"rendered":"Improving the integration between Capybara and RSpec"},"content":{"rendered":"
When David Chelimsky was visiting S\u00e3o Paulo in last April, we invited him to go out for some coffee, beers and brazilian appetizers. We had a great time and we talked about different topics like OO, programming languages, authoring books and, as expected, about testing.<\/p>\n
One of the topics in our testing discussion was the current confusion in rspec-rails request specs when using Capybara. There is an open issue for this in rspec-rails’ issues tracker<\/a> and discussing it personally allowed us to talk about some possible solutions, which could take months in internet time. \ud83d\ude42<\/p>\n rspec-rails is a gem that wraps Rails testing behaviors into RSpec’s example groups. For example, the controller example group is based on This setup with the request example group running on top of Rails’ Integration Runner works fine until you add Capybara to your application (which is always a good idea). The issue is that Capybara by default includes its DSL in the same request example group<\/a> and that’s when the confusion starts.<\/p>\n Capybara, being an acceptance test framework, does not expose low-level details like a request or response object. In order to access a web page using Capybara, the developer needs to use the method However, since both Capybara DSL and Rails’ Integration Runner are included in the same example group, both methods This confusion not only happens inside each test<\/a> but it also leads to a poor testing suite. I have seen many, many files inside Talking to David, I have expressed a possible solution to this problem based on how we have been building applications at Plataformatec. First of all, we start by having two directories: Everything you want to test from the user\/browser perspective goes under Everything under This separation of concerns already helps solving the confusion above. Under Therefore, while this blog post means to provide some guidance for those that run into such problems, we also would like to propose a solution that we discussed with David. The solution goes like this:<\/p>\n 1) We change RSpec to no longer generate 2) We change Capybara to include by default its DSL and RSpec matchers under The proposal suggests the addition of two new directories instead of changing the behavior of existing ones in order to be backwards compatible while ensuring a safe and more semantic future for everyone else. David asked me to outline our conversation in a blog post, so we can get some awareness and feedback before undergoing such changes. So, what do you<\/strong> think?<\/p>\n","protected":false},"excerpt":{"rendered":" When David Chelimsky was visiting S\u00e3o Paulo in last April, we invited him to go out for some coffee, beers and brazilian appetizers. We had a great time and we talked about different topics like OO, programming languages, authoring books and, as expected, about testing. One of the topics in our testing discussion was the … \u00bb<\/a><\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[94,7,183],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2804"}],"collection":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=2804"}],"version-history":[{"count":8,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2804\/revisions"}],"predecessor-version":[{"id":2833,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2804\/revisions\/2833"}],"wp:attachment":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=2804"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=2804"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=2804"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}ActionController::TestCase::Behavior<\/code><\/a>. There are also example groups for views, helpers and so forth, but for now we are interested in the request example group, which is as a wrapper for
ActionDispatch::Integration::Runner<\/code><\/a>. The Rails’ integration runner is built on top of
rack-test<\/code>, a great small gem that adds support to methods like
get<\/code>,
post<\/code>,
put<\/code> and
delete<\/code> and handle the rack request and response objects.<\/p>\n
visit<\/code> (instead of
get<\/code>). To read the accessed page body, the developer must use
page<\/code> instead of manipulating the
response<\/code>.<\/p>\n
visit<\/code> and
get<\/code> are available! Not only that, even if I visit a web page using Capybara’s
visit<\/code>, I can still access the request and response object that comes from Rails, except that they will be blank since Capybara uses a completely different stack to access the application.<\/p>\n
spec\/requests<\/code> that mixes both syntaxes.<\/p>\n
spec\/requests<\/code> and
spec\/acceptance<\/code>. Since both are supported by Capybara, this (mostly) works out of the box.<\/p>\n
spec\/acceptance<\/code>. So if you want to test that by filling the body and the title fields and pressing the button “Publish” publishes a new blog post, you will test that under acceptance (protip: we usually have subdirectories inside
spec\/acceptance<\/code> based on the application roles, like
spec\/acceptance\/guest<\/code>,
spec\/acceptance\/admin<\/code>, etc).<\/p>\n
spec\/requests<\/code> applies to the inner working of your application. Is it returning the proper http headers? Is this route streaming the correct JSON response? Also, since APIs are not part of the user\/browser perspective, they are also tested under
spec\/requests<\/code> and not under
spec\/acceptance<\/code><\/a>.<\/p>\n
spec\/acceptance<\/code>, you should use only Capybara helpers. Inside
spec\/requests<\/code>, you are using Rails provided tools. However, this does not solve the underlying problem that both helpers are still included in
spec\/requests<\/code>.<\/p>\n
spec\/requests<\/code>, but both
spec\/api<\/code> and
spec\/features<\/code> (I have proposed
spec\/acceptance<\/code> but David pointed out those are not strictly speaking acceptance tests). The Capybara DSL (
visit<\/code>,
page<\/code> and friends) should not be included in
spec\/api<\/code> under any circumstance.<\/p>\n
spec\/features<\/code> and change the
feature<\/code> method to rely on the type
:features<\/code> instead of
:requests<\/code><\/a>.<\/p>\n