Skip to content

Fix action mailer preview path setup. #1327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 18, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Bug Fixes:

* Fix auto-including of generic `Helper` object for view specs sitting in the
`app/views` root (David Daniell, #1289)
* Remove pre-loading of ActionMailer in the Railtie (Aaron Kromer, #1327)

### 3.2.1 / 2015-02-23
[Full Changelog](http://github.com/rspec/rspec-rails/compare/v3.2.0...v3.2.1)
Expand Down
32 changes: 32 additions & 0 deletions example_app_generator/generate_action_mailer_specs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require 'active_support'
require 'active_support/core_ext/module'

# We need to copy this method from Thor for older Rails versions
def comment_lines(path, flag, *args)
flag = flag.respond_to?(:source) ? flag.source : flag
gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args)
end

using_source_path(File.expand_path('..', __FILE__)) do
# Comment out the default mailer stuff
comment_lines 'config/environments/development.rb', /action_mailer/
comment_lines 'config/environments/test.rb', /action_mailer/

initializer 'action_mailer.rb', <<-CODE
if ENV['DEFAULT_URL']
Rails.application.configure do
config.action_mailer.default_url_options = { :host => ENV['DEFAULT_URL'] }
end
end
CODE

copy_file 'spec/support/default_preview_path'
chmod 'spec/support/default_preview_path', 0755
gsub_file 'spec/support/default_preview_path',
/ExampleApp/,
Rails.application.class.parent.to_s
if skip_active_record?
comment_lines 'spec/support/default_preview_path', /active_record/
end
copy_file 'spec/verify_mailer_preview_path_spec.rb'
end
54 changes: 24 additions & 30 deletions example_app_generator/generate_stuff.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
require 'rspec/rails/feature_check'

module ExampleAppHooks
DEFAULT_SOURCE_PATH = File.expand_path('..', __FILE__)
DEFAULT_SOURCE_PATH = File.expand_path('..', __FILE__)

module ExampleAppHooks
module AR
def source_paths
[DEFAULT_SOURCE_PATH]
@__source_paths__ ||= [DEFAULT_SOURCE_PATH]
end

def setup_tasks
Expand All @@ -19,11 +19,15 @@ def final_tasks
run('bin/rake db:migrate RAILS_ENV=test')
end
end

def skip_active_record?
false
end
end

module NoAR
def source_paths
[File.join(DEFAULT_SOURCE_PATH, 'no_active_record')]
@__source_paths__ ||= [File.join(DEFAULT_SOURCE_PATH, 'no_active_record')]
end

def setup_tasks
Expand All @@ -40,6 +44,10 @@ def setup_tasks
def final_tasks
copy_file 'spec/verify_no_active_record_spec.rb'
end

def skip_active_record?
true
end
end

def self.environment_hooks
Expand All @@ -56,6 +64,14 @@ def generate(*)
$?.success? || abort
end

def using_source_path(path)
source_paths.unshift path
yield
ensure
# Remove our path munging
source_paths.shift
end

# Generally polluting `main` is bad as it monkey patches all objects. In this
# context, `self` is an _instance_ of a `Rails::Generators::AppGenerator`. So
# this won't pollute anything.
Expand All @@ -68,32 +84,7 @@ def generate(*)
generate('controller welcome index') # singular
generate('integration_test widgets')
generate('mailer Notifications signup')
if ::RSpec::Rails::FeatureCheck.has_action_mailer_preview?
create_file "spec/support/default_preview_path.rb", <<-EOS.strip_heredoc
ENV['RAILS_ENV'] = 'development'

CONFIG_PATH = File.expand_path('../../../config', __FILE__)
APP_PATH = File.expand_path(File.join(CONFIG_PATH, 'application'))
# Default rails setup
require File.join(CONFIG_PATH, 'boot')
require 'rails/all'
require File.join(CONFIG_PATH, 'environment')

puts Rails.application.config.action_mailer.preview_path
EOS
create_file "spec/verify_mailer_preview_path_spec.rb", <<-EOS.strip_heredoc
RSpec.describe 'Verifying the railtie sets the preview path' do
it 'is set to the rspec path' do
exec_script = File.expand_path(
File.join(__FILE__, '../support/default_preview_path.rb')
)
expect(%x(ruby #\{exec_script\}).chomp).to eq(
"#\{::Rails.root\}/spec/mailers/previews"
)
end
end
EOS
end

generate('model thing name:string')
generate('helper things')
generate('scaffold widget name:string category:string instock:boolean foo_id:integer bar_id:integer --force')
Expand All @@ -113,6 +104,9 @@ def generate(*)
"This is a template for a custom action.",
:force => true

# Use the absolute path so we can load it without active record too
apply File.join(DEFAULT_SOURCE_PATH, 'generate_action_mailer_specs.rb')

gsub_file 'spec/spec_helper.rb', /^=(begin|end)/, ''

# Warnings are too noisy in the sample apps
Expand Down
60 changes: 60 additions & 0 deletions example_app_generator/spec/support/default_preview_path
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env ruby
# Transparent helper to simply document code sections
def require_file_stub(name)
yield
end

ENV['RAILS_ENV'] ||= 'development'

require_file_stub 'config/environment' do
# Load the Rails application.
require_file_stub 'config/application' do
require_file_stub 'config/boot' do
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
end

# Pick the frameworks you want:
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie" unless ENV['NO_ACTION_MAILER']
require "action_view/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
if Rails::VERSION::STRING.to_f < 3.1
Bundler.require(:default, Rails.env)
else
Bundler.require(*Rails.groups)
end

module ExampleApp
class Application < Rails::Application
config.eager_load = false

# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false unless ENV['NO_ACTION_MAILER']

if ENV['CUSTOM_PREVIEW_PATH']
config.action_mailer.preview_path = ENV['CUSTOM_PREVIEW_PATH']
end
if ENV['SHOW_PREVIEWS']
config.action_mailer.show_previews = (ENV['SHOW_PREVIEWS'] == 'true')
end
end
end

I18n.enforce_available_locales = true if I18n.respond_to?(:enforce_available_locales)
end

# Initialize the Rails application.
Rails.application.initialize!
end

exit if ENV['NO_ACTION_MAILER']
if ENV['DEFAULT_URL']
puts ActionMailer::Base.default_url_options[:host]
elsif defined?(::ActionMailer::Preview)
puts Rails.application.config.action_mailer.preview_path
end
183 changes: 183 additions & 0 deletions example_app_generator/spec/verify_mailer_preview_path_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
require 'rails_helper'
require 'rspec/rails/feature_check'

RSpec.describe 'Action Mailer railtie hook' do
CaptureExec = Struct.new(:io, :exit_status) do
def ==(str)
io == str
end
end

def capture_exec(*ops)
io = if RUBY_VERSION.to_f < 1.9
IO.popen(ops.join(' '))
else
ops << { :err => [:child, :out] }
IO.popen(ops)
end
# Necessary to ignore warnings from Rails code base
out = io.readlines.reject { |line|
line =~ /warning: circular argument reference/
}.join.chomp
CaptureExec.new(out, $?.exitstatus)
end

def have_no_preview
have_attributes(:io => be_blank, :exit_status => 0)
end

let(:exec_script) {
File.expand_path(File.join(__FILE__, '../support/default_preview_path'))
}

if RSpec::Rails::FeatureCheck.has_action_mailer_show_preview?
context 'in the development environment' do
let(:custom_env) { { 'RAILS_ENV' => rails_env } }
let(:rails_env) { 'development' }

it 'sets the preview path to the default rspec path' do
expect(capture_exec(custom_env, exec_script)).to eq(
"#{::Rails.root}/spec/mailers/previews"
)
end

it 'respects the setting from `show_previews`' do
expect(
capture_exec(
custom_env.merge('SHOW_PREVIEWS' => 'false'),
exec_script
)
).to have_no_preview
end

it 'respects a custom `preview_path`' do
expect(
capture_exec(
custom_env.merge('CUSTOM_PREVIEW_PATH' => '/custom/path'),
exec_script
)
).to eq('/custom/path')
end

it 'allows initializers to set options' do
expect(
capture_exec(
custom_env.merge('DEFAULT_URL' => 'test-host'),
exec_script
)
).to eq('test-host')
end

it 'handles action mailer not being available' do
expect(
capture_exec(
custom_env.merge('NO_ACTION_MAILER' => 'true'),
exec_script
)
).to have_no_preview
end
end

context 'in a non-development environment' do
let(:custom_env) { { 'RAILS_ENV' => rails_env } }
let(:rails_env) { 'test' }

it 'does not set the preview path by default' do
expect(capture_exec(custom_env, exec_script)).to have_no_preview
end

it 'respects the setting from `show_previews`' do
expect(
capture_exec(custom_env.merge('SHOW_PREVIEWS' => 'true'), exec_script)
).to eq("#{::Rails.root}/spec/mailers/previews")
end

it 'allows initializers to set options' do
expect(
capture_exec(
custom_env.merge('DEFAULT_URL' => 'test-host'),
exec_script
)
).to eq('test-host')
end

it 'handles action mailer not being available' do
expect(
capture_exec(
custom_env.merge('NO_ACTION_MAILER' => 'true'),
exec_script
)
).to have_no_preview
end
end
elsif RSpec::Rails::FeatureCheck.has_action_mailer_preview?
context 'in the development environment', 'without `show_previews`' do
let(:custom_env) { { 'RAILS_ENV' => rails_env } }
let(:rails_env) { 'development' }

it 'sets the preview path to the default rspec path' do
expect(capture_exec(custom_env, exec_script)).to eq(
"#{::Rails.root}/spec/mailers/previews"
)
end

it 'respects a custom `preview_path`' do
expect(
capture_exec(
custom_env.merge('CUSTOM_PREVIEW_PATH' => '/custom/path'),
exec_script
)
).to eq('/custom/path')
end

it 'allows initializers to set options' do
expect(
capture_exec(
custom_env.merge('DEFAULT_URL' => 'test-host'),
exec_script
)
).to eq('test-host')
end

it 'handles action mailer not being available' do
expect(
capture_exec(
custom_env.merge('NO_ACTION_MAILER' => 'true'),
exec_script
)
).to have_no_preview
end
end

context 'in a non-development environment', 'without `show_previews`' do
let(:custom_env) { { 'RAILS_ENV' => rails_env } }
let(:rails_env) { 'test' }

it 'does not set the preview path by default' do
expect(capture_exec(custom_env, exec_script)).to have_no_preview
end

it 'respects a custom `preview_path`' do
expect(
capture_exec(
custom_env.merge('CUSTOM_PREVIEW_PATH' => '/custom/path'),
exec_script
)
).to eq('/custom/path')
end

it 'handles action mailer not being available' do
expect(
capture_exec(
custom_env.merge('NO_ACTION_MAILER' => 'true'),
exec_script
)
).to have_no_preview
end
end
else
it 'handles no action mailer preview' do
expect(capture_exec(exec_script)).to have_no_preview
end
end
end
Loading