How to add RSpec to an existing Rails engine Aug 13 2018

Update 2018-08-27

I ran into a problem with Rails, it couldn't find a database.yml, this was not because of a Rails missconfiguration but because of the binstub for rails had:

1
APP_PATH = File.expand_path('../../test/dummy/config/application', __FILE__)

And well we change it to use rspec, so it should be:

1
APP_PATH = File.expand_path('../../spec/dummy/config/application', __FILE__)


Adding RSpec to an existing Rails engine

If we already have a Rails engine and we wish to add RSpec to it, how would we go about it? The solution is not as straightforward as we might think, there are a few details always missing from tutorials or the guides, so I'll try to share what I found and hopefully help someone that has the same issue.

Because we are testing an engine, we will need a testing environment that includes our engine so we can test it. When we build a new engine, Rails generates a dummy application that will serve as the environment to mount the engine and run the tests. And there is where we'll start.

Create a temporary engine to build the dummy app

Generate a new engine with the same name as your engine, skip UnitTest but build the dummy app, this dummy app is the one we will move to the current engine and use as our test environment.

1
rails plugin new same_engine_name --full --dummy-path=spec/dummy -T

The T flag tells rails to skip the UnitTest. Then copy the spec/ directory to your current engine's root path:

1
cp -r spec PATH_TO/OUR_ENGINE/

Add the dependencies to the gemspec

Engine dependencies are added to the our_engine.gemspec file:

1
s.add_development_dependency 'rspec-rails'

If we were to use capybara and factory bot, add them but let's just keep it simple for now.

Tell the engine where to find the test files

inside the gemspec file:

1
s.test_files = Dir["spec/**/*"]

If you are replacing Unit/MiniTest with RSpec you can remove all that configuration, unless for some reason you wish to have the two frameworks.

Let's say we will remove the old configuration:

1
2
 # we can delete this line if we are no longer going to use it
  s.test_files = Dir["test/**/*"]

Update the Rakefile to run the RSpec tests

Update our Rakefile in the engine to be aware of our RSpec tests and let's set our RSpec tests as the default task to run when we just run rake without arguments.

Rspec task configuration

1
2
3
4
5
6
7
8
require 'rspec/core'
require 'rspec/core/rake_task'

desc "Run all specs in spec directory (excluding plugin specs)"
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')

task :default => :spec

Again removed the code for the previous testing framework if we are replacing it with RSpec.

1
2
3
4
5
6
7
8
9
10
11
# UnitTest configuration - remove if no longer in use
require 'rake/testtask'

Rake::TestTask.new(:test) do |t|
  t.libs << 'lib'
  t.libs << 'test'
  t.pattern = 'test/**/*_test.rb'
  t.verbose = false
end

task :default => :test

Create rails_helper.rb and spec_helper.rb to load tests and libraries

Inside the spec directory, create the file spec_helper.rb to set up all the RSpec configurations we will use. The following is a basic configuration example add the configurations you would normally use.

1
2
3
4
5
6
7
8
9
#spec_helper.rb
require 'rspec/autorun'
Rails.backtrace_cleaner.remove_silencers!
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }

RSpec.configure do |config|
 config.mock_with :rspec
 config.order = "random"
end

Now let's create rails_helper.rb, this file will require our spec_helper.rb and contain all the configuration necessary for rails to know where to load our dummy app and configure RSpec rails preferences.

1
2
3
4
5
6
#rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../dummy/config/environment.rb', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'

Add configuration for the Engine generators

When we generate a new model, resource, etc. we would like Rails to generate the RSpec test files automatically.

1
2
3
4
5
6
7
8
9
module YourEngineName
  class Engine < ::Rails::Engine
    config.generators do |g|
      g.test_framework :rspec
      g.assets false
      g.helper false
    end
  end
end

Now we have our configuration done, we can create tests inside our spec directory and run them from the root of our engine, for example, if we have a User model and we would like to test it, we could create a file inside our spec directory:

1
our_engine/spec/models/users_spec.rb

Write a general test:

1
2
3
4
5
6
7
8
require 'spec_helper'

RSpec.describe User, type: :model do
  it "Is a valid user" do
  user = User.create(name: "Don")
  expect(user.valid?).to eq(true)
  end
end

We can now run rake from the root of our engine and start exploring TDD.

Hope this helps, let me know what you think. If I missed something, let me know and I'll add it.


** If you want to check what else I'm currently doing be sure to follow me on twitter @rderik or subscribe to the newsletter. If you want to send me a direct message you can send it to derik@rderik.com.