Refactor rspec config and support files

#206
This commit is contained in:
Artur Beljajev 2016-10-20 18:34:52 +03:00
parent e8dac5e45d
commit ee3ec69e54
9 changed files with 404 additions and 132 deletions

View file

@ -1,29 +1,28 @@
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
require 'capybara/poltergeist'
require 'paper_trail/frameworks/rspec'
PaperTrail.whodunnit = 'autotest'
require "money-rails/test_helpers"
require 'money-rails/test_helpers'
if ENV['ROBOT']
require 'simplecov'
SimpleCov.start 'rails'
end
# 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 with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
require 'support/matchers/alias_attribute'
require 'support/matchers/active_job'
require 'support/capybara'
require 'support/database_cleaner'
require 'support/epp'
require 'support/epp_doc'
require 'support/feature'
require 'support/registrar_helpers'
require 'support/request'
require 'support/autodoc'
require 'support/paper_trail'
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
# create general settings
@ -49,81 +48,44 @@ def create_settings
# speedup and easier to create fabrications
@fixed_registrar =
Registrar.find_by_name('fixed registrar') ||
Fabricate(:registrar, name: 'fixed registrar', code: 'FIXED')
Registrar.find_by_name('fixed registrar') ||
Fabricate(:registrar, name: 'fixed registrar', code: 'FIXED')
end
RSpec.configure do |config|
config.filter_run focus: true
config.run_all_when_everything_filtered = true
config.include ActionView::TestCase::Behavior, type: :presenter
config.include ActiveSupport::Testing::TimeHelpers
# 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
config.before(:suite) do
ActiveRecord::Base.establish_connection :api_log_test
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.strategy = nil
ActiveRecord::Base.establish_connection :test
config.define_derived_metadata(file_path: %r{/spec/presenters/}) do |metadata|
metadata[:type] = :presenter
metadata[:db] = false
end
config.use_transactional_fixtures = false
config.before(:all) do
DatabaseCleaner.clean_with(:truncation)
create_settings
end
config.before(:all, epp: true) do
DatabaseCleaner.strategy = nil
create_settings
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
create_settings
end
config.before(:each, type: :request) do
DatabaseCleaner.strategy = :truncation
create_settings
end
config.before(:each, type: :model) do
create_settings
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.start
end
config.after(:each, type: :model) do
DatabaseCleaner.clean
end
Capybara.javascript_driver = :poltergeist
# 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!
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
end
Autodoc.configuration.path = 'doc/repp'
Autodoc.configuration.suppressed_request_header = ['Host']
Autodoc.configuration.suppressed_response_header = ['ETag', 'X-Request-Id', 'X-Runtime']
Autodoc.configuration.template = File.read('spec/requests/repp_doc_template.md.erb')
end

View file

@ -1,76 +1,77 @@
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause this
# file to always be loaded, without a need to explicitly require it in any files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, make a
# separate helper file that requires this one and then use it only in the specs
# that actually need it.
#
# The `.rspec` file also contains a few flags that are not defaults but that
# users commonly want.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |_config|
RSpec.configure do |config|
# https://github.com/rspec/rspec-rails/issues/1076
config.around :each, type: :view do |example|
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = false
example.run
mocks.verify_partial_doubles = true
end
end
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
# # These two settings work together to allow you to limit a spec run
# # to individual examples or groups you care about by tagging them with
# # `:focus` metadata. When nothing is tagged with `:focus`, all examples
# # get run.
# config.filter_run :focus
# config.run_all_when_everything_filtered = true
#
# # Many RSpec users commonly either run the entire suite or an individual
# # file, and it's useful to allow more verbose output when running an
# # individual spec file.
# if config.files_to_run.one?
# # Use the documentation formatter for detailed output,
# # unless a formatter has already been configured
# # (e.g. via a command-line flag).
# config.default_formatter = 'doc'
# end
#
# # Print the 10 slowest examples and example groups at the
# # end of the spec run, to help surface which specs are running
# # particularly slow.
# config.profile_examples = 10
#
# # Run specs in random order to surface order dependencies. If you find an
# # order dependency and want to debug it, you can fix the order by providing
# # the seed, which is printed after each run.
# # --seed 1234
# config.order = :random
#
# # Seed global randomization in this process using the `--seed` CLI option.
# # Setting this allows you to use `--seed` to deterministically reproduce
# # test failures related to randomization by passing the same `--seed` value
# # as the one that triggered the failure.
# Kernel.srand config.seed
#
# # rspec-expectations config goes here. You can use an alternate
# # assertion/expectation library such as wrong or the stdlib/minitest
# # assertions if you prefer.
# config.expect_with :rspec do |expectations|
# # Enable only the newer, non-monkey-patching expect syntax.
# # For more details, see:
# # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
# expectations.syntax = :expect
# end
#
# # rspec-mocks config goes here. You can use an alternate test double
# # library (such as bogus or mocha) by changing the `mock_with` option here.
# config.mock_with :rspec do |mocks|
# # Enable only the newer, non-monkey-patching expect syntax.
# # For more details, see:
# # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# mocks.syntax = :expect
#
# # Prevents you from mocking or stubbing a method that does not exist on
# # a real object. This is generally recommended.
# mocks.verify_partial_doubles = true
# end
=begin
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run :focus
config.run_all_when_everything_filtered = true
# Limits the available syntax to the non-monkey patched syntax that is recommended.
# For more details, see:
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
config.disable_monkey_patching!
# This setting enables warnings. It's recommended, but in some cases may
# be too noisy due to issues in dependencies.
config.warnings = true
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = 'doc'
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
=end
end

4
spec/support/autodoc.rb Normal file
View file

@ -0,0 +1,4 @@
Autodoc.configuration.path = 'doc/repp'
Autodoc.configuration.suppressed_request_header = ['Host']
Autodoc.configuration.suppressed_response_header = ['ETag', 'X-Request-Id', 'X-Runtime']
Autodoc.configuration.template = File.read('spec/requests/repp_doc_template.md.erb')

8
spec/support/capybara.rb Normal file
View file

@ -0,0 +1,8 @@
require_relative 'macros/capybara'
RSpec.configure do |config|
config.include CapybaraViewMacros, type: :view
config.include CapybaraViewMacros, type: :presenter
end
Capybara.javascript_driver = :poltergeist

View file

@ -0,0 +1,30 @@
RSpec.configure do |config|
db_connection_names = %i(test whois_test api_log_test registrant_write_test)
config.before :suite do
DatabaseCleaner.strategy = :truncation
db_connection_names.each do |connection_name|
ActiveRecord::Base.establish_connection(connection_name)
DatabaseCleaner[:active_record, connection: connection_name].strategy = :truncation
end
end
config.before :example do |example|
if example.metadata[:db] || (%i(model).include?(example.metadata[:type]) && example.metadata[:db].nil?)
db_connection_names.each do |connection_name|
ActiveRecord::Base.establish_connection(connection_name)
DatabaseCleaner[:active_record, connection: connection_name].start
end
end
end
config.after :each do |example|
if example.metadata[:db] || (%i(model).include?(example.metadata[:type]) && example.metadata[:db].nil?)
db_connection_names.each do |connection_name|
ActiveRecord::Base.establish_connection(connection_name)
DatabaseCleaner[:active_record, connection: connection_name].clean
end
end
end
end

View file

@ -0,0 +1,5 @@
module CapybaraViewMacros
def page
Capybara::Node::Simple.new(rendered)
end
end

View file

@ -0,0 +1,252 @@
require "active_job/base"
require "active_job/arguments"
# This matcher is needed because it is absent it rspec-rails 3.3.2
module RSpec
module Rails
module Matchers
# Namespace for various implementations of ActiveJob features
#
# @api private
module ActiveJob
# rubocop: disable Style/ClassLength
# @private
class Base < RSpec::Matchers::BuiltIn::BaseMatcher
def initialize
@args = []
@queue = nil
@at = nil
@block = Proc.new {}
set_expected_number(:exactly, 1)
end
def with(*args, &block)
@args = args
@block = block if block.present?
self
end
def on_queue(queue)
@queue = queue
self
end
def at(date)
@at = date
self
end
def exactly(count)
set_expected_number(:exactly, count)
self
end
def at_least(count)
set_expected_number(:at_least, count)
self
end
def at_most(count)
set_expected_number(:at_most, count)
self
end
def times
self
end
def once
exactly(:once)
end
def twice
exactly(:twice)
end
def thrice
exactly(:thrice)
end
def failure_message
"expected to enqueue #{base_message}"
end
def failure_message_when_negated
"expected not to enqueue #{base_message}"
end
def message_expectation_modifier
case @expectation_type
when :exactly then "exactly"
when :at_most then "at most"
when :at_least then "at least"
end
end
def supports_block_expectations?
true
end
private
def check(jobs)
@matching_jobs_count = jobs.count do |job|
if serialized_attributes.all? { |key, value| value == job[key] }
args = ::ActiveJob::Arguments.deserialize(job[:args])
@block.call(*args)
true
else
false
end
end
case @expectation_type
when :exactly then @expected_number == @matching_jobs_count
when :at_most then @expected_number >= @matching_jobs_count
when :at_least then @expected_number <= @matching_jobs_count
end
end
def base_message
"#{message_expectation_modifier} #{@expected_number} jobs,".tap do |msg|
msg << " with #{@args}," if @args.any?
msg << " on queue #{@queue}," if @queue
msg << " at #{@at}," if @at
msg << " but enqueued #{@matching_jobs_count}"
end
end
def serialized_attributes
{}.tap do |attributes|
attributes[:args] = ::ActiveJob::Arguments.serialize(@args) if @args.any?
attributes[:at] = @at.to_f if @at
attributes[:queue] = @queue if @queue
attributes[:job] = @job if @job
end
end
def set_expected_number(relativity, count)
@expectation_type = relativity
@expected_number = case count
when :once then 1
when :twice then 2
when :thrice then 3
else Integer(count)
end
end
def queue_adapter
::ActiveJob::Base.queue_adapter
end
end
# rubocop: enable Style/ClassLength
# @private
class HaveEnqueuedJob < Base
def initialize(job)
super()
@job = job
end
def matches?(proc)
raise ArgumentError, "have_enqueued_job and enqueue_job only support block expectations" unless Proc === proc
original_enqueued_jobs_count = queue_adapter.enqueued_jobs.count
proc.call
in_block_jobs = queue_adapter.enqueued_jobs.drop(original_enqueued_jobs_count)
check(in_block_jobs)
end
end
# @private
class HaveBeenEnqueued < Base
def matches?(job)
@job = job
check(queue_adapter.enqueued_jobs)
end
end
end
# @api public
# Passes if a job has been enqueued inside block. May chain at_least, at_most or exactly to specify a number of times.
#
# @example
# expect {
# HeavyLiftingJob.perform_later
# }.to have_enqueued_job
#
# # Using alias
# expect {
# HeavyLiftingJob.perform_later
# }.to enqueue_job
#
# expect {
# HelloJob.perform_later
# HeavyLiftingJob.perform_later
# }.to have_enqueued_job(HelloJob).exactly(:once)
#
# expect {
# 3.times { HelloJob.perform_later }
# }.to have_enqueued_job(HelloJob).at_least(2).times
#
# expect {
# HelloJob.perform_later
# }.to have_enqueued_job(HelloJob).at_most(:twice)
#
# expect {
# HelloJob.perform_later
# HeavyLiftingJob.perform_later
# }.to have_enqueued_job(HelloJob).and have_enqueued_job(HeavyLiftingJob)
#
# expect {
# HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42)
# }.to have_enqueued_job.with(42).on_queue("low").at(Date.tomorrow.noon)
def have_enqueued_job(job = nil)
check_active_job_adapter
ActiveJob::HaveEnqueuedJob.new(job)
end
alias_method :enqueue_job, :have_enqueued_job
# @api public
# Passes if a job has been enqueued. May chain at_least, at_most or exactly to specify a number of times.
#
# @example
# before { ActiveJob::Base.queue_adapter.enqueued_jobs.clear }
#
# HeavyLiftingJob.perform_later
# expect(HeavyLiftingJob).to have_been_enqueued
#
# HelloJob.perform_later
# HeavyLiftingJob.perform_later
# expect(HeavyLiftingJob).to have_been_enqueued.exactly(:once)
#
# 3.times { HelloJob.perform_later }
# expect(HelloJob).to have_been_enqueued.at_least(2).times
#
# HelloJob.perform_later
# expect(HelloJob).to enqueue_job(HelloJob).at_most(:twice)
#
# HelloJob.perform_later
# HeavyLiftingJob.perform_later
# expect(HelloJob).to have_been_enqueued
# expect(HeavyLiftingJob).to have_been_enqueued
#
# HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42)
# expect(HelloJob).to have_been_enqueued.with(42).on_queue("low").at(Date.tomorrow.noon)
def have_been_enqueued
check_active_job_adapter
ActiveJob::HaveBeenEnqueued.new
end
private
# @private
def check_active_job_adapter
return if ::ActiveJob::QueueAdapters::TestAdapter === ::ActiveJob::Base.queue_adapter
raise StandardError, "To use ActiveJob matchers set `ActiveJob::Base.queue_adapter = :test`"
end
end
end
end

View file

@ -0,0 +1,9 @@
RSpec::Matchers.define :alias_attribute do |alias_name, original_name|
match do |actual|
actual.class.attribute_alias(alias_name) == original_name.to_s
end
failure_message do |actual|
"expected #{actual.class.name} to alias attribute :#{alias_name} by :#{original_name}"
end
end

View file

@ -0,0 +1 @@
PaperTrail.whodunnit = 'autotest'