Introduction to feature specs in RSpec
Lately, I’ve decided to spend a lot of focus on writing feature specs with RSpec and Capybara. Feature specs allow you to test your application from the user’s point of view. You use the Capybara gem to test your application’s interface with commands like these:
(A point of confusion: sometimes these kinds of tests are called “acceptance tests” or “integration tests,” and now DHH is calling them system tests and is declaring that a future release of Rails will provide functionality for tests like these.)
I’ve found that this methodology tests 80% of what I need without needing to dive into the minutiae of testing every boundary case in every method in every class. Don’t get me wrong; I still test most custom logic in model specs and some authorization logic in request specs, but I try to not go overboard. A deeper level of detail in my testing can come later when my app becomes a wild success, amiright?
My understanding is that these tests run on the slower side compared to other types of tests that RSpec can run, but I’ve found the trade-off to be worth it to test the whole system from the user’s point of view.
Tutorial: let’s get into some CRUD
Simple CRUD functionality is a great place to start to get a feel for how this all works. Let’s do this for a simplified
Product model in the admin area of a fictitious e-commerce application.
And quick configuration of some validations on the
Product class at
(I may as well use this example as a chance to pimp the wonderful money-rails gem for handling currency.)
A good place to start is a product creation area. We can go ahead and setup the route under an
Then we write our test first at
spec/features/products/admin_creates_product_spec.rb. I enjoy the suggestion by Thoughtbot to name your features with an actor and then an action, thus naming the feature
Admin creates product.
With this in place, you can build the functionality to make the test pass. The finished product would look something like the following files.
(Note that the code above uses the amazing Simple Form gem.)
We’d think that this code would make the test pass, but there is a problem:
We need to add a handler for our flash message to
Then we should see the test pass:
Next, we can add a test that the form correctly reports validation errors when the user doesn’t enter data correctly:
And then update the
create action to handle validation errors:
You should get a passing grade from RSpec:
Handling updates and deletes
I assume that you know how to build basic CRUD, so I will leave that as an exercise for the reader. Or hey, you can just look at what I committed to the GitHub repo.
However, this post is about feature specs, so this is how I would write the specs for the
Notice that in this spec’s
with valid input scenario, we’re using the form to replace the values persisted by
product with the values from
Other miscellaneous feature spec examples
This is but a mere blog post, but I could demonstrate a few other features of Capybara that I use quite frequently in feature specs.
If you want to check for content within a specific block of your page, you can pass your
expect assertion(s) in a block to
within, using a CSS selector:
Testing email that your app sends and receives is simple with the email_spec gem:
js: true to your specs:
Want to learn more?
I found these to be good resources for fine-tuning my feature spec skills:
- Rails 4 in Action, Ryan Bigg, Yehuda Katz, and Steve Klabnik
- Multitenancy with Rails, Ryan Bigg
- How I Test, Ryan Bates, RailsCasts
- End-to-End Testing with RSpec Integration Tests and Capybara, Harlow Ward, Thoughtbot
- How We Test Rails Applications, Josh Steiner, Thoughtbot