Skip to content

Instantly share code, notes, and snippets.

@matismasters
Last active December 18, 2015 10:09
Show Gist options
  • Save matismasters/5766418 to your computer and use it in GitHub Desktop.
Save matismasters/5766418 to your computer and use it in GitHub Desktop.
Generate rake tasks dynamically based on Rails + Engines folder structure for running tests using RSpec + Factory Girl

Rake spec tasks for engines

Dependencies:

  • rails 3.2+
  • rspec-rails
  • factory-girl

Scenario:

  • You have a Rails application with several engines.
  • You have all the engines in the same directory within the app.
  • You have properly configured your spec_helper to use rspec-rails and factory-girl

Motivation:

  • You don't want to use/setup a dummy app to test each engine
  • You want to be able to run the specs for the engines separatedly but in the same env

Solution:

Dynamically based on the folder/files structure add a Rake tasks to:

  • Run all the specs of the host app, and all the engines

    rake spec:all

  • Run all the specs of a specific engine

    rake spec:engine_name

  • Run all the specs of a certain type from an engine

    rake spec:engine_name:spec_type

Example:

For an engine located in /engines/engine_name/special_category
The rake tasks should look like:

  • To run all the specs

    rake spec:engine_name:special_category

  • To run only the models specs

    rake spec:engine_name:special_category:models

  • To run only the controllers specs

    rake spec:engine_name:special_category:models

  • To run any other spec type specs

    rake spec:engine_name:special-category:any_other_folder_name

Notes:

  • The specs should be in a folder named spec/ in the engine root folder
  • The factories should be in the spec directory, inside a folder named factories/
  • Use rake -T to check all the rake tasks
  • spec_helper should be placed at #{Rails.root}/spec/spec_helper.rb
  • In order for the rake task to be generated, the spec folder should contain files ending with _spec

Tips: To configure RSpec + Factory Girl + Capybara here is a blogpost from @brianjlandau http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl

# Rake spec tasks for engines
# ===========================
#
# Dependencies:
# - rails 3.2+
# - rspec-rails
# - factory-girl
#
# Scenario:
# - You have a Rails application with several engines.
# - You have all the engines in the same directory within the app.
# - You have properly configured your spec_helper to use rspec-rails and factory-girl
#
# Motivation:
# - You don't want to use/setup a dummy app to test each engine
# - You want to be able to run the specs for the engines separatedly but in the same env
#
# Solution:
# Dynamically based on the folder/files structure add a Rake task to:
# - Run all the specs of the host app, and all the engines
# 'rake spec:all'
# - Run all the specs of a specific engine
# 'rake spec:engine_name
# - Run all the specs of a certain type from an engine
# 'rake spec:engine_name:spec_type
#
# Example:
# For an engine located in '/engines/engine_name/special_category'
# The rake tasks should look like:
# - To run all the specs
# rake spec:engine_name:special_category
# - To run only the models specs
# rake spec:engine_name:special_category:models
# - To run only the controllers specs
# rake spec:engine_name:special_category:models
# - To run any other spec type specs
# rake spec:engine_name:special-category:any_other_folder_name
#
# Notes:
# * The specs should be in a folder named 'spec/' in the engine root folder
# * The factories should be in the 'spec/' directory, inside a folder named 'factories/'
# * Use 'rake -T' to check all the rake tasks
# * spec_helper should be placed at "#{Rails.root}/spec/spec_helper.rb"
# * In order for the rake task to be generated, the spec folder should contain files
# ending with '_spec'
#
# Tips:
# To configure RSpec + Factory Girl + Capybara here is a blogpost from @BRIAN LANDAU
# http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
spec_prereq = Rails.configuration.generators.options[:rails][:orm] == :active_record ? "test:prepare" : :noop
task :noop do; end
def absolute_rails_path(*segments)
# Rails root path
root = Rails.application.root
root.join(*segments).to_s
end
def absolute_engine_path(*segments)
absolute_rails_path(*(["engines"] + segments))
end
def absolute_engine_factories_path(engine_path)
absolute_engine_path(engine_path,'spec', "factories", "**", "*.rb")
end
namespace :spec do
# One task to run them all
desc "Run specs from the host app and the engines"
RSpec::Core::RakeTask.new(:all => spec_prereq) do |t|
t.rspec_opts = "-r ./spec/spec_helper.rb"
t.pattern = [
absolute_rails_path("spec", "**", "*_spec.rb"),
absolute_rails_path("spec", "factories", "**", "*_spec.rb"),
absolute_engine_path("**", "*_spec.rb"),
absolute_engine_path("**","factories", "**", "*.rb")
]
end
def engine_types(engine_path)
# Path to match all the available spec types from within a specific engine
# spec types => controllers, models, helpers, etc
engine_type_dirs = absolute_engine_path(engine_path, '**', 'spec', '**', '*_spec.rb')
# Get all the unique engine spec types paths
dirs = Dir[engine_type_dirs].map { |f| f.sub(/.*?\/spec\/(\w+)\/.*/, '\\1') }.uniq
# Creating a hash with a task-like name as key and
# its corresponding path as value
Hash[dirs.map { |d| [d.split('/').last, d] }]
end
def engines
# Path to match all the engine directories with a 'spec/' directory
# that contains files ending with _spec
engine_dirs = absolute_engine_path('**', 'spec', '**', '*_spec.rb')
# Getting all the different engine paths
dirs = Dir[engine_dirs].map { |f| f.sub(/.*?\/engines\/(.*?)\/spec.*/, '\\1') }.uniq
# Creating a hash with a task-like name as key and
# its corresponding path as value
Hash[dirs.map { |d| [d.gsub('/',':'), d] }]
end
# For each engine we will create different rake tasks
engines.each do |engine, engine_path|
# A task to run all the engine specs at once
# sample call for an engine wich path is '/vendor/special/api'
# should be 'rake spec:vendor:special:api'
desc "Run the specs for the engine #{engine}"
RSpec::Core::RakeTask.new(engine => spec_prereq) do |t|
t.rspec_opts = "-r ./spec/spec_helper.rb"
# If there are factories, they will be picked up too
t.pattern = [
absolute_engine_factories_path(engine_path),
absolute_engine_path(engine_path, "**", "*_spec.rb")
]
end
# For each engine we also create a namespace
namespace engine do
# For each type of specs from within the engine, we create another task
# to run only those
engine_types(engine_path).each do |type, type_path|
desc "Run the #{type} specs from the #{engine} engine"
RSpec::Core::RakeTask.new(type => spec_prereq) do |t|
t.rspec_opts = "-r ./spec/spec_helper.rb"
# If there are factories, they will be picked up too
t.pattern = [
absolute_engine_factories_path(engine_path),
absolute_engine_path(engine_path,"spec", type_path, "**", "*_spec.rb")
]
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment