A Quick Guide to Rails System Tests in RSpec
Just this week, RSpec 3.7 was released with support for the Rails system tests added in Rails 5.1.
What are System tests?
System tests were added to Rails core in Rails 5.1 as the core team’s preferred way to test client-side interactions using Capybara and a browser driver. This is in addition to the Rails core integration tests, which don’t use Capybara, but which do test against server-side generated DOM elements.
Okay, but I already use Capybara in my RSpec tests, why is this better?
Even if you are already using RSpec feature tests with Capybara, the system tests still offer some benefits:
Configuring the Capybara browser is easier, especially in the default case.
So, should I use System Tests?
How do I use system tests?
In RSpec, you can define a system test using metadata and the
:type keyword, as in
RSpec.describe "add to cart", type: :system do
If you have the
infer_spec_type_from_file_location! configuration turned on, then any spec in the
spec/system directory is a system test.
How do I set up System tests?
System tests use a method called
driven_by, which is part of Rails core, and which manages the Capybara driver configuration.
The argument to
driven_by is the Capybara driver. The default is
:selenium, but you can also use
driven_by method takes three optional keyword arguments,
:using, which specifies the browser for selenium, as in
driven_by :selenium, using: :firefox, and
:screen_size, which specifies the size of the browser window as a two-element array:
driven_by :selenium, screen_size: [640, 480]. There’s also an
:options keyword which is passed to the driver if the driver requires other options.
You can call
driven_by as part of each test in a before block, but in RSpec you can also make that part of the suite-wide configuration. Here’s the setup I’ve been using:
selenium_chrome_headless requires the
selenium-webdriver gem, which is installed by default in Rails 5.1.
I’m pretty sure that using the
selenium_chrome_headless driver also requires having Chromium installed on your system, but honestly, at this point, I’m not 100% sure beyond the fact that I have it installed on my system and system tests work…
You can install other drivers if you want you’d just require them in the same file that has the
driven_by setup and then use
driven_by :poltergeist or
:webkit (if you use
How hard is the transition?
Pretty easy so far, if you are on Rails 5.1… I’ve moved two small projects by just changing their directory and type, and adding the setup above. Since everything is going back to the same Capybara functionality, everything just worked (though Circle CI had to be coaxed, more on that in a second).
If you are doing something unusual with your Capybara driver, you may need to translate the driver configuration, but the existing Capybara driver creators should work.
That said, I’m not sure that you all need to run out and do this to existing projects unless you are having issues. Getting rid of Database Cleaner does seem like a positive step in making tests less confusing.
If you are using Circle CI 2.0
As far as I can tell (the official docs are lacking), the preferred way to do Selenium in Circle CI 2.0 is via a separate Docker image.
In the spirit of “I spent two hours on this so you don’t have to”, here’s the configuration that works for me.
In my CircleCI
config.yml file, the docker setup looks like this:
The RSpec step is as normal, using the syntax that Circle seems to prefer:
That sets up a
SELENIUM_DRIVER_URL environment variable, which we can then use to force a remote driver in that environment. My actual driver setup looks like this:
ENV["SELENIUM_DRIVER_URL"].present?, I use a regular selenium driver, setting the options to mark it as remote, and using the external URL.
It’s still simpler than the Capybara config was before I switched to system testing…
Hope this helps, happy testing!