Upgrading to RSpec 3.7.2 and system specs

January 08, 2018

A few months ago, literally days after I released a major update to Everyday Rails Testing with RSpec with coverage of Rails 5.1 and RSpec 3.6, the RSpec team released a new version, 3.7. Due to how I build up each chapter incrementally, and the fact that the rspec-rails gem is introduced to the book’s sample code base early on, I’ve decided not to try to retrofit. Instead, I want to share my experience upgrading the sample application to use RSpec 3.7–and most importantly, its support for Rails 5.1 system tests.

With system tests, the Rails framework finally offers end-to-end, browser-based tests like the feature-style approach I cover in chapter six of my book, out of the box. These tests are called system tests and, in my opinion, have been a glaring omission from the default Rails stack for some time. I appreciate the hard work the Rails team put into making system tests simple to configure and write–even if it means more work as me as someone who teaches others how to test Rails apps!

As you may know, Rails ships with the MiniTest testing framework by default. But with RSpec 3.7, you can add system specs to your suite as long as you’re testing a Rails 5.1 app. RSpec 3.7 will work with older versions of Rails, but you’ll need to stick with feature tests for integration testing. You’ll also miss out on some of the other features provided by Rails 5.1’s system testing support, though there are alternatives I’ll share below.

The upgrade

I made a separate commit for each step of this process; feel free to follow along. While preparing to work on this upgrade, I ran into a dependency conflict with jquery-rails and the new rspec-rails. For the purposes of this tutorial, I upgraded Rails to a newer patch of 5.1.

Before starting the RSpec upgrade, run the existing specs and make sure everything still passes as expected. This is especially important on projects that have gone untouched for awhile. With a passing test suite, we can upgrade the dependency in the project’s Gemfile:

group :development, :test do
  gem 'rspec-rails', '~> 3.7.2'
  # other gems ...
end

Run bundle update rspec-rails to complete the installation. If we wanted to, we could stop now. Feature specs continue to work with RSpec 3.7, and will continue to do so for the foreseeable future. However, in the interest of keeping our test suite forward-facing, let’s move existing feature specs to system specs.

First, I recommend modifying our test driver configuration, located in spec/support/capybara.rb, and explicitly set the speedy Rack::Test driver for basic browser testing, and a JavaScript capable driver for more complex browser interactions (I prefer headless Chrome). Replace the file’s contents:

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :rack_test
  end

  config.before(:each, type: :system, js: true) do
    driven_by :selenium_chrome_headless
  end
end

You can also set driven_by on a test-by-test basis, but I like setting things system-wide when I can.

Let’s wrap up by migrating existing feature specs to the new system testing structure and syntax. We’ll make the following changes:

  • Rename spec/features to spec/system (diff)
  • Set each spec’s type as type: :system (diff)
  • Use RSpec.describe to define system specs, instead of RSpec.feature (diff)
  • Replace the scenario alias in previous feature specs with the standard it syntax (this appears to be optional) (diff)

That’s it! Specs still pass, and going forward, we can add new integration tests in the new spec/system directory.

Generating new system specs

As of version 3.7.2, rspec-rails doesn’t provide a generator to create system specs, though a pull request is in progress as I write this. In the meantime, you’ll need to manually create new spec files in spec/system, using this general boilerplate:

require 'rails_helper'

RSpec.system "Test name", type: :system do
  it "does something" do
    # ... your test
  end
end

Screenshots

Since we’ve been using Capybara, we can already save screenshots of browser-based tests in progress using save_screenshot. With Rails 5.1 and RSpec 3.7, we can use the alternative take_screenshot method anywhere in a test to generate an image of the simulated browser at that point. The file is saved in tmp/screenshots by default. And if a test fails, you’ll get a screenshot automatically! This is a useful feature when debugging integration tests that run in headless environments.

If you’re not using Rails 5.1, you can get similar functionality with the capybara-screenshot gem. It requires a little additional setup, but is also more full-featured than what Rails 5.1 provides out of the box.

Database Cleaner

I removed coverage of Database Cleaner from the Rails 5.1 edition of the book, because it wasn’t necessary to make tests work in the sample app. However, if you’re upgrading from previous versions of Rails and RSpec, you may have used this tool to keep database state from leaking across tests. With Rails 5.1, you no longer need Database Cleaner, at least from my limited experiments and what I’ve read. If you’ve found otherwise, please leave a comment to let me know.

Moving forward

RSpec’s documentation now recommends using system specs over feature specs. This seems reasonable to me, based on my experience so far with migrating existing feature tests to the new approach. I don’t think you necessarily need to make this switch a priority over other work you have to do on your Rails app, but if time permits, give it a shot. I haven’t worked with the new tooling extensively yet, but there’s a chance you may need to update your Capybara dependency, too, if you run into errors or deprecation warnings.

I’d love to hear about your experiences moving to system specs in your Rails apps, both positive and negative. Please leave a comment below. Thanks as always for reading!

References

Rails testing made simple

Learn to test Rails apps the way I learned, building up tests step-by-step, in Everyday Rails Testing with RSpec. Expanded to include exclusive content and a complete sample Rails application. Learn more »

Also available on Amazon.com.

blog comments powered by Disqus