RSpec infrastructure

RSpec, Guard, FactoryBot, Shoulda, VCR, Webmock - standard rspec environment
Icons/chart bar
Used 158 times
Created by
d dpaluy

Usage
This template installs:


It creates spec/support folder and includes those files while loading RSpec
It also adds the following:

  • ActiveSupport::Testing::TimeHelpers
  • .rspec

Add HOSTS to be ignored:  `c.ignore_hosts 'codeclimate.com',  'example.com'`

If you want to disable saving cassettes, add the following vcr: { record: :skip }
For example:

context 'amazing spec', vcr: { record: :skip } do
   ...
end

Run this command in your Rails app directory in the terminal:

rails app:template LOCATION="https://railsbytes.com/script/X8Bsyo"
Template Source

Review the code before running this template on your machine.

gem_group :development, :test do
  gem "factory_bot_rails"
  gem "rspec-rails"
end

gem_group :development do
  gem 'guard-bundler'
  gem 'guard-rspec'

  gem 'terminal-notifier', require: false
  gem 'terminal-notifier-guard', require: false
end

gem_group :test do 
  gem 'capybara'
  gem 'shoulda-matchers'
  gem 'vcr'
  gem 'webmock', require: 'webmock/rspec'
end 

run "bundle install"
rails_command "generate rspec:install"

File.open(Rails.root.join("spec/rails_helper.rb"), "r+") do |file|
  lines = file.each_line.to_a
  config_index = lines.find_index("RSpec.configure do |config|\n")
  lines.insert(config_index, "\nDir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }\n\n")
  file.rewind
  file.write(lines.join)
end

factory_bot_rb = %Q[require 'factory_bot_rails'

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end

FactoryBot.use_parent_strategy = true
]

shoulda_rb = %Q[require 'shoulda/matchers'

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end
]


vcr_rb = <<~EOS
require 'vcr'
require 'webmock/rspec'

WebMock.disable_net_connect!(allow_localhost: true)

VCR.configure do |c|
  c.cassette_library_dir = Rails.root.join('spec', 'cassettes')
  c.ignore_localhost = true
  c.hook_into :webmock
  c.configure_rspec_metadata!
  c.allow_http_connections_when_no_cassette = true
  c.ignore_hosts 'codeclimate.com'

  c.before_record do |interaction|
    interaction.request.headers['Authorization'] = '[FILTERED]'
  end
end

RSpec.configure do |config|
  # Add VCR to all tests
  config.around(:each) do |example|
    options = example.metadata[:vcr] || {}
    options[:allow_playback_repeats] = true
    options[:match_requests_on] = %i[path]

    if options[:record] == :skip
      WebMock.allow_net_connect!
      VCR.turned_off(ignore_cassettes: true, &example)
      WebMock.disable_net_connect!(allow_localhost: false)
    else
      custom_name = example.metadata.dig(:vcr, :cassette_name)
      generated_name = example.metadata[:full_description].split(/\\s+/, 2).join('/').underscore.tr('.', '/').gsub(/[^\\w\\/]+/, '_').gsub(/\\/$/, '')
      name = custom_name || generated_name
      
      VCR.use_cassette(name, options, &example)
    end
  end
end
EOS

time_helper_rb = %{RSpec.configure do |config|
  config.include ActiveSupport::Testing::TimeHelpers
end
}

capybara_rb = %{require 'capybara/rspec'}

run "mkdir spec/support"

File.open(Rails.root.join("spec/support/time_helper.rb"), "w") do |file|
 file.write(time_helper_rb)
end

File.open(Rails.root.join("spec/support/factory_bot.rb"), "w") do |file|
 file.write(factory_bot_rb)
end

File.open(Rails.root.join("spec/support/shoulda.rb"), "w") do |file|
 file.write(shoulda_rb)
end

File.open(Rails.root.join("spec/support/vcr.rb"), "w") do |file|
 file.write(vcr_rb)
end

File.open(Rails.root.join("spec/support/capybara.rb"), "w") do |file|
 file.write(capybara_rb)
end

dot_rspec = %{--require rails_helper
--color
--format documentation
--tag ~slow
}

File.open(Rails.root.join(".rspec"), "w") do |file|
 file.write(dot_rspec)
end

run "bundle exec guard init"
run "bundle binstub guard"

run "rm -rf test" if yes?("Do you want to remove the /test directory?")

if yes?("Would you like to generate factories for your existing models?")
  Dir.glob(Rails.root.join("app/models/*.rb")).each { |file| require file }
  models = ApplicationRecord.send(:subclasses).map(&:name)
  
  models.each do |model|
    run("rails generate factory_bot:model #{model} #{model.constantize.columns.map { |column| "#{column.name}:#{column.type}" }.join(" ")}")
  end
end
Comments
BB
Thanks for this! 

There's an issue though, the `vcr.rb` file is outputting the regex incorrectly because of the escaping.

# actual:
example.metadata[:full_description].split(/ +/, 2).join('/').underscore.tr('.', '/').gsub(/[^w/]+/, '_').gsub(//$/, '')

# expected:
example.metadata[:full_description].split(/\s+/, 2).join('/').underscore.tr('.', '/').gsub(/[^\w\/]+/, '_').gsub(/\/$/, '')

The template needs to escape the slashes:

# fix:
example.metadata[:full_description].split(/\\s+/, 2).join('/').underscore.tr('.', '/').gsub(/[^\\w\\/]+/, '_').gsub(/\\/$/, '')
dpaluy
Fixed. Thanks!
I also updated the `VCR` skip option
dpaluy
Note: `options[:match_requests_on] = %i[path]` ignores HOST
dpaluy
Note: https://github.com/sds/mock_redis/issues/253

Should be removed:

```
 config.before(:each) do
    mock_redis = MockRedis.new
    allow(RedisClient).to receive(:current).and_return(mock_redis)
  end
```