Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jonathanstiansen/76479ab03d3711592b1f9765fc70b453 to your computer and use it in GitHub Desktop.
Save jonathanstiansen/76479ab03d3711592b1f9765fc70b453 to your computer and use it in GitHub Desktop.
Rails Spec setup checklist, helper and support files

Rails RSpec Checklist

  • Ensure turbolinks is disabled for good measure

    • comment out gem
    • remove from javascript asset pipeline
    • remove from application layout
  • Add the following gems to Gemfile in a development, test group

    • hirb
    • rspec-rails
    • guard
    • guard-rspec
    • factory_bot_rails
    • database_cleaner
    • capybara (Included with Rails 6)
    • launchy
    • selenium-webdriver (Included with Rails 6)
  • Run the necessary initializers with bundle, guard, and rspec

    • $ bundle exec guard init
    • $ rails g rspec:install
  • In the Guardfile comment out the following lines

    • watch(rspec.spec_helper) { rspec.spec_dir }
      • Ignore when spec_helper is saved
    • watch(rspec.spec_support) { rspec.spec_dir }
      • Ignore when a support file is saved
  • Prepare test database with $ rake db:test:prepare

  • Ensure you have a spec/ folder in root directory

  • Ensure you have a spec_helper.rb and rails_helper.rb in the spec/ folder

  • Create a spec/factories/ folder

    • Add any model factories in model_factory.rb files
    • Be sure to use sequences for factories that will have multiple instances
    • Be sure to include associations
  • Create a spec/support/ folder

  • Create a spec/support/macros folder

  • See rails_helper.rb for relevant changes to rails_helper.rb

    • Under the line that says
      • # Add additional requires below this line. Rails is not loaded until this point!
      • Require capybara
      • Require the spec/support folder recursively in rails_helper.rb
    • Inside the config block
      • Include FactoryGirl methods into RSpec
      • Disable fixtures
  • Any helpers for Capybara should go in a appropriately named spec/support/marcos file and be name spaced under a module called Macros

    • See the example here in global.rb
  • A spec/support/controller_helper.rb and spec/support/view_helper.rb can be used for shared controller and view helper methods

    • See controller_helper.rb and view_helper.rb here
  • Capybara macros and other helper modules from spec/support should be included like

  • FactoryGirl in the rails_helper when they are to be available globally

  • For the view_helper.rb module it should be used as shown in the index_spec.rb https://gist.github.com/BideoWego/973df3cf566b99513da8 where the view object extends the module

    • This includes the module methods on the view object in the current spec and allows it to access the methods as expected in normal rails application flow
  • Create the following folders

    • spec/controllers/
    • spec/features/
    • spec/models/
    • spec/views/
  • Any spec that requires javascript should use the format shown in secret_spec.rb

    • This will use the selenium-webdriver with capybara to launch FireFox and perform the spec live
    • NOTE the use of page.driver.browser.switch_to.alert.accept to accept the alert box
  • As a final note, be aware than if you ever run ALL tests with the rspec command, FactoryGirl will increment sequences from the first test all the way to the last test.

    • This means it is possible for the number value to effect tests differently based on where they fall into the overall test suite
    • For example: if there is a validation on length of a string and the test is run after many many tests, the incremented value might be 1000 instead of 10
    • This could cause unexpected validation errors because the extra few chars pushed the otherwise valid string over the maximum
    • JUST BE AWARE OF THIS!!!!
  • While testing use $ tail -f log/test.log to view the server output from tests

Done!

Happy testing!

# spec/support/controller_helper.rb
module ControllerHelper
def login(user)
session[:user_id] = user.id
end
def logout
session.delete(:user_id)
end
def current_user
User.find(session[:user_id]) if User.exists?(session[:user_id]) && session[:user_id]
end
def signed_in_user?
!!current_user
end
end
# spec/support/database_cleaner.rb
# From blog post
# http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
# spec/support/macros/global.rb
module Macros
module Global
def submit_form
find('input[name="commit"]').click
end
end
end
# spec/views/index_spec.rb
require 'rails_helper'
describe 'secrets/index.html.erb' do
let(:user){create(:user)}
let(:users){[user, create(:user)]}
let(:secrets){[create(:secret, :author => user), create(:secret)]}
before do
view.extend(ViewHelper)
assign(:users, users)
assign(:secrets, secrets)
end
context 'the user is logged in' do
it 'shows the author of all secrets' do
login(user)
render
expect(rendered).to_not have_content(hidden_text)
end
end
context 'the user is logged out' do
it 'does not show any author of any secrets' do
render
expect(rendered).to have_content(hidden_text)
end
end
end
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
# ------------------------------------
# My Requires
# ------------------------------------
require 'capybara/rails'
require 'factory_girl_rails'
require 'database_cleaner'
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Checks for pending migration and applies them before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# ------------------------------------
# My Config
# ------------------------------------
config.include FactoryGirl::Syntax::Methods
config.include Macros::Post
config.include Macros::Session
config.include Macros::Search
config.include Macros::User
config.include ControllerHelper
config.after(:all) do
if Rails.env.test?
FileUtils.rm_rf(Dir["#{Rails.root}/public/system/test"])
end
end
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name")
end
# spec/features/secret_spec.rb
require 'rails_helper'
feature 'Secrets' do
let!(:user){create(:user)}
let!(:secrets){create_list(:secret, 5, :author => user)}
let!(:user_one){create(:user, :name => 'User One', :email => 'user@one.com')}
let!(:user_two){create(:user, :name => 'User Two', :email => 'user@two.com')}
let!(:secrets_user_one){create_list(:secret, 5, :author => user_one)}
let!(:secrets_user_two){create_list(:secret, 5, :author => user_two)}
# ----------------------------------------
# Delete Secret
# ----------------------------------------
feature 'deletion' do
context 'when the user is logged in' do
before do
visit new_session_path
sign_in(user)
visit secrets_path
end
after do
visit logout_path
end
scenario 'is enabled on current user secrets', :js => true do
link = find('a', :text => 'Destroy', :match => :first)
link.click
page.driver.browser.switch_to.alert.accept
expect(page).to have_content(success_text_for('Secret', 'destroy'))
end
scenario 'redirects to secrets listing upon deletion', :js => true do
link = find('a', :text => 'Destroy', :match => :first)
link.click
page.driver.browser.switch_to.alert.accept
expect(page).to have_content('Listing secrets')
end
end
end
end
# spec/support/view_helper.rb
module ViewHelper
include ControllerHelper
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment