- Harrison Broadbent
I've been writing feature specs for a while. Turns out, they should have been system specs instead! Maybe you've done the same, and I wouldn't blame you — there's not much good info available, and it's hard to find out what the differences are.
To help, I wrote this article. In it, I break down the difference between system specs and feature specs in RSpec and Rails, and walk you through refactoring your feature specs to system specs.
Table of Contents
Lately, I've been writing a lot of RSpec tests, and I came upon a conundrum — Should I write feature specs, or system specs? Given that RSpec released system specs in 2017, it was surprisingly difficult to find an answer!
Turns out, if your running Rails 5.1+, you should write system specs. If you've been writing feature specs though, it's OK! I was doing that too, and they work just fine.
If you want to make the (simple) transition though, this article is for you. I start with a quick breakdown of the differences between RSpec's feature specs and system specs. Then, I walk you through converting your feature specs into system specs.
Feature Specs vs. System Specs — What's the difference?
There's one key difference between RSpec's feature specs and system specs — system specs are RSpec's wrapper around native Rails system tests, whereas feature specs are a kind of "proto-system-spec", from a time before Rails included system tests.
The RSpec team officially recommends Rails 5.1+ apps use system specs (since Rails 5.1 was the version of Rails which introduced native system tests).
Here's a great explanation of their differences, pulled from the RSpec wiki —
Before Rails introduced system testing facilities, feature specs were the only spec type for end-to-end testing. While the RSpec team now officially recommends system specs instead, feature specs are still fully supported, look basically identical, and work on older versions of Rails.
Both specs are fine, both are similar, but system specs have a few bonus extras —
System specs easily integrate with different test drivers. By default, they run using
selenium, but you can change that to
playwrighteasily. It's a simple change in system specs, but trickier with feature specs.
System specs also handle database cleaning between runs. This saves you from installing the
database-cleanergem alongside your test suite.
That's it! The differences are slight, but I hope this section has cleared things up for you. It took me hours of research to piece this together!
Now, read on as I show you how to refactor your feature specs to system specs (it's simple, I promise 😉).
Refactoring your feature specs to system specs
Refactoring from feature specs to system specs is, fortunately, pretty straightforward.
Essentially, we just add a new gem, edit
spec/rails_helper.rb, and rename our feature specs into system specs.
Let's begin! Start by adding
selenium-webdriver to your
group :development, :test do ... # testing gem "capybara" gem "selenium-webdriver" gem "rspec-rails" end
RSpecs system specs use
selenium by default, but we're going to overwrite that. We're going to configure RSpec to run our system specs with
rack_test, and only use
Let's do that now. By editing
rails_helper.rb, we tell RSpec to use
rack_test by default and only use
selenium as needed. If you wanted to swap
playwright (or another browser automation tool), you could do it here.
Add this to the end of your
So why do this? Why not use
selenium for everything?
rack_test runs a lot faster than
rack_test as the default driver for our system specs, they run much quicker. Then we tell RSpec to use
If we didn't add this config, RSpec would use
selenium for everything. There's nothing wrong with this (although it might break some specs with its different API) — it would just be an unnecessary performance slowdown.
On to our next step though — time to edit our spec files.
To start, rename
spec/system. If you've configured RSpec with
config.infer_spec_type_from_file_location!, this should be enough to tell RSpec to treat these as system specs.
I like to specify the
type: of my specs directly anyway — if you do too, you'll need to edit your specs and change their
# OLD: feature spec type RSpec.feature "name", type: :feature do # NEW: system spec type RSpec.describe "name", type: :system do
There's a chance that if you run
rspec now, everything will work! Your system specs will run as they should, and everything will pass. If so, congratulations!
It's likely though that you'll run into some sort of error, caused by
selenium (or whichever browser automation tool you're using).
In my case (on macOS), I was getting this error —
Selenium::WebDriver::Error::SessionNotCreatedError: session not created: This version of ChromeDriver only supports Chrome version 114
This one's pretty simple, it's caused by
selenium-chromedriver not having access to a local
chromedriver executable. To fix it, I just had to install
chromedriver and give it permission to run —
❯ brew install chromedriver ==> Downloading https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/116.0.5845.96/mac-arm64/chromedriver-mac-arm64.zip ==> Installing Cask chromedriver ==> Linking Binary 'chromedriver' to '/opt/homebrew/bin/chromedriver' 🍺 chromedriver was successfully installed!
Then I removed the extended attributes from
chromedriver, so macOS could run it straight away —
xattr -d com.apple.quarantine $(which chromedriver)
If you're on another operating system, you'll have to make sure you've correctly installed
Once it's installed though, your system specs should work! RSpec should be able to load
selenium correctly and interact with your specs.
Note: I replaced
rails_helper.rbto run my specs in "headed mode" for the gif above. This lets you see what RSpec and
seleniumare actually doing, which is fun to watch and can be helpful for debugging.
Since RSpec system specs handle wiping the database for us, you can also remove the
database_cleaner gem from your
Gemfile, and any related configuration — in my case, I could also delete
Enjoy your system specs!
Conclusion and more resources
I hope you enjoyed this article! It was tough piecing together all the scattered info on system vs. feature specs, but I think this article is a solid place to start.
Feel free to reach out if you have any questions, otherwise, these links are great places to go for more information on RSpec's system specs and feature specs —
RSpec system spec and feature spec documentation: https://rspec.info/documentation/3.8/rspec-rails/#system-specs-feature-specs-request-specs-what-s-the-difference
Upgrading to RSpec 3.7.2 and system specs: https://everydayrails.com/2018/01/08/rspec-3.7-system-tests.html