The difference between system specs and feature specs

by Jason Swett,

If you’re like me, you might have found the difference between RSpec’s “feature specs” and “system specs” to be a little too nuanced to be easily understandable. Here’s my explanation of the difference between the two.

Two levels of Rails tests

For some background, I want to talk about the main two types of Rails tests that I use, and where feature specs, the predecessor to system specs, come intro the picture.

I think of Rails tests as existing on two basic levels.

High-level, course-grained

One level of tests is at a high level. These tests simulate a user visiting pages, filling in forms, clicking links and buttons, etc. Different people use different terms for these tests including “integration test”, “end-to-end test” and “acceptance test”.

Because these types of tests are often expensive to write and run, they tend not to cover every nook and cranny of the application’s behavior.

In RSpec terminology, these types of tests have historically been called feature specs.

Low-level, fine-grained

The other level of tests is at a lower level. There are all kinds of tests you could possibly write with Rails/RSpec (model specs, request specs, view specs, helper specs) but I tend to skip most of those in most scenarios and only write model specs.

From feature spec to system spec

The backstory

When Rails 5.1 came out in April 2017, one of the features it introduced was system tests. Here’s why this was done.

By default Rails ships with Minitest. The inclusion of Minitest provides a way to write model tests and certain other kinds of tests, but it historically hasn’t provided a way to write full-blown end-to-end without doing some extra work yourself, like bringing Capybara and Database Cleaner into the picture. This is the rationale for the addition of system tests, in my understanding.

System specs wrap system tests

According to the RSpec docs, “System specs are RSpec’s wrapper around Rails’ own system tests.” This means that it’s no longer required to explicitly include the Capybara gem, and because system tests are already run inside a transaction, you don’t need Database Cleaner.

The syntactical difference

Here are two examples from the RSpec docs for feature specs and for system specs. Hopefully the syntactical difference is clear enough to spot without explanation.

(Note: it’s been pointed out to me by Reddit user jrochkind that the “feature/scenario” and “describe/it” syntaxes are interchangeable and independent of system specs vs. features specs. Apparently the RSpec team has developed a preference for the “describe/it” version.)

Feature spec example

require "rails_helper"

RSpec.feature "Widget management", :type => :feature do
  scenario "User creates a new widget" do
    visit "/widgets/new"

    fill_in "Name", :with => "My Widget"
    click_button "Create Widget"

    expect(page).to have_text("Widget was successfully created.")
  end
end

System spec example

require "rails_helper"

RSpec.describe "Widget management", :type => :system do
  it "enables me to create widgets" do
    visit "/widgets/new"

    fill_in "Name", :with => "My Widget"
    click_button "Create Widget"

    expect(page).to have_text("Widget was successfully created.")
  end
end

Summary

System specs are a wrapper around Rails’ system tests. The benefits of using system specs instead of feature specs is that you don’t have to explicitly include the Capybara gem, nor do you have to use Database Cleaner. If you prefer the new syntax (as I do) which more closely matches the RSpec syntax for all the other RSpec spec types, then that’s an additional benefit as well.

  •  
  •  
  •  
  • 3

One thought on “The difference between system specs and feature specs

  1. Mohnish Jadwani

    This was quite informative, didn’t know earlier that Rspec Team prefers describe & it block over using scenario for system tests and it was also good to learn that System tests use capybara under the hood , thank you 🙂

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *