
This weekend I was reminded how complex (and in some cases, convoluted) typical test setup is for Rails applications. The steps below were all necessary in my case, but please don’t read into this list any criticisms of these tools’ excellent open source maintainers. In this case, Jonas Nicklas, Hiro Asari (of Travis) & Mike Moore all took time out of the holiday weekend to help unblock me.
These are the things I either knew in advance or discovered in the process of setting up the solitary test you see running in the GIF above:
- For a new Rails project, the “minitest” gem is included even though it’s absent from the generated Gemfile.
- In spite of minitest’s aforementioned inclusion, the addition of the minitest-rails gem is apparently necessary to avoid some tests from raising errors
- The minitest-rails gem must be added to the
:developmentgroup (in addition to:test) of the Gemfile, so that its rake tasks are available from the command line. That means that running an app in development unnecessarily pollutes it with all the class loading and monkey-patching of its test-scope dependencies - Outside of Rails,
Minitest::Specis the test class used fordescribe…itstyle tests. In a Rails app, however, each test is an instance ofActiveSupport::TestCasewith theMinitest::Spec::DSLmerely mixed in (this required an update to minitest-given) - If you don’t add
require "rails/test_unit/railtie"to yourapplication.rb, then the server started byrake testwill actually be initialized in development mode, even if your test helper explicitly setsENV['RAILS_ENV'] = "test"(further blurring the line between production-scope and test-scope dependencies) - Before any tests are defined (e.g. in a
test/test_helper.rbfile), one must firstrequire File.expand_path("../../config/environment", __FILE__)and thenrequire "rails/test_help"or errors will be raised - To run full-stack tests with browser automation, one might add the minitest-rails-capybara gem and then must explicitly
require "minitest/rails/capybara"(and to know that this both installs andrequire’s Capybara itself) - Rack::Test is used by Capybara’s default driver, but it can’t make web requests outside the Rack app (e.g. GitHub OAuth, Harvest integration). In this case, Selenium was added by way of the selenium-webdriver gem and the setting
Capybara.default_driver = :selenium - Without Firefox installed, one might need the
chromedriverbin (viabrew install chromedriver), as well as to override the Capybara driver registration withCapybara.register_driver :selenium { |app| Capybara::Selenium::Driver.new(app, :browser => :chrome) } - minitest-rails-capybara expects its test files to be placed in
test/features - When using Capybara, the
Minitest::SpecDSL changes fromdescribe/ittofeature/scenario, unless you usedescribe 'foo', :capybara do - In order to extract one’s use of Capybara’s API into other modules or classes, they must
extendorincludetheCapybara::DSL - The test database in such an arrangement is, by default, persisted between tests and test runs; wiping and re-seeding the database must be handled elsewise (perhaps one might
Rake::Task["db:setup"].invokein a before hook) - To enable continuous integration (“CI”), one might go to Travis, login, click “Accounts”, click the repo owner, manually sync repos, then click “on” for the repo under test
- Rails tests will require non-default CI settings, necessitating a
.travis.ymlfile withlanguage: ruby, and abefore_scriptentry ofRAILS_ENV=test bundle exec rake db:setup - Any secure environment variables needed by the application must be added with the
travisCLI (acquired bygem install travis), then created withtravis encrypt SOMEVAR="some val" --add env.globaland committed - To run browser tests that execute JavaScript in a headless CI environment, one might use the poltergeist gem, which implements a PhantomJS-based driver
- To juggle the two drivers, an environment variable might flag their use (
Capybara.default_driver = ENV['HEADLESS'] ? :poltergeist : :selenium), with- HEADLESS=truein theenv.globalkey of the.travis.yml - To speed up CI, one should add
cache: bundlerto the.travis.ymlfile [Note: at this time I can’t seem to get caching to work, despite this] - GitHub OAuth applications require a static port in the OAuth callback URL, meaning the test must fix its port to a known value via
Capybara.server_port = ENV['SOME_SET_PORT'] - Capybara makes web requests to
127.0.0.1, and any request tolocalhostwill spawn a separate browser session. As a result, the OAuth success callback won’t be able to be verified unless the application’s callback URL is set explicitly to127.0.0.1 - GitHub’s login page throws uncaught JavaScript errors, so Poltergeist’s Capybara driver must be overridden so as to specify that it should not re-raise any JS errors via
Capybara.register_driver :poltergeist { |app| Capybara::Poltergeist::Driver.new(app, :js_errors => false) }
As for the task of actually writing any tests, I leave that as an exercise to the reader.
I don’t have a solution in mind as to how to make this setup process simpler (and surely it would be, if only I’d acquiesce a bit more to the Omakase test suites), but it certainly feels like the requisite work to get up-and-running with full-stack testing presents too high a barrier of entry, especially given that Ruby’s testing tools are, generally, the good ones. Also, while I typically use RSpec, I don’t believe much, if any, of the work above would have been obviated by it (or Cucumber, for that matter).









