How to create a gemified plugin with Rails 3.2, Rspec, Capybara, Spork, and Guard

It can be tricky to set up a new gemified Rails plugin (with the dummy application) to use Rspec and friends rather than the default test-unit. Here’s how I did it.

We will use Rails 3.2 to generate a new plugin (not engine) and set everything up ready to do BDD using Rspec, Capybara, Spork, and Guard.  We also use a dummy application included in our library to do integration tests on a real Rails app. 

Lets start off by using Rails to generate a new plugin. Because we want to use Rspec instead of the default test-unit, we will skip it and specify where Rails should generate the dummy application.

$ rails plugin new foobar --skip-test-unit --dummy-path=spec/dummy

Now we can change directories into our new plugin, edit the foobar.gemspec file and add four libraries we will be using to develop this gem.

$ cd foobar
$ vim foobar.gemspec
$:.push File.expand_path("../lib", __FILE__)

# Maintain your gem's version:
require "foobar/version"

# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
  .
  .
  .
  s.add_development_dependency "rspec-rails"
  s.add_development_dependency "capybara"
  s.add_development_dependency "guard-rspec"
  s.add_development_dependency "guard-spork"
end

We want to run bundle again to install these libraries.

$ bundle

Now if we were building a Rails app, we would just run rails generate rspec:install, but that won’t work here because the spec directory is located at the root of the plugin structure. This will likely be fixed in the future, but for now, lets trick it by changing into the directory of the dummy app and sym-linking back to the spec directory.  We can then run the rspec install command right there in the root of the dummy app.

$ cd spec/dummy
$ ln -s ../../spec
$ rails generate rspec:install

The rspec install  command creates a new spec/spec_helper.rb file.

Now lets change back to the root directory of the plugin and set up Spork. This will add some code to the same spec/spec_helper.rb file.

$ cd -
$ spork --bootstrap

We should see a message from Spork saying that spec/spec_helper.rb has been bootstrapped and we should now edit the file. We are going to move all of the code generated by rails generate rspec:install into the Spork.prefork block. The resulting spec/spec_helper.rb file should look like this (with all the comments removed).

require 'rubygems'
require 'spork'

Spork.prefork do
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'
  require 'rspec/autorun'

  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

  RSpec.configure do |config|
    config.fixture_path = "#{::Rails.root}/spec/fixtures"
    config.use_transactional_fixtures = true
    config.infer_base_class_for_anonymous_controllers = false
  end
end

Spork.each_run do
  # This code will be run each time you run your specs.
end

We need to make one more change in this file to make Rspec work with the dummy app rather than a normal rails app.

Change this line:

require File.expand_path("../../config/environment", __FILE__)

To this:

require File.expand_path("../dummy/config/environment", __FILE__)

Save the file and we are done with Rspec and Spork setup.

Now lets create a Guardfile so that Guard knows what to do.

$ bundle exec guard init spork
$ bundle exec guard init rspec

After running those two commands you will have a Guard file that will work with this setup. Check out the Guardfile, it is important that spork block come before the rspec block.

vim Guardfile

To make Guard use Spork each time it runs Rspec, lets change this line:

guard 'rspec', :version => 2 do

To this:

guard 'rspec', :cli => "--color --drb", :version => 2 do

This will also produce a nicer colored output.

Next edit the rails ‘watch’ lines so that instead of referring to just `app` we are referring to `spec/dummy/app`.  Like this:

guard 'rspec', :cli => "--color --drb", :version => 2 do
  .
  .
  .
  watch(%r{^spec/dummy/app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^spec/dummy/app/(.*)(\.erb|\.haml)$})                 { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
  watch(%r{^spec/dummy/app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('spec/dummy/config/routes.rb')                           { "spec/routing" }
  watch('spec/dummy/app/controllers/application_controller.rb')  { "spec/controllers" }
  # Capybara request specs
  watch(%r{^spec/dummy/app/views/(.+)/.*\.(erb|haml)$})          { |m| "spec/requests/#{m[1]}_spec.rb" }
end

And we are done. Now we can run:

bundle exec guard

And our specs are run each time we make a change.

Setting it up this way allows us to do real BDD with an inline dummy Ruby on Rails app including integration tests with Capybara.

Let me know if you have any suggestions about this setup or problems getting it to work.

Cheers.

2 notes

  1. namick posted this